From de897aaa923fcb463644a626d2d03f630ef0ec16 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Wed, 11 Jan 2017 15:22:00 +0100 Subject: [PATCH] Rewrite #414 in a way that makes me happy --- ArchiSteamFarm/ArchiWebHandler.cs | 406 ++++++++++++++++------------- ArchiSteamFarm/Bot.cs | 7 +- ArchiSteamFarm/Statistics.cs | 5 +- ArchiSteamFarm/Trading.cs | 8 +- ArchiSteamFarm/Utilities.cs | 20 ++ ArchiSteamFarm/config/example.json | 1 - ConfigGenerator/BotConfig.cs | 4 - 7 files changed, 252 insertions(+), 199 deletions(-) diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index e268bf2ca..83673da22 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -64,19 +64,9 @@ namespace ArchiSteamFarm { internal bool Ready { get; private set; } private DateTime LastSessionRefreshCheck = DateTime.MinValue; + private string SteamApiKey; private ulong SteamID; - private string _SteamApiKey; - internal string SteamApiKey => ObtainApiKey().Result; - private enum ESteamApiKeyState : byte { - Unknown = 0, - Invalid = 1, - Registered = 2, - NotRegistered = 3, - AccessDenied = 4, - } - private ESteamApiKeyState SteamApiKeyState; - internal ArchiWebHandler(Bot bot) { if (bot == null) { throw new ArgumentNullException(nameof(bot)); @@ -95,7 +85,7 @@ namespace ArchiSteamFarm { return false; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -123,7 +113,7 @@ namespace ArchiSteamFarm { return false; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -151,7 +141,7 @@ namespace ArchiSteamFarm { return false; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -171,15 +161,20 @@ namespace ArchiSteamFarm { } */ - internal void DeclineTradeOffer(ulong tradeID) { - if ((tradeID == 0) || string.IsNullOrEmpty(SteamApiKey)) { - Bot.ArchiLogger.LogNullError(nameof(tradeID) + " || " + nameof(SteamApiKey)); + internal async Task DeclineTradeOffer(ulong tradeID) { + if (tradeID == 0) { + Bot.ArchiLogger.LogNullError(nameof(tradeID)); + return; + } + + string steamApiKey = await GetApiKey().ConfigureAwait(false); + if (string.IsNullOrEmpty(SteamApiKey)) { return; } KeyValue response = null; for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { - using (dynamic iEconService = WebAPI.GetInterface(IEconService, SteamApiKey)) { + using (dynamic iEconService = WebAPI.GetInterface(IEconService, steamApiKey)) { iEconService.Timeout = Timeout; try { @@ -201,7 +196,7 @@ namespace ArchiSteamFarm { /* internal async Task> GenerateNewDiscoveryQueue() { - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -222,15 +217,15 @@ namespace ArchiSteamFarm { } */ - internal HashSet GetActiveTradeOffers() { + internal async Task> GetActiveTradeOffers() { + string steamApiKey = await GetApiKey().ConfigureAwait(false); if (string.IsNullOrEmpty(SteamApiKey)) { - Bot.ArchiLogger.LogNullError(nameof(SteamApiKey)); return null; } KeyValue response = null; for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { - using (dynamic iEconService = WebAPI.GetInterface(IEconService, SteamApiKey)) { + using (dynamic iEconService = WebAPI.GetInterface(IEconService, steamApiKey)) { iEconService.Timeout = Timeout; try { @@ -332,114 +327,13 @@ namespace ArchiSteamFarm { return result; } - private async Task UpdateApiKey() { - if ( !await RefreshSessionIfNeeded().ConfigureAwait(false) ) { - return ESteamApiKeyState.Invalid; - } - - string request = SteamCommunityURL + "/dev/apikey?l=english"; - - HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false); - - HtmlNode titleNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='mainContents']/h2"); - - if (titleNode == null) { - return ESteamApiKeyState.Invalid; - } - - string title = titleNode.InnerText; - - if (title.IndexOf("Access Denied") == 0) { - return ESteamApiKeyState.AccessDenied; - } - - HtmlNode htmlNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='bodyContents_ex']/p"); - if (htmlNode == null) { - return ESteamApiKeyState.Invalid; - } - - string text = htmlNode.InnerText; - - if (string.IsNullOrEmpty(text)) { - Bot.ArchiLogger.LogNullError(nameof(text)); - return ESteamApiKeyState.Invalid; - } - - int hintIndex = text.IndexOf("Registering for a Steam Web API Key", StringComparison.Ordinal); - if (hintIndex == 0) { - return ESteamApiKeyState.NotRegistered; - } - - int keyIndex = text.IndexOf("Key: ", StringComparison.Ordinal); - if ( keyIndex < 0 ) { - Bot.ArchiLogger.LogNullError(nameof(keyIndex)); - return ESteamApiKeyState.Invalid; - } - - keyIndex += 5; - text = text.Substring(keyIndex); - - if ( text.Length != 32 ) { - Bot.ArchiLogger.LogNullError(nameof(text)); - return ESteamApiKeyState.Invalid; - } - - string allowedChars = "0123456789ABCDEF"; - foreach (char c in text) { - if (!allowedChars.Contains(c.ToString()) ) { - Bot.ArchiLogger.LogNullError(nameof(text)); - return ESteamApiKeyState.Invalid; - } - } - - this._SteamApiKey = text; - - return ESteamApiKeyState.Registered; - } - - private async Task RegisterApiKey() { - string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); - if ( string.IsNullOrEmpty(sessionID) ) { - Bot.ArchiLogger.LogNullError(nameof(sessionID)); - return false; - } - - string request = SteamCommunityURL + "/dev/registerkey"; - Dictionary data = new Dictionary(4) { - {"domain", "localhost" }, - {"agreeToTerms", "agreed"}, - {"sessionid", sessionID}, - {"Submit", "Register"} - }; - - return await WebBrowser.UrlPostRetry( request, data).ConfigureAwait(false); - } - - private async Task ObtainApiKey() { - switch (SteamApiKeyState) { - case ESteamApiKeyState.Unknown: - SteamApiKeyState = await UpdateApiKey().ConfigureAwait(false); - return await ObtainApiKey().ConfigureAwait(false); - case ESteamApiKeyState.NotRegistered: - await RegisterApiKey().ConfigureAwait(false); - SteamApiKeyState = ESteamApiKeyState.Unknown; - return await ObtainApiKey().ConfigureAwait(false); - case ESteamApiKeyState.Registered: - return _SteamApiKey; - case ESteamApiKeyState.AccessDenied: - return string.Empty; - default: - return null; - } - } - internal async Task GetBadgePage(byte page) { if (page == 0) { Bot.ArchiLogger.LogNullError(nameof(page)); return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -453,7 +347,7 @@ namespace ArchiSteamFarm { return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -474,7 +368,7 @@ namespace ArchiSteamFarm { return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -484,7 +378,7 @@ namespace ArchiSteamFarm { /* internal async Task GetDiscoveryQueuePage() { - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -494,7 +388,7 @@ namespace ArchiSteamFarm { */ internal async Task> GetFamilySharingSteamIDs() { - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -533,7 +427,7 @@ namespace ArchiSteamFarm { return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -541,13 +435,53 @@ namespace ArchiSteamFarm { return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false); } + internal async Task> GetMyOwnedGames() { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { + return null; + } + + const string request = SteamCommunityURL + "/my/games/?xml=1"; + + XmlDocument response = await WebBrowser.UrlGetToXMLRetry(request).ConfigureAwait(false); + + XmlNodeList xmlNodeList = response?.SelectNodes("gamesList/games/game"); + if ((xmlNodeList == null) || (xmlNodeList.Count == 0)) { + return null; + } + + Dictionary result = new Dictionary(xmlNodeList.Count); + foreach (XmlNode xmlNode in xmlNodeList) { + XmlNode appNode = xmlNode.SelectSingleNode("appID"); + if (appNode == null) { + Bot.ArchiLogger.LogNullError(nameof(appNode)); + return null; + } + + uint appID; + if (!uint.TryParse(appNode.InnerText, out appID)) { + Bot.ArchiLogger.LogNullError(nameof(appID)); + return null; + } + + XmlNode nameNode = xmlNode.SelectSingleNode("name"); + if (nameNode == null) { + Bot.ArchiLogger.LogNullError(nameof(nameNode)); + return null; + } + + result[appID] = nameNode.InnerText; + } + + return result; + } + internal async Task> GetMySteamInventory(bool tradable, HashSet wantedTypes) { if ((wantedTypes == null) || (wantedTypes.Count == 0)) { Bot.ArchiLogger.LogNullError(nameof(wantedTypes)); return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -666,55 +600,20 @@ namespace ArchiSteamFarm { return result; } - internal async Task> GetOwnedGames() { - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + internal async Task> GetOwnedGames(ulong steamID) { + if (steamID == 0) { + Bot.ArchiLogger.LogNullError(nameof(steamID)); return null; } - const string request = SteamCommunityURL + "/my/games/?xml=1"; - - XmlDocument response = await WebBrowser.UrlGetToXMLRetry(request).ConfigureAwait(false); - - XmlNodeList xmlNodeList = response?.SelectNodes("gamesList/games/game"); - if ((xmlNodeList == null) || (xmlNodeList.Count == 0)) { - return null; - } - - Dictionary result = new Dictionary(xmlNodeList.Count); - foreach (XmlNode xmlNode in xmlNodeList) { - XmlNode appNode = xmlNode.SelectSingleNode("appID"); - if (appNode == null) { - Bot.ArchiLogger.LogNullError(nameof(appNode)); - return null; - } - - uint appID; - if (!uint.TryParse(appNode.InnerText, out appID)) { - Bot.ArchiLogger.LogNullError(nameof(appID)); - return null; - } - - XmlNode nameNode = xmlNode.SelectSingleNode("name"); - if (nameNode == null) { - Bot.ArchiLogger.LogNullError(nameof(nameNode)); - return null; - } - - result[appID] = nameNode.InnerText; - } - - return result; - } - - internal Dictionary GetOwnedGames(ulong steamID) { - if ((steamID == 0) || string.IsNullOrEmpty(SteamApiKey)) { - Bot.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(SteamApiKey)); + string steamApiKey = await GetApiKey().ConfigureAwait(false); + if (string.IsNullOrEmpty(SteamApiKey)) { return null; } KeyValue response = null; for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { - using (dynamic iPlayerService = WebAPI.GetInterface(IPlayerService, SteamApiKey)) { + using (dynamic iPlayerService = WebAPI.GetInterface(IPlayerService, steamApiKey)) { iPlayerService.Timeout = Timeout; try { @@ -775,7 +674,7 @@ namespace ArchiSteamFarm { /* internal async Task GetSteamAwardsPage() { - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -790,7 +689,7 @@ namespace ArchiSteamFarm { return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -841,7 +740,7 @@ namespace ArchiSteamFarm { return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -857,7 +756,7 @@ namespace ArchiSteamFarm { return null; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -881,6 +780,8 @@ namespace ArchiSteamFarm { return response?.Success; } + internal async Task HasValidApiKey() => !string.IsNullOrEmpty(await GetApiKey().ConfigureAwait(false)); + internal static void Init() => Timeout = Program.GlobalConfig.HttpTimeout * 1000; internal async Task Init(ulong steamID, EUniverse universe, string webAPIUserNonce, string parentalPin) { @@ -976,7 +877,7 @@ namespace ArchiSteamFarm { return false; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -996,7 +897,7 @@ namespace ArchiSteamFarm { } internal async Task MarkInventory() { - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -1012,7 +913,7 @@ namespace ArchiSteamFarm { return ArchiHandler.PurchaseResponseCallback.EPurchaseResult.Unknown; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return ArchiHandler.PurchaseResponseCallback.EPurchaseResult.Timeout; } @@ -1031,7 +932,7 @@ namespace ArchiSteamFarm { return false; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -1078,6 +979,122 @@ namespace ArchiSteamFarm { return true; } + private async Task GetApiKey(bool allowRegister = true) { + switch (SteamApiKey) { + case null: + // We didn't fetch API key yet + Tuple result = await GetApiKeyState().ConfigureAwait(false); + if (result == null) { + // Request timed out, bad luck, we'll try again later + return null; + } + + switch (result.Item1) { + case ESteamApiKeyState.Registered: + // We succeeded in fetching API key, and it resulted in registered key + // Cache the result and return it + SteamApiKey = result.Item2; + return SteamApiKey; + case ESteamApiKeyState.NotRegisteredYet: + // We succeeded in fetching API key, and it resulted in no key registered yet + if (!allowRegister) { + // But this call doesn't allow us to register it, so return null + return null; + } + + // If we're allowed to register the key, let's do so + if (!await RegisterApiKey().ConfigureAwait(false)) { + // Request timed out, bad luck, we'll try again later + return null; + } + + // We should have key ready, to let's call GetApiKey() recursively, but don't allow further recursion + return await GetApiKey(false).ConfigureAwait(false); + case ESteamApiKeyState.AccessDenied: + // We succeeded in fetching API key, but it resulted in access denied + // Cache the result as empty, and return null + SteamApiKey = ""; + return null; + default: + // We got some kind of error, maybe it's temporary, maybe it's permanent + // Don't cache anything, we'll try again later + return null; + } + case "": + // API key is permanently unavailable via AccessDenied + return null; + default: + // We have key already fetched and cached, return it + return SteamApiKey; + } + } + + private async Task> GetApiKeyState() { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { + return null; + } + + const string request = SteamCommunityURL + "/dev/apikey?l=english"; + HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false); + + HtmlNode titleNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='mainContents']/h2"); + if (titleNode == null) { + return null; + } + + string title = titleNode.InnerText; + if (string.IsNullOrEmpty(title)) { + Bot.ArchiLogger.LogNullError(nameof(title)); + return new Tuple(ESteamApiKeyState.Error, null); + } + + if (title.Contains("Access Denied")) { + return new Tuple(ESteamApiKeyState.AccessDenied, null); + } + + HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@id='bodyContents_ex']/p"); + if (htmlNode == null) { + Bot.ArchiLogger.LogNullError(nameof(htmlNode)); + return new Tuple(ESteamApiKeyState.Error, null); + } + + string text = htmlNode.InnerText; + if (string.IsNullOrEmpty(text)) { + Bot.ArchiLogger.LogNullError(nameof(text)); + return new Tuple(ESteamApiKeyState.Error, null); + } + + if (text.Contains("Registering for a Steam Web API Key")) { + return new Tuple(ESteamApiKeyState.NotRegisteredYet, null); + } + + int keyIndex = text.IndexOf("Key: ", StringComparison.Ordinal); + if (keyIndex < 0) { + Bot.ArchiLogger.LogNullError(nameof(keyIndex)); + return new Tuple(ESteamApiKeyState.Error, null); + } + + keyIndex += 5; + + if (text.Length <= keyIndex) { + Bot.ArchiLogger.LogNullError(nameof(text)); + return new Tuple(ESteamApiKeyState.Error, null); + } + + text = text.Substring(keyIndex); + if (text.Length != 32) { + Bot.ArchiLogger.LogNullError(nameof(text)); + return new Tuple(ESteamApiKeyState.Error, null); + } + + if (Utilities.IsValidHexadecimalString(text)) { + return new Tuple(ESteamApiKeyState.Registered, text); + } + + Bot.ArchiLogger.LogNullError(nameof(text)); + return new Tuple(ESteamApiKeyState.Error, null); + } + /* internal async Task SteamAwardsVote(byte voteID, uint appID) { if ((voteID == 0) || (appID == 0)) { @@ -1085,7 +1102,7 @@ namespace ArchiSteamFarm { return false; } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } @@ -1230,6 +1247,28 @@ namespace ArchiSteamFarm { } } + private async Task RegisterApiKey() { + if (!Ready || !await RefreshSessionIfNeeded().ConfigureAwait(false)) { + return false; + } + + string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); + if (string.IsNullOrEmpty(sessionID)) { + Bot.ArchiLogger.LogNullError(nameof(sessionID)); + return false; + } + + const string request = SteamCommunityURL + "/dev/registerkey"; + Dictionary data = new Dictionary(4) { + { "domain", "localhost" }, + { "agreeToTerms", "agreed" }, + { "sessionid", sessionID }, + { "Submit", "Register" } + }; + + return await WebBrowser.UrlPostRetry(request, data).ConfigureAwait(false); + } + private async Task UnlockParentalAccount(string parentalPin) { if (string.IsNullOrEmpty(parentalPin)) { Bot.ArchiLogger.LogNullError(nameof(parentalPin)); @@ -1252,5 +1291,12 @@ namespace ArchiSteamFarm { Bot.ArchiLogger.LogGenericInfo(Strings.Success); return true; } + + private enum ESteamApiKeyState : byte { + Error, + Registered, + NotRegisteredYet, + AccessDenied + } } } \ No newline at end of file diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 4a8c48f67..9aefd0974 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -60,7 +60,6 @@ namespace ArchiSteamFarm { internal readonly string BotName; internal bool HasMobileAuthenticator => BotDatabase?.MobileAuthenticator != null; - internal bool HasValidApiKey => !string.IsNullOrEmpty(ArchiWebHandler.SteamApiKey); internal bool IsConnectedAndLoggedOn => (SteamClient?.IsConnected == true) && (SteamClient.SteamID != null); internal bool IsPlayingPossible => !PlayingBlocked && (LibraryLockedBySteamID == 0); @@ -1832,10 +1831,10 @@ namespace ArchiSteamFarm { } Dictionary ownedGames; - if (HasValidApiKey) { - ownedGames = ArchiWebHandler.GetOwnedGames(SteamClient.SteamID); + if (await ArchiWebHandler.HasValidApiKey().ConfigureAwait(false)) { + ownedGames = await ArchiWebHandler.GetOwnedGames(SteamClient.SteamID).ConfigureAwait(false); } else { - ownedGames = await ArchiWebHandler.GetOwnedGames().ConfigureAwait(false); + ownedGames = await ArchiWebHandler.GetMyOwnedGames().ConfigureAwait(false); } if ((ownedGames == null) || (ownedGames.Count == 0)) { diff --git a/ArchiSteamFarm/Statistics.cs b/ArchiSteamFarm/Statistics.cs index f31e12bfd..2f2941940 100644 --- a/ArchiSteamFarm/Statistics.cs +++ b/ArchiSteamFarm/Statistics.cs @@ -40,9 +40,6 @@ namespace ArchiSteamFarm { private readonly Bot Bot; private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1); - private bool HasAutomatedTrading => Bot.HasMobileAuthenticator && Bot.HasValidApiKey; - private bool SteamTradeMatcher => Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher); - private string LastAvatarHash; private DateTime LastHeartBeat = DateTime.MinValue; private bool? LastMatchEverything; @@ -95,7 +92,7 @@ namespace ArchiSteamFarm { } // Don't announce if we don't meet conditions - if (!HasAutomatedTrading || !SteamTradeMatcher) { + if (!Bot.HasMobileAuthenticator || !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher) || !await Bot.ArchiWebHandler.HasValidApiKey().ConfigureAwait(false)) { ShouldSendHeartBeats = false; return; } diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index d74f626da..46f890202 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -91,11 +91,7 @@ namespace ArchiSteamFarm { internal void OnDisconnected() => IgnoredTrades.ClearAndTrim(); private async Task ParseActiveTrades() { - if (!Bot.HasValidApiKey) { - return; - } - - HashSet tradeOffers = Bot.ArchiWebHandler.GetActiveTradeOffers(); + HashSet tradeOffers = await Bot.ArchiWebHandler.GetActiveTradeOffers().ConfigureAwait(false); if ((tradeOffers == null) || (tradeOffers.Count == 0)) { return; } @@ -150,7 +146,7 @@ namespace ArchiSteamFarm { if (result.Result == ParseTradeResult.EResult.RejectedPermanently) { if (Bot.BotConfig.IsBotAccount) { Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.RejectingTrade, tradeOffer.TradeOfferID)); - Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID); + await Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false); break; } diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index a5295aa77..44987ac35 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -24,6 +24,7 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Linq; using System.Net; using System.Runtime.CompilerServices; @@ -76,6 +77,25 @@ namespace ArchiSteamFarm { } */ + internal static bool IsValidHexadecimalString(string text) { + if (string.IsNullOrEmpty(text)) { + Program.ArchiLogger.LogNullError(nameof(text)); + return false; + } + + const byte split = 16; + for (byte i = 0; i < text.Length; i += split) { + string textPart = string.Join("", text.Skip(i).Take(split)); + + ulong ignored; + if (!ulong.TryParse(textPart, NumberStyles.HexNumber, null, out ignored)) { + return false; + } + } + + return true; + } + internal static string ToHumanReadable(this TimeSpan timeSpan) { // It's really dirty, I'd appreciate a lot if C# offered nice TimeSpan formatting by default // Normally I'd use third-party library like Humanizer, but using it only for this bit is not worth it diff --git a/ArchiSteamFarm/config/example.json b/ArchiSteamFarm/config/example.json index ac03b2bfa..79726ba61 100644 --- a/ArchiSteamFarm/config/example.json +++ b/ArchiSteamFarm/config/example.json @@ -22,7 +22,6 @@ "SendOnFarmingFinished": false, "SendTradePeriod": 0, "ShutdownOnFarmingFinished": false, - "SteamApiKey": null, "SteamLogin": null, "SteamMasterClanID": 0, "SteamMasterID": 0, diff --git a/ConfigGenerator/BotConfig.cs b/ConfigGenerator/BotConfig.cs index 9e5dda8d8..d8308e3c5 100644 --- a/ConfigGenerator/BotConfig.cs +++ b/ConfigGenerator/BotConfig.cs @@ -108,10 +108,6 @@ namespace ConfigGenerator { [JsonProperty(Required = Required.DisallowNull)] public bool ShutdownOnFarmingFinished { get; set; } = false; - [LocalizedCategory("Access")] - [JsonProperty] - public string SteamApiKey { get; set; } = null; - [LocalizedCategory("Core")] [JsonProperty] public string SteamLogin { get; set; } = null;