diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index a019fab4d..20e1317d7 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -70,7 +70,6 @@ namespace ArchiSteamFarm { private string CachedApiKey; private bool? CachedPublicInventory; private string CachedTradeToken; - private DateTime InventoryRateLimitedUntil = DateTime.MinValue; private DateTime LastSessionRefreshCheck = DateTime.MinValue; private ulong SteamID; private string VanityURL; @@ -479,22 +478,6 @@ namespace ArchiSteamFarm { [SuppressMessage("ReSharper", "FunctionComplexityOverflow")] internal async Task> GetMySteamInventory(bool tradableOnly = false, HashSet wantedTypes = null, HashSet wantedRealAppIDs = null) { - if (DateTime.UtcNow < InventoryRateLimitedUntil) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, EResult.RateLimitExceeded)); - return null; - } - - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { - return null; - } - - await InventorySemaphore.WaitAsync().ConfigureAwait(false); - - if (DateTime.UtcNow < InventoryRateLimitedUntil) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, EResult.RateLimitExceeded)); - return null; - } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { return null; } @@ -505,27 +488,22 @@ namespace ArchiSteamFarm { string request = SteamCommunityURL + "/inventory/" + SteamID + "/" + Steam.Asset.SteamAppID + "/" + Steam.Asset.SteamCommunityContextID + "?l=english&count=5000"; ulong startAssetID = 0; + await InventorySemaphore.WaitAsync().ConfigureAwait(false); + try { while (true) { - (bool Success, Steam.InventoryResponse Result) response = await WebBrowser.UrlGetToJsonResultWithSuccessRetry(request + (startAssetID > 0 ? "&start_assetid=" + startAssetID : "")).ConfigureAwait(false); + Steam.InventoryResponse response = await WebBrowser.UrlGetToJsonResultRetry(request + (startAssetID > 0 ? "&start_assetid=" + startAssetID : "")).ConfigureAwait(false); - if (!response.Success) { + if (response == null) { return null; } - if (response.Success && (response.Result == null)) { - // If request succeeded but Steam responded with null body, this is rate-limiting - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, EResult.RateLimitExceeded)); - InventoryRateLimitedUntil = DateTime.UtcNow.AddMinutes(Bot.CaptchaCooldownInMinutes); - return null; - } - - if ((response.Result.Assets == null) || (response.Result.Assets.Count == 0) || (response.Result.Descriptions == null) || (response.Result.Descriptions.Count == 0)) { + if ((response.Assets == null) || (response.Assets.Count == 0) || (response.Descriptions == null) || (response.Descriptions.Count == 0)) { return result; } Dictionary descriptionMap = new Dictionary(); - foreach (Steam.InventoryResponse.Description description in response.Result.Descriptions.Where(description => description != null)) { + foreach (Steam.InventoryResponse.Description description in response.Descriptions.Where(description => description != null)) { if (description.ClassID == 0) { Bot.ArchiLogger.LogNullError(nameof(description.ClassID)); return null; @@ -554,7 +532,7 @@ namespace ArchiSteamFarm { descriptionMap[description.ClassID] = (appID, type, description.Tradable); } - foreach (Steam.Asset asset in response.Result.Assets.Where(asset => asset != null)) { + foreach (Steam.Asset asset in response.Assets.Where(asset => asset != null)) { if (descriptionMap.TryGetValue(asset.ClassID, out (uint AppID, Steam.Asset.EType Type, bool Tradable) description)) { if (tradableOnly && !description.Tradable) { continue; @@ -571,16 +549,16 @@ namespace ArchiSteamFarm { result.Add(asset); } - if (!response.Result.MoreItems) { + if (!response.MoreItems) { return result; } - if (response.Result.LastAssetID == 0) { - Bot.ArchiLogger.LogNullError(nameof(response.Result.LastAssetID)); + if (response.LastAssetID == 0) { + Bot.ArchiLogger.LogNullError(nameof(response.LastAssetID)); return null; } - startAssetID = response.Result.LastAssetID; + startAssetID = response.LastAssetID; } } finally { if (Program.GlobalConfig.InventoryLimiterDelay == 0) { @@ -953,28 +931,14 @@ namespace ArchiSteamFarm { } internal async Task MarkInventory() { - if (DateTime.UtcNow < InventoryRateLimitedUntil) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, EResult.RateLimitExceeded)); - return false; - } - - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { - return false; - } - - await InventorySemaphore.WaitAsync().ConfigureAwait(false); - - if (DateTime.UtcNow < InventoryRateLimitedUntil) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, EResult.RateLimitExceeded)); - return false; - } - if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) { return false; } const string request = SteamCommunityURL + "/my/inventory"; + await InventorySemaphore.WaitAsync().ConfigureAwait(false); + try { return await WebBrowser.UrlHeadRetry(request).ConfigureAwait(false); } finally { diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index ab5cc477f..1f049efe7 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -42,10 +42,10 @@ using SteamKit2.Discovery; namespace ArchiSteamFarm { internal sealed class Bot : IDisposable { internal const ushort CallbackSleep = 500; // In miliseconds - internal const byte CaptchaCooldownInMinutes = 25; // Captcha disappears after around 20 minutes, so we make it 25 internal const byte MinPlayingBlockedTTL = 60; // Delay in seconds added when account was occupied during our disconnect, to not disconnect other Steam client session too soon private const byte FamilySharingInactivityMinutes = 5; + private const byte LoginCooldownInMinutes = 25; // Captcha disappears after around 20 minutes, so we make it 25 private const uint LoginID = GlobalConfig.DefaultIPCPort; // This must be the same for all ASF bots and all ASF processes private const ushort MaxSteamMessageLength = 2048; private const byte MaxTwoFactorCodeFailures = 3; @@ -1617,8 +1617,8 @@ namespace ArchiSteamFarm { await Task.Delay(5000).ConfigureAwait(false); break; case EResult.RateLimitExceeded: - ArchiLogger.LogGenericInfo(string.Format(Strings.BotRateLimitExceeded, TimeSpan.FromMinutes(CaptchaCooldownInMinutes).ToHumanReadable())); - await Task.Delay(CaptchaCooldownInMinutes * 60 * 1000).ConfigureAwait(false); + ArchiLogger.LogGenericInfo(string.Format(Strings.BotRateLimitExceeded, TimeSpan.FromMinutes(LoginCooldownInMinutes).ToHumanReadable())); + await Task.Delay(LoginCooldownInMinutes * 60 * 1000).ConfigureAwait(false); break; case EResult.AccountDisabled: // Do not attempt to reconnect, those failures are permanent diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index ef013210e..9c9c1b463 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -156,34 +156,6 @@ namespace ArchiSteamFarm { } } - internal async Task<(bool Success, T Result)> UrlGetToJsonResultWithSuccessRetry(string request, string referer = null) { - if (string.IsNullOrEmpty(request)) { - ArchiLogger.LogNullError(nameof(request)); - return default; - } - - string json = await UrlGetToContentRetry(request, referer).ConfigureAwait(false); - if (string.IsNullOrEmpty(json)) { - return default; - } - - T result; - - try { - result = JsonConvert.DeserializeObject(json); - } catch (JsonException e) { - ArchiLogger.LogGenericException(e); - - if (Debugging.IsUserDebugging) { - ArchiLogger.LogGenericDebug(string.Format(Strings.Content, json)); - } - - return default; - } - - return (true, result); - } - internal async Task UrlGetToXMLRetry(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { ArchiLogger.LogNullError(nameof(request));