IPC controllers cleanup

This commit is contained in:
JustArchi
2019-04-11 22:47:21 +02:00
parent ac70af0268
commit 513b821b60
9 changed files with 119 additions and 89 deletions

View File

@@ -37,7 +37,7 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin {
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(GenericResponse<string>), (int) HttpStatusCode.OK)] [ProducesResponseType(typeof(GenericResponse<string>), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)]
public async Task<ActionResult<GenericResponse<string>>> CatGet() { public async Task<ActionResult<GenericResponse>> CatGet() {
string link = await CatAPI.GetRandomCatURL(ASF.WebBrowser).ConfigureAwait(false); string link = await CatAPI.GetRandomCatURL(ASF.WebBrowser).ConfigureAwait(false);
return !string.IsNullOrEmpty(link) ? Ok(new GenericResponse<string>(link)) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false)); return !string.IsNullOrEmpty(link) ? Ok(new GenericResponse<string>(link)) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false));

View File

@@ -22,6 +22,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using ArchiSteamFarm.IPC.Requests; using ArchiSteamFarm.IPC.Requests;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
@@ -36,7 +37,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Fetches common info related to ASF as a whole. /// Fetches common info related to ASF as a whole.
/// </summary> /// </summary>
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(GenericResponse<ASFResponse>), 200)] [ProducesResponseType(typeof(GenericResponse<ASFResponse>), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse<ASFResponse>> ASFGet() { public ActionResult<GenericResponse<ASFResponse>> ASFGet() {
uint memoryUsage = (uint) GC.GetTotalMemory(false) / 1024; uint memoryUsage = (uint) GC.GetTotalMemory(false) / 1024;
@@ -50,7 +51,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </summary> /// </summary>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost] [HttpPost]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> ASFPost([FromBody] ASFRequest request) { public async Task<ActionResult<GenericResponse>> ASFPost([FromBody] ASFRequest request) {
if (request == null) { if (request == null) {
ASF.ArchiLogger.LogNullError(nameof(request)); ASF.ArchiLogger.LogNullError(nameof(request));
@@ -100,7 +102,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Makes ASF shutdown itself. /// Makes ASF shutdown itself.
/// </summary> /// </summary>
[HttpPost("Exit")] [HttpPost("Exit")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse> ExitPost() { public ActionResult<GenericResponse> ExitPost() {
(bool success, string message) = Actions.Exit(); (bool success, string message) = Actions.Exit();
@@ -111,7 +113,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Makes ASF restart itself. /// Makes ASF restart itself.
/// </summary> /// </summary>
[HttpPost("Restart")] [HttpPost("Restart")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse> RestartPost() { public ActionResult<GenericResponse> RestartPost() {
(bool success, string message) = Actions.Restart(); (bool success, string message) = Actions.Restart();
@@ -122,7 +124,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Makes ASF update itself. /// Makes ASF update itself.
/// </summary> /// </summary>
[HttpPost("Update")] [HttpPost("Update")]
[ProducesResponseType(typeof(GenericResponse<Version>), 200)] [ProducesResponseType(typeof(GenericResponse<Version>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<Version>>> UpdatePost() { public async Task<ActionResult<GenericResponse<Version>>> UpdatePost() {
(bool success, string message, Version version) = await Actions.Update().ConfigureAwait(false); (bool success, string message, Version version) = await Actions.Update().ConfigureAwait(false);

View File

@@ -19,6 +19,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
using System.Net;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
@@ -26,8 +27,10 @@ using Swashbuckle.AspNetCore.Annotations;
namespace ArchiSteamFarm.IPC.Controllers.Api { namespace ArchiSteamFarm.IPC.Controllers.Api {
[ApiController] [ApiController]
[Produces("application/json")] [Produces("application/json")]
[SwaggerResponse(400, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))] [SwaggerResponse((int) HttpStatusCode.BadRequest, "The request has failed, check " + nameof(GenericResponse.Message) + " from response body for actual reason. Most of the time this is ASF, understanding the request, but refusing to execute it due to provided reason.", typeof(GenericResponse))]
[SwaggerResponse(401, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + SharedInfo.ProjectURL + "/wiki/IPC#authentication.")] [SwaggerResponse((int) HttpStatusCode.Unauthorized, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set, but you've failed to authenticate. See " + SharedInfo.ProjectURL + "/wiki/IPC#authentication.")]
[SwaggerResponse(403, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + SharedInfo.ProjectURL + "/wiki/IPC#authentication.")] [SwaggerResponse((int) HttpStatusCode.Forbidden, "ASF has " + nameof(GlobalConfig.IPCPassword) + " set and you've failed to authenticate too many times, try again in an hour. See " + SharedInfo.ProjectURL + "/wiki/IPC#authentication.")]
[SwaggerResponse((int) HttpStatusCode.InternalServerError, "ASF has encountered an unexpected error while serving the request. The log may include extra info related to this issue.")]
[SwaggerResponse((int) HttpStatusCode.ServiceUnavailable, "ASF has encountered an error while requesting a third-party resource. Try again later.")]
public abstract class ArchiController : ControllerBase { } public abstract class ArchiController : ControllerBase { }
} }

View File

@@ -23,6 +23,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using ArchiSteamFarm.IPC.Requests; using ArchiSteamFarm.IPC.Requests;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
@@ -37,7 +38,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Deletes all files related to given bots. /// Deletes all files related to given bots.
/// </summary> /// </summary>
[HttpDelete("{botNames:required}")] [HttpDelete("{botNames:required}")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> BotDelete(string botNames) { public async Task<ActionResult<GenericResponse>> BotDelete(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
@@ -60,18 +62,19 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Fetches common info related to given bots. /// Fetches common info related to given bots.
/// </summary> /// </summary>
[HttpGet("{botNames:required}")] [HttpGet("{botNames:required}")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, Bot>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, Bot>>), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse<IReadOnlyDictionary<string, Bot>>> BotGet(string botNames) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public ActionResult<GenericResponse> BotGet(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, Bot>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
} }
HashSet<Bot> bots = Bot.GetBots(botNames); HashSet<Bot> bots = Bot.GetBots(botNames);
if (bots == null) { if (bots == null) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, Bot>>(false, string.Format(Strings.ErrorIsInvalid, nameof(bots)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(bots))));
} }
return Ok(new GenericResponse<IReadOnlyDictionary<string, Bot>>(bots.ToDictionary(bot => bot.BotName, bot => bot, Bot.BotsComparer))); return Ok(new GenericResponse<IReadOnlyDictionary<string, Bot>>(bots.ToDictionary(bot => bot.BotName, bot => bot, Bot.BotsComparer)));
@@ -82,18 +85,19 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </summary> /// </summary>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost("{botNames:required}")] [HttpPost("{botNames:required}")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, bool>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, bool>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, bool>>>> BotPost(string botNames, [FromBody] BotRequest request) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> BotPost(string botNames, [FromBody] BotRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) { if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request)); ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, bool>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
} }
(bool valid, string errorMessage) = request.BotConfig.CheckValidation(); (bool valid, string errorMessage) = request.BotConfig.CheckValidation();
if (!valid) { if (!valid) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, bool>>(false, errorMessage)); return BadRequest(new GenericResponse(false, errorMessage));
} }
request.BotConfig.ShouldSerializeEverything = false; request.BotConfig.ShouldSerializeEverything = false;
@@ -135,7 +139,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
if (string.IsNullOrEmpty(filePath)) { if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(filePath); ASF.ArchiLogger.LogNullError(filePath);
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, bool>>(false, string.Format(Strings.ErrorIsInvalid, nameof(filePath)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(filePath))));
} }
result[botName] = await BotConfig.Write(filePath, request.BotConfig).ConfigureAwait(false); result[botName] = await BotConfig.Write(filePath, request.BotConfig).ConfigureAwait(false);
@@ -148,7 +152,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Removes BGR output files of given bots. /// Removes BGR output files of given bots.
/// </summary> /// </summary>
[HttpDelete("{botNames:required}/GamesToRedeemInBackground")] [HttpDelete("{botNames:required}/GamesToRedeemInBackground")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundDelete(string botNames) { public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundDelete(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
@@ -171,18 +176,19 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Fetches BGR output files of given bots. /// Fetches BGR output files of given bots.
/// </summary> /// </summary>
[HttpGet("{botNames:required}/GamesToRedeemInBackground")] [HttpGet("{botNames:required}/GamesToRedeemInBackground")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>>> GamesToRedeemInBackgroundGet(string botNames) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundGet(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
} }
HashSet<Bot> bots = Bot.GetBots(botNames); HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) { if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>(false, string.Format(Strings.BotNotFound, botNames))); return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
} }
IList<(Dictionary<string, string> UnusedKeys, Dictionary<string, string> UsedKeys)> results = await Utilities.InParallel(bots.Select(bot => bot.GetUsedAndUnusedKeys())).ConfigureAwait(false); IList<(Dictionary<string, string> UnusedKeys, Dictionary<string, string> UsedKeys)> results = await Utilities.InParallel(bots.Select(bot => bot.GetUsedAndUnusedKeys())).ConfigureAwait(false);
@@ -202,28 +208,29 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </summary> /// </summary>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost("{botNames:required}/GamesToRedeemInBackground")] [HttpPost("{botNames:required}/GamesToRedeemInBackground")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>>> GamesToRedeemInBackgroundPost(string botNames, [FromBody] BotGamesToRedeemInBackgroundRequest request) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundPost(string botNames, [FromBody] BotGamesToRedeemInBackgroundRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) { if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request)); ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
} }
if (request.GamesToRedeemInBackground.Count == 0) { if (request.GamesToRedeemInBackground.Count == 0) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.ErrorIsEmpty, nameof(request.GamesToRedeemInBackground)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(request.GamesToRedeemInBackground))));
} }
HashSet<Bot> bots = Bot.GetBots(botNames); HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) { if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.BotNotFound, botNames))); return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
} }
IOrderedDictionary validGamesToRedeemInBackground = Bot.ValidateGamesToRedeemInBackground(request.GamesToRedeemInBackground); IOrderedDictionary validGamesToRedeemInBackground = Bot.ValidateGamesToRedeemInBackground(request.GamesToRedeemInBackground);
if ((validGamesToRedeemInBackground == null) || (validGamesToRedeemInBackground.Count == 0)) { if ((validGamesToRedeemInBackground == null) || (validGamesToRedeemInBackground.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.ErrorIsEmpty, nameof(validGamesToRedeemInBackground)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(validGamesToRedeemInBackground))));
} }
await Utilities.InParallel(bots.Select(bot => bot.AddGamesToRedeemInBackground(validGamesToRedeemInBackground))).ConfigureAwait(false); await Utilities.InParallel(bots.Select(bot => bot.AddGamesToRedeemInBackground(validGamesToRedeemInBackground))).ConfigureAwait(false);
@@ -242,7 +249,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </summary> /// </summary>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost("{botNames:required}/Pause")] [HttpPost("{botNames:required}/Pause")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> PausePost(string botNames, [FromBody] BotPauseRequest request) { public async Task<ActionResult<GenericResponse>> PausePost(string botNames, [FromBody] BotPauseRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) { if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request)); ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
@@ -270,22 +278,23 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </remarks> /// </remarks>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost("{botNames:required}/Redeem")] [HttpPost("{botNames:required}/Redeem")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>>> RedeemPost(string botNames, [FromBody] BotRedeemRequest request) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> RedeemPost(string botNames, [FromBody] BotRedeemRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) { if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request)); ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
} }
if (request.KeysToRedeem.Count == 0) { if (request.KeysToRedeem.Count == 0) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>(false, string.Format(Strings.ErrorIsEmpty, nameof(request.KeysToRedeem)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(request.KeysToRedeem))));
} }
HashSet<Bot> bots = Bot.GetBots(botNames); HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) { if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>(false, string.Format(Strings.BotNotFound, botNames))); return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
} }
IList<ArchiHandler.PurchaseResponseCallback> results = await Utilities.InParallel(bots.Select(bot => request.KeysToRedeem.Select(key => bot.Actions.RedeemKey(key))).SelectMany(task => task)).ConfigureAwait(false); IList<ArchiHandler.PurchaseResponseCallback> results = await Utilities.InParallel(bots.Select(bot => request.KeysToRedeem.Select(key => bot.Actions.RedeemKey(key))).SelectMany(task => task)).ConfigureAwait(false);
@@ -311,7 +320,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </summary> /// </summary>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost("{botName:required}/Rename")] [HttpPost("{botName:required}/Rename")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> RenamePost(string botName, [FromBody] BotRenameRequest request) { public async Task<ActionResult<GenericResponse>> RenamePost(string botName, [FromBody] BotRenameRequest request) {
if (string.IsNullOrEmpty(botName) || (request == null)) { if (string.IsNullOrEmpty(botName) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botName) + " || " + nameof(request)); ASF.ArchiLogger.LogNullError(nameof(botName) + " || " + nameof(request));
@@ -336,7 +346,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Resumes given bots. /// Resumes given bots.
/// </summary> /// </summary>
[HttpPost("{botNames:required}/Resume")] [HttpPost("{botNames:required}/Resume")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> ResumePost(string botNames) { public async Task<ActionResult<GenericResponse>> ResumePost(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
@@ -359,7 +370,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Starts given bots. /// Starts given bots.
/// </summary> /// </summary>
[HttpPost("{botNames:required}/Start")] [HttpPost("{botNames:required}/Start")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> StartPost(string botNames) { public async Task<ActionResult<GenericResponse>> StartPost(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
@@ -382,7 +394,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Stops given bots. /// Stops given bots.
/// </summary> /// </summary>
[HttpPost("{botNames:required}/Stop")] [HttpPost("{botNames:required}/Stop")]
[ProducesResponseType(typeof(GenericResponse), 200)] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> StopPost(string botNames) { public async Task<ActionResult<GenericResponse>> StopPost(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
@@ -405,22 +418,25 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Accepts 2FA confirmations of given bots, requires ASF 2FA module to be active on them. /// Accepts 2FA confirmations of given bots, requires ASF 2FA module to be active on them.
/// </summary> /// </summary>
[HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Accept")] [HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Accept")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, GenericResponse>>>> TwoFactorAuthenticationConfirmationsAcceptPost(string botNames) => await TwoFactorAuthenticationConfirmationsPost(botNames, true).ConfigureAwait(false); [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsAcceptPost(string botNames) => await TwoFactorAuthenticationConfirmationsPost(botNames, true).ConfigureAwait(false);
/// <summary> /// <summary>
/// Denies 2FA confirmations of given bots, requires ASF 2FA module to be active on them. /// Denies 2FA confirmations of given bots, requires ASF 2FA module to be active on them.
/// </summary> /// </summary>
[HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Cancel")] [HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Cancel")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, GenericResponse>>>> TwoFactorAuthenticationConfirmationsCancelPost(string botNames) => await TwoFactorAuthenticationConfirmationsPost(botNames, false).ConfigureAwait(false); [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsCancelPost(string botNames) => await TwoFactorAuthenticationConfirmationsPost(botNames, false).ConfigureAwait(false);
/// <summary> /// <summary>
/// Fetches 2FA tokens of given bots, requires ASF 2FA module to be active on them. /// Fetches 2FA tokens of given bots, requires ASF 2FA module to be active on them.
/// </summary> /// </summary>
[HttpGet("{botNames:required}/TwoFactorAuthentication/Token")] [HttpGet("{botNames:required}/TwoFactorAuthentication/Token")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse<string>>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyDictionary<string, GenericResponse<string>>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, GenericResponse<string>>>>> TwoFactorAuthenticationTokenGet(string botNames) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationTokenGet(string botNames) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));
@@ -445,7 +461,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
return Ok(new GenericResponse<IReadOnlyDictionary<string, GenericResponse<string>>>(result)); return Ok(new GenericResponse<IReadOnlyDictionary<string, GenericResponse<string>>>(result));
} }
private async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, GenericResponse>>>> TwoFactorAuthenticationConfirmationsPost(string botNames, bool accept) { private async Task<ActionResult<GenericResponse>> TwoFactorAuthenticationConfirmationsPost(string botNames, bool accept) {
if (string.IsNullOrEmpty(botNames)) { if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames)); ASF.ArchiLogger.LogNullError(nameof(botNames));

View File

@@ -21,6 +21,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
using ArchiSteamFarm.Localization; using ArchiSteamFarm.Localization;
@@ -37,29 +38,30 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// You should use "given bot" commands when executing this endpoint, omitting targets of the command will cause the command to be executed on first defined bot /// You should use "given bot" commands when executing this endpoint, omitting targets of the command will cause the command to be executed on first defined bot
/// </remarks> /// </remarks>
[HttpPost("{command:required}")] [HttpPost("{command:required}")]
[ProducesResponseType(typeof(GenericResponse<string>), 200)] [ProducesResponseType(typeof(GenericResponse<string>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<string>>> CommandPost(string command) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> CommandPost(string command) {
if (string.IsNullOrEmpty(command)) { if (string.IsNullOrEmpty(command)) {
ASF.ArchiLogger.LogNullError(nameof(command)); ASF.ArchiLogger.LogNullError(nameof(command));
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsEmpty, nameof(command)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(command))));
} }
if (ASF.GlobalConfig.SteamOwnerID == 0) { if (ASF.GlobalConfig.SteamOwnerID == 0) {
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsInvalid, nameof(ASF.GlobalConfig.SteamOwnerID)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(ASF.GlobalConfig.SteamOwnerID))));
} }
Bot targetBot = Bot.Bots.OrderBy(bot => bot.Key, Bot.BotsComparer).Select(bot => bot.Value).FirstOrDefault(); Bot targetBot = Bot.Bots.OrderBy(bot => bot.Key, Bot.BotsComparer).Select(bot => bot.Value).FirstOrDefault();
if (targetBot == null) { if (targetBot == null) {
return BadRequest(new GenericResponse<string>(false, Strings.ErrorNoBotsDefined)); return BadRequest(new GenericResponse(false, Strings.ErrorNoBotsDefined));
} }
if (!string.IsNullOrEmpty(ASF.GlobalConfig.CommandPrefix) && command.StartsWith(ASF.GlobalConfig.CommandPrefix, StringComparison.Ordinal)) { if (!string.IsNullOrEmpty(ASF.GlobalConfig.CommandPrefix) && command.StartsWith(ASF.GlobalConfig.CommandPrefix, StringComparison.Ordinal)) {
command = command.Substring(ASF.GlobalConfig.CommandPrefix.Length); command = command.Substring(ASF.GlobalConfig.CommandPrefix.Length);
if (string.IsNullOrEmpty(command)) { if (string.IsNullOrEmpty(command)) {
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsEmpty, nameof(command)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(command))));
} }
} }

View File

@@ -22,6 +22,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@@ -44,7 +45,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// This API endpoint requires a websocket connection. /// This API endpoint requires a websocket connection.
/// </remarks> /// </remarks>
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(IEnumerable<GenericResponse<string>>), 200)] [ProducesResponseType(typeof(IEnumerable<GenericResponse<string>>), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult> NLogGet() { public async Task<ActionResult> NLogGet() {
if (!HttpContext.WebSockets.IsWebSocketRequest) { if (!HttpContext.WebSockets.IsWebSocketRequest) {
return BadRequest(new GenericResponse(false, string.Format(Strings.WarningFailedWithError, nameof(HttpContext.WebSockets.IsWebSocketRequest) + ": " + HttpContext.WebSockets.IsWebSocketRequest))); return BadRequest(new GenericResponse(false, string.Format(Strings.WarningFailedWithError, nameof(HttpContext.WebSockets.IsWebSocketRequest) + ": " + HttpContext.WebSockets.IsWebSocketRequest)));

View File

@@ -20,6 +20,7 @@
// limitations under the License. // limitations under the License.
using System; using System;
using System.Net;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
using ArchiSteamFarm.Localization; using ArchiSteamFarm.Localization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -34,18 +35,19 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Structure is defined as a representation of given object in its default state. /// Structure is defined as a representation of given object in its default state.
/// </remarks> /// </remarks>
[HttpGet("{structure:required}")] [HttpGet("{structure:required}")]
[ProducesResponseType(typeof(GenericResponse<object>), 200)] [ProducesResponseType(typeof(GenericResponse<object>), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse<object>> StructureGet(string structure) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public ActionResult<GenericResponse> StructureGet(string structure) {
if (string.IsNullOrEmpty(structure)) { if (string.IsNullOrEmpty(structure)) {
ASF.ArchiLogger.LogNullError(nameof(structure)); ASF.ArchiLogger.LogNullError(nameof(structure));
return BadRequest(new GenericResponse<object>(false, string.Format(Strings.ErrorIsEmpty, nameof(structure)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(structure))));
} }
Type targetType = WebUtilities.ParseType(structure); Type targetType = WebUtilities.ParseType(structure);
if (targetType == null) { if (targetType == null) {
return BadRequest(new GenericResponse<object>(false, string.Format(Strings.ErrorIsInvalid, structure))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, structure)));
} }
object obj; object obj;
@@ -53,7 +55,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
try { try {
obj = Activator.CreateInstance(targetType, true); obj = Activator.CreateInstance(targetType, true);
} catch (Exception e) { } catch (Exception e) {
return BadRequest(new GenericResponse<object>(false, string.Format(Strings.ErrorParsingObject, nameof(targetType)) + Environment.NewLine + e)); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorParsingObject, nameof(targetType)) + Environment.NewLine + e));
} }
return Ok(new GenericResponse<object>(obj)); return Ok(new GenericResponse<object>(obj));

View File

@@ -22,6 +22,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Reflection; using System.Reflection;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
using ArchiSteamFarm.Localization; using ArchiSteamFarm.Localization;
@@ -38,18 +39,19 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// Type info is defined as a representation of given object with its fields and properties being assigned to a string value that defines their type. /// Type info is defined as a representation of given object with its fields and properties being assigned to a string value that defines their type.
/// </remarks> /// </remarks>
[HttpGet("{type:required}")] [HttpGet("{type:required}")]
[ProducesResponseType(typeof(GenericResponse<TypeResponse>), 200)] [ProducesResponseType(typeof(GenericResponse<TypeResponse>), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse<TypeResponse>> TypeGet(string type) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public ActionResult<GenericResponse> TypeGet(string type) {
if (string.IsNullOrEmpty(type)) { if (string.IsNullOrEmpty(type)) {
ASF.ArchiLogger.LogNullError(nameof(type)); ASF.ArchiLogger.LogNullError(nameof(type));
return BadRequest(new GenericResponse<TypeResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(type)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(type))));
} }
Type targetType = WebUtilities.ParseType(type); Type targetType = WebUtilities.ParseType(type);
if (targetType == null) { if (targetType == null) {
return BadRequest(new GenericResponse<object>(false, string.Format(Strings.ErrorIsInvalid, type))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, type)));
} }
string baseType = targetType.BaseType?.GetUnifiedName(); string baseType = targetType.BaseType?.GetUnifiedName();

View File

@@ -24,6 +24,7 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using ArchiSteamFarm.IPC.Requests; using ArchiSteamFarm.IPC.Requests;
using ArchiSteamFarm.IPC.Responses; using ArchiSteamFarm.IPC.Responses;
@@ -40,18 +41,20 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW endpoints as they can disappear and change anytime. /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW endpoints as they can disappear and change anytime.
/// </remarks> /// </remarks>
[HttpGet("Directory/{directory:required}")] [HttpGet("Directory/{directory:required}")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyCollection<string>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyCollection<string>>), (int) HttpStatusCode.OK)]
public ActionResult<GenericResponse<IReadOnlyCollection<string>>> DirectoryGet(string directory) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.InternalServerError)]
public ActionResult<GenericResponse> DirectoryGet(string directory) {
if (string.IsNullOrEmpty(directory)) { if (string.IsNullOrEmpty(directory)) {
ASF.ArchiLogger.LogNullError(nameof(directory)); ASF.ArchiLogger.LogNullError(nameof(directory));
return BadRequest(new GenericResponse<IReadOnlyCollection<string>>(false, string.Format(Strings.ErrorIsEmpty, nameof(directory)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(directory))));
} }
string directoryPath = Path.Combine(ArchiKestrel.WebsiteDirectory, directory); string directoryPath = Path.Combine(ArchiKestrel.WebsiteDirectory, directory);
if (!Directory.Exists(directoryPath)) { if (!Directory.Exists(directoryPath)) {
return BadRequest(new GenericResponse<IReadOnlyCollection<string>>(false, string.Format(Strings.ErrorIsInvalid, directory))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, directory)));
} }
string[] files; string[] files;
@@ -59,7 +62,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
try { try {
files = Directory.GetFiles(directoryPath); files = Directory.GetFiles(directoryPath);
} catch (Exception e) { } catch (Exception e) {
return BadRequest(new GenericResponse<IReadOnlyCollection<string>>(false, string.Format(Strings.ErrorParsingObject, nameof(files)) + Environment.NewLine + e)); return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(Strings.ErrorParsingObject, nameof(files)) + Environment.NewLine + e));
} }
HashSet<string> result = files.Select(Path.GetFileName).ToHashSet(); HashSet<string> result = files.Select(Path.GetFileName).ToHashSet();
@@ -74,16 +77,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW endpoints as they can disappear and change anytime. /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW endpoints as they can disappear and change anytime.
/// </remarks> /// </remarks>
[HttpGet("GitHub/Releases")] [HttpGet("GitHub/Releases")]
[ProducesResponseType(typeof(GenericResponse<IReadOnlyCollection<GitHubReleaseResponse>>), 200)] [ProducesResponseType(typeof(GenericResponse<IReadOnlyCollection<GitHubReleaseResponse>>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<IReadOnlyCollection<GitHubReleaseResponse>>>> GitHubReleasesGet([FromQuery] byte count = 10) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)]
public async Task<ActionResult<GenericResponse>> GitHubReleasesGet([FromQuery] byte count = 10) {
if (count == 0) { if (count == 0) {
return BadRequest(new GenericResponse<IReadOnlyCollection<GitHubReleaseResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(count)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(count))));
} }
ImmutableList<GitHub.ReleaseResponse> response = await GitHub.GetReleases(count).ConfigureAwait(false); ImmutableList<GitHub.ReleaseResponse> response = await GitHub.GetReleases(count).ConfigureAwait(false);
if ((response == null) || (response.Count == 0)) { if ((response == null) || (response.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyCollection<GitHub.ReleaseResponse>>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries))); return StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
} }
List<GitHubReleaseResponse> result = response.Select(singleResponse => new GitHubReleaseResponse(singleResponse)).ToList(); List<GitHubReleaseResponse> result = response.Select(singleResponse => new GitHubReleaseResponse(singleResponse)).ToList();
@@ -98,19 +103,17 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW endpoints as they can disappear and change anytime. /// This is internal API being utilizied by our ASF-ui IPC frontend. You should not depend on existence of any /Api/WWW endpoints as they can disappear and change anytime.
/// </remarks> /// </remarks>
[HttpGet("GitHub/Releases/{version:required}")] [HttpGet("GitHub/Releases/{version:required}")]
[ProducesResponseType(typeof(GenericResponse<GitHubReleaseResponse>), 200)] [ProducesResponseType(typeof(GenericResponse<GitHubReleaseResponse>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<GitHubReleaseResponse>>> GitHubReleasesGet(string version) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)]
public async Task<ActionResult<GenericResponse>> GitHubReleasesGet(string version) {
if (string.IsNullOrEmpty(version)) { if (string.IsNullOrEmpty(version)) {
return BadRequest(new GenericResponse<GitHubReleaseResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(version)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(version))));
} }
GitHub.ReleaseResponse releaseResponse = await GitHub.GetRelease(version).ConfigureAwait(false); GitHub.ReleaseResponse releaseResponse = await GitHub.GetRelease(version).ConfigureAwait(false);
if (releaseResponse == null) { return releaseResponse != null ? Ok(new GenericResponse<GitHubReleaseResponse>(new GitHubReleaseResponse(releaseResponse))) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
return BadRequest(new GenericResponse<GitHubReleaseResponse>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}
return Ok(new GenericResponse<GitHubReleaseResponse>(new GitHubReleaseResponse(releaseResponse)));
} }
/// <summary> /// <summary>
@@ -121,25 +124,23 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
/// </remarks> /// </remarks>
[Consumes("application/json")] [Consumes("application/json")]
[HttpPost("Send")] [HttpPost("Send")]
[ProducesResponseType(typeof(GenericResponse<string>), 200)] [ProducesResponseType(typeof(GenericResponse<string>), (int) HttpStatusCode.OK)]
public async Task<ActionResult<GenericResponse<string>>> SendPost([FromBody] WWWSendRequest request) { [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)]
public async Task<ActionResult<GenericResponse>> SendPost([FromBody] WWWSendRequest request) {
if (request == null) { if (request == null) {
ASF.ArchiLogger.LogNullError(nameof(request)); ASF.ArchiLogger.LogNullError(nameof(request));
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsEmpty, nameof(request)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(request))));
} }
if (string.IsNullOrEmpty(request.URL) || !Uri.TryCreate(request.URL, UriKind.Absolute, out Uri uri) || !uri.Scheme.Equals(Uri.UriSchemeHttps)) { if (string.IsNullOrEmpty(request.URL) || !Uri.TryCreate(request.URL, UriKind.Absolute, out Uri uri) || !uri.Scheme.Equals(Uri.UriSchemeHttps)) {
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsInvalid, nameof(request.URL)))); return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(request.URL))));
} }
WebBrowser.StringResponse urlResponse = await ASF.WebBrowser.UrlGetToString(request.URL).ConfigureAwait(false); WebBrowser.StringResponse urlResponse = await ASF.WebBrowser.UrlGetToString(request.URL).ConfigureAwait(false);
if (urlResponse?.Content == null) { return urlResponse?.Content != null ? Ok(new GenericResponse<string>(urlResponse.Content)) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}
return Ok(new GenericResponse<string>(urlResponse.Content));
} }
} }
} }