Add /Api/{Bots}/Input endpoint

Makes https://github.com/JustArchiNET/ASF-ui/issues/888 (and similar actions) possible
This commit is contained in:
JustArchi 2020-06-03 19:26:59 +02:00
parent d9355ceab0
commit a5d85a211d
6 changed files with 140 additions and 43 deletions

View file

@ -877,7 +877,7 @@ namespace ArchiSteamFarm {
[PublicAPI]
public enum EUserInputType : byte {
Unknown,
None,
DeviceID,
Login,
Password,

View file

@ -94,6 +94,7 @@ namespace ArchiSteamFarm {
[PublicAPI]
public uint GamesToRedeemInBackgroundCount => BotDatabase?.GamesToRedeemInBackgroundCount ?? 0;
[JsonProperty]
[PublicAPI]
public bool HasMobileAuthenticator => BotDatabase?.MobileAuthenticator != null;
@ -153,23 +154,34 @@ namespace ArchiSteamFarm {
#pragma warning restore IDE0051
[JsonProperty]
[PublicAPI]
public EAccountFlags AccountFlags { get; private set; }
[JsonProperty]
[PublicAPI]
public BotConfig BotConfig { get; private set; }
[JsonProperty]
[PublicAPI]
public bool KeepRunning { get; private set; }
[JsonProperty]
[PublicAPI]
public string Nickname { get; private set; }
[JsonProperty]
[PublicAPI]
public ASF.EUserInputType RequiredInput { get; private set; }
[JsonProperty]
[PublicAPI]
public ulong SteamID { get; private set; }
[JsonProperty]
[PublicAPI]
public long WalletBalance { get; private set; }
[JsonProperty]
[PublicAPI]
public ECurrencyCode WalletCurrency { get; private set; }
@ -477,11 +489,11 @@ namespace ArchiSteamFarm {
}
[PublicAPI]
public void SetUserInput(ASF.EUserInputType inputType, string inputValue) {
if ((inputType == ASF.EUserInputType.Unknown) || !Enum.IsDefined(typeof(ASF.EUserInputType), inputType) || string.IsNullOrEmpty(inputValue)) {
public bool SetUserInput(ASF.EUserInputType inputType, string inputValue) {
if ((inputType == ASF.EUserInputType.None) || !Enum.IsDefined(typeof(ASF.EUserInputType), inputType) || string.IsNullOrEmpty(inputValue)) {
ArchiLogger.LogNullError(nameof(inputType) + " || " + nameof(inputValue));
return;
return false;
}
// This switch should cover ONLY bot properties
@ -491,26 +503,32 @@ namespace ArchiSteamFarm {
break;
case ASF.EUserInputType.Login:
if (BotConfig != null) {
BotConfig.SteamLogin = inputValue;
if (BotConfig == null) {
return false;
}
BotConfig.SteamLogin = inputValue;
break;
case ASF.EUserInputType.Password:
if (BotConfig != null) {
BotConfig.DecryptedSteamPassword = inputValue;
if (BotConfig == null) {
return false;
}
BotConfig.DecryptedSteamPassword = inputValue;
break;
case ASF.EUserInputType.SteamGuard:
AuthCode = inputValue;
break;
case ASF.EUserInputType.SteamParentalCode:
if (BotConfig != null) {
BotConfig.SteamParentalCode = inputValue;
if (BotConfig == null) {
return false;
}
BotConfig.SteamParentalCode = inputValue;
break;
case ASF.EUserInputType.TwoFactorAuthentication:
TwoFactorCode = inputValue;
@ -521,6 +539,12 @@ namespace ArchiSteamFarm {
break;
}
if (RequiredInput == inputType) {
RequiredInput = ASF.EUserInputType.None;
}
return true;
}
internal void AddGamesToRedeemInBackground(IOrderedDictionary gamesToRedeemInBackground) {
@ -1733,13 +1757,13 @@ namespace ArchiSteamFarm {
ArchiLogger.LogGenericWarning(Strings.BotAuthenticatorInvalidDeviceID);
if (string.IsNullOrEmpty(DeviceID)) {
RequiredInput = ASF.EUserInputType.DeviceID;
string deviceID = await Logging.GetUserInput(ASF.EUserInputType.DeviceID, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(deviceID)) {
if (string.IsNullOrEmpty(deviceID) || !SetUserInput(ASF.EUserInputType.DeviceID, deviceID)) {
return;
}
SetUserInput(ASF.EUserInputType.DeviceID, deviceID);
}
if (!MobileAuthenticator.IsValidDeviceID(DeviceID)) {
@ -1789,23 +1813,23 @@ namespace ArchiSteamFarm {
private async Task<bool> InitLoginAndPassword(bool requiresPassword) {
if (string.IsNullOrEmpty(BotConfig.SteamLogin)) {
RequiredInput = ASF.EUserInputType.Login;
string steamLogin = await Logging.GetUserInput(ASF.EUserInputType.Login, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(steamLogin)) {
if (string.IsNullOrEmpty(steamLogin) || !SetUserInput(ASF.EUserInputType.Login, steamLogin)) {
return false;
}
SetUserInput(ASF.EUserInputType.Login, steamLogin);
}
if (requiresPassword && string.IsNullOrEmpty(BotConfig.DecryptedSteamPassword)) {
RequiredInput = ASF.EUserInputType.Password;
string steamPassword = await Logging.GetUserInput(ASF.EUserInputType.Password, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(steamPassword)) {
if (string.IsNullOrEmpty(steamPassword) || !SetUserInput(ASF.EUserInputType.Password, steamPassword)) {
return false;
}
SetUserInput(ASF.EUserInputType.Password, steamPassword);
}
return true;
@ -1815,6 +1839,7 @@ namespace ArchiSteamFarm {
AccountFlags = EAccountFlags.NormalUser;
AvatarHash = Nickname = null;
MasterChatGroupID = 0;
RequiredInput = ASF.EUserInputType.None;
WalletBalance = 0;
WalletCurrency = ECurrencyCode.Invalid;
@ -2406,28 +2431,24 @@ namespace ArchiSteamFarm {
break;
case EResult.AccountLogonDenied:
RequiredInput = ASF.EUserInputType.SteamGuard;
string authCode = await Logging.GetUserInput(ASF.EUserInputType.SteamGuard, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(authCode)) {
if (string.IsNullOrEmpty(authCode) || !SetUserInput(ASF.EUserInputType.SteamGuard, authCode)) {
Stop();
break;
}
SetUserInput(ASF.EUserInputType.SteamGuard, authCode);
break;
case EResult.AccountLoginDeniedNeedTwoFactor:
if (!HasMobileAuthenticator) {
RequiredInput = ASF.EUserInputType.TwoFactorAuthentication;
string twoFactorCode = await Logging.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(twoFactorCode)) {
if (string.IsNullOrEmpty(twoFactorCode) || !SetUserInput(ASF.EUserInputType.TwoFactorAuthentication, twoFactorCode)) {
Stop();
break;
}
SetUserInput(ASF.EUserInputType.TwoFactorAuthentication, twoFactorCode);
}
break;
@ -2474,32 +2495,36 @@ namespace ArchiSteamFarm {
if (!string.IsNullOrEmpty(steamParentalCode)) {
if (BotConfig.SteamParentalCode != steamParentalCode) {
SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode);
if (!SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode)) {
Stop();
break;
}
}
} else if (string.IsNullOrEmpty(BotConfig.SteamParentalCode) || (BotConfig.SteamParentalCode.Length != BotConfig.SteamParentalCodeLength)) {
RequiredInput = ASF.EUserInputType.SteamParentalCode;
steamParentalCode = await Logging.GetUserInput(ASF.EUserInputType.SteamParentalCode, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(steamParentalCode) || (steamParentalCode.Length != BotConfig.SteamParentalCodeLength)) {
if (string.IsNullOrEmpty(steamParentalCode) || (steamParentalCode.Length != BotConfig.SteamParentalCodeLength) || !SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode)) {
Stop();
break;
}
SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode);
}
} else {
SteamParentalActive = false;
}
} else if (SteamParentalActive && !string.IsNullOrEmpty(BotConfig.SteamParentalCode) && (BotConfig.SteamParentalCode.Length != BotConfig.SteamParentalCodeLength)) {
RequiredInput = ASF.EUserInputType.SteamParentalCode;
string steamParentalCode = await Logging.GetUserInput(ASF.EUserInputType.SteamParentalCode, BotName).ConfigureAwait(false);
if (string.IsNullOrEmpty(steamParentalCode) || (steamParentalCode.Length != BotConfig.SteamParentalCodeLength)) {
if (string.IsNullOrEmpty(steamParentalCode) || (steamParentalCode.Length != BotConfig.SteamParentalCodeLength) || !SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode)) {
Stop();
break;
}
SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode);
}
ArchiWebHandler.OnVanityURLChanged(callback.VanityURL);

View file

@ -1416,7 +1416,7 @@ namespace ArchiSteamFarm {
return FormatBotResponse(Strings.ErrorFunctionOnlyInHeadlessMode);
}
if (!Enum.TryParse(propertyName, true, out ASF.EUserInputType inputType) || (inputType == ASF.EUserInputType.Unknown) || !Enum.IsDefined(typeof(ASF.EUserInputType), inputType)) {
if (!Enum.TryParse(propertyName, true, out ASF.EUserInputType inputType) || (inputType == ASF.EUserInputType.None) || !Enum.IsDefined(typeof(ASF.EUserInputType), inputType)) {
return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(inputType)));
}

View file

@ -242,6 +242,35 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
return Ok(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(result));
}
/// <summary>
/// Provides input value to given bot for next usage.
/// </summary>
[Consumes("application/json")]
[HttpPost("{botNames:required}/Input")]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
public async Task<ActionResult<GenericResponse>> InputPost(string botNames, [FromBody] BotInputRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
}
if ((request.Type == ASF.EUserInputType.None) || !Enum.IsDefined(typeof(ASF.EUserInputType), request.Type) || string.IsNullOrEmpty(request.Value)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(request.Type) + " || " + nameof(request.Value))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<bool> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.SetUserInput(request.Type, request.Value)))).ConfigureAwait(false);
return Ok(results.All(result => result) ? new GenericResponse(true) : new GenericResponse(false, Strings.WarningFailed));
}
/// <summary>
/// Pauses given bots.
/// </summary>

View file

@ -0,0 +1,43 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2020 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
namespace ArchiSteamFarm.IPC.Requests {
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
public sealed class BotInputRequest {
/// <summary>
/// Specifies the type of the input.
/// </summary>
[JsonProperty(Required = Required.Always)]
public readonly ASF.EUserInputType Type;
/// <summary>
/// Specifies the value for given input type (declared in <see cref="Type" />)
/// </summary>
[JsonProperty(Required = Required.Always)]
public readonly string Value;
[JsonConstructor]
private BotInputRequest() { }
}
}

View file

@ -65,7 +65,9 @@ namespace ArchiSteamFarm.NLog {
}
internal static async Task<string> GetUserInput(ASF.EUserInputType userInputType, string botName = SharedInfo.ASF) {
if (userInputType == ASF.EUserInputType.Unknown) {
if ((userInputType == ASF.EUserInputType.None) || !Enum.IsDefined(typeof(ASF.EUserInputType), userInputType) || string.IsNullOrEmpty(botName)) {
ASF.ArchiLogger.LogNullError(nameof(userInputType) + " || " + nameof(botName));
return null;
}
@ -118,10 +120,8 @@ namespace ArchiSteamFarm.NLog {
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(userInputType), userInputType));
Console.Write(Bot.FormatBotResponse(string.Format(Strings.UserInputUnknown, userInputType), botName));
result = ConsoleReadLine();
break;
return null;
}
if (!Console.IsOutputRedirected) {
@ -132,9 +132,9 @@ namespace ArchiSteamFarm.NLog {
ASF.ArchiLogger.LogGenericException(e);
return null;
} finally {
OnUserInputEnd();
}
OnUserInputEnd();
} finally {
ConsoleSemaphore.Release();
}