Skip to content

Commit

Permalink
Closes #3174
Browse files Browse the repository at this point in the history
  • Loading branch information
JustArchi committed Mar 27, 2024
1 parent 0ae4b6f commit 9a02c79
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -253,7 +252,7 @@ internal async Task OnPersonaState(string? nickname = null, string? avatarHash =

try {
inventory = await Bot.ArchiHandler.GetMyInventoryAsync().ToListAsync().ConfigureAwait(false);
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
ShouldSendHeartBeats = false;

Expand Down Expand Up @@ -940,7 +939,7 @@ private async void MatchActively(object? state = null) {

try {
assetsForMatching = await Bot.ArchiHandler.GetMyInventoryAsync().Where(item => item is { AssetID: > 0, Amount: > 0, ClassID: > 0, RealAppID: > 0, Type: > EAssetType.Unknown, Rarity: > EAssetRarity.Unknown, IsSteamPointsShopItem: false } && acceptedMatchableTypes.Contains(item.Type) && !Bot.BotDatabase.MatchActivelyBlacklistAppIDs.Contains(item.RealAppID)).ToHashSetAsync().ConfigureAwait(false);
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
Bot.ArchiLogger.LogGenericWarningException(e);
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(assetsForMatching)));

Expand Down
3 changes: 1 addition & 2 deletions ArchiSteamFarm/Steam/Bot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading;
Expand Down Expand Up @@ -3669,7 +3668,7 @@ private async Task SendCompletedSets() {
.Where(item => appIDs.Contains(item.RealAppID) && BotConfig.CompleteTypesToSend.Contains(item.Type))
.ToHashSetAsync()
.ConfigureAwait(false);
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
ArchiLogger.LogGenericWarningException(e);

return;
Expand Down
3 changes: 1 addition & 2 deletions ArchiSteamFarm/Steam/Exchange/Trading.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Collections;
Expand Down Expand Up @@ -499,7 +498,7 @@ private async Task<ParseTradeResult> ParseTrade(TradeOffer tradeOffer) {

try {
inventory = await Bot.ArchiHandler.GetMyInventoryAsync().Where(item => !item.IsSteamPointsShopItem && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity))).ToHashSetAsync().ConfigureAwait(false);
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
// If we can't check our inventory when not using MatchEverything, this is a temporary failure, try again later
Bot.ArchiLogger.LogGenericWarningException(e);
Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, nameof(inventory)));
Expand Down
64 changes: 50 additions & 14 deletions ArchiSteamFarm/Steam/Integration/ArchiHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.NLog;
using ArchiSteamFarm.Steam.Data;
using ArchiSteamFarm.Steam.Integration.Callbacks;
using ArchiSteamFarm.Steam.Integration.CMsgs;
using ArchiSteamFarm.Web;
using JetBrains.Annotations;
using SteamKit2;
using SteamKit2.Internal;
Expand Down Expand Up @@ -179,14 +179,15 @@ public async IAsyncEnumerable<Asset> GetMyInventoryAsync(uint appID = Asset.Stea
ArgumentOutOfRangeException.ThrowIfZero(contextID);
ArgumentOutOfRangeException.ThrowIfZero(itemsCountPerRequest);

if (Client.SteamID == null) {
throw new InvalidOperationException(nameof(Client.SteamID));
if (!Client.IsConnected || (Client.SteamID == null)) {
throw new TimeoutException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Client.IsConnected)));
}

// We need to store asset IDs to make sure we won't get duplicate items
HashSet<ulong>? assetIDs = null;
ulong steamID = Client.SteamID;

Dictionary<(ulong ClassID, ulong InstanceID), InventoryDescription>? descriptions = null;
if (steamID == 0) {
throw new InvalidOperationException(nameof(Client.SteamID));
}

CEcon_GetInventoryItemsWithDescriptions_Request request = new() {
appid = appID,
Expand All @@ -198,23 +199,58 @@ public async IAsyncEnumerable<Asset> GetMyInventoryAsync(uint appID = Asset.Stea
},

get_descriptions = true,
steamid = Client.SteamID,
steamid = steamID,
count = itemsCountPerRequest
};

// We need to store asset IDs to make sure we won't get duplicate items
HashSet<ulong>? assetIDs = null;

Dictionary<(ulong ClassID, ulong InstanceID), InventoryDescription>? descriptions = null;

while (true) {
SteamUnifiedMessages.ServiceMethodResponse serviceMethodResponse;
SteamUnifiedMessages.ServiceMethodResponse? serviceMethodResponse = null;

for (byte i = 0; (i < WebBrowser.MaxTries) && (serviceMethodResponse?.Result != EResult.OK) && Client.IsConnected && (Client.SteamID != null); i++) {
if (i > 0) {
// It seems 2 seconds is enough to win over DuplicateRequest, so we'll use that for this and also other network-related failures
await Task.Delay(2000).ConfigureAwait(false);
}

try {
serviceMethodResponse = await UnifiedEconService.SendMessage(x => x.GetInventoryItemsWithDescriptions(request)).ToLongRunningTask().ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);

try {
serviceMethodResponse = await UnifiedEconService.SendMessage(x => x.GetInventoryItemsWithDescriptions(request)).ToLongRunningTask().ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
continue;
}

// Interpret the result and see what we should do about it
switch (serviceMethodResponse.Result) {
case EResult.Busy:
case EResult.DuplicateRequest:
case EResult.ServiceUnavailable:
// Those are generic failures that we should be able to retry
ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, serviceMethodResponse.Result));

continue;
case EResult.OK:
// Success, we can continue
break;
default:
// Unknown failures, report them and do not retry since we're unsure if we should
ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(serviceMethodResponse.Result), serviceMethodResponse.Result));

throw new TimeoutException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, serviceMethodResponse.Result));
}
}

throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(serviceMethodResponse)));
if (serviceMethodResponse == null) {
throw new TimeoutException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(serviceMethodResponse)));
}

if (serviceMethodResponse.Result != EResult.OK) {
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, serviceMethodResponse.Result));
throw new TimeoutException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, serviceMethodResponse.Result));
}

CEcon_GetInventoryItemsWithDescriptions_Response response = serviceMethodResponse.GetDeserializedResponse<CEcon_GetInventoryItemsWithDescriptions_Response>();
Expand Down
26 changes: 14 additions & 12 deletions ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public async IAsyncEnumerable<Asset> GetInventoryAsync(ulong steamID = 0, uint a
ObjectResponse<InventoryResponse>? response = null;

try {
for (byte i = 0; (i < WebBrowser.MaxTries) && (response == null); i++) {
for (byte i = 0; (i < WebBrowser.MaxTries) && (response?.StatusCode.IsSuccessCode() != true); i++) {
if ((i > 0) && (rateLimitingDelay > 0)) {
await Task.Delay(rateLimitingDelay).ConfigureAwait(false);
}
Expand All @@ -293,22 +293,24 @@ public async IAsyncEnumerable<Asset> GetInventoryAsync(ulong steamID = 0, uint a
if (response.StatusCode.IsServerErrorCode()) {
if (string.IsNullOrEmpty(response.Content?.ErrorText)) {
// This is a generic server error without a reason, try again
response = null;

continue;
}

// Interpret the reason and see if we should try again
Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText));

// Try to interpret the failure reason and see if we should try again
switch (response.Content.ErrorCode) {
case EResult.Busy:
case EResult.DuplicateRequest:
case EResult.ServiceUnavailable:
response = null;

// Those are generic failures that we should be able to retry
continue;
}
default:
// Unknown failures, report them and do not retry since we're unsure if we should
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(response.Content.ErrorText), response.Content.ErrorText));

// This is actually client error with a reason, so it doesn't make sense to retry
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText), null, response.StatusCode);
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText), null, response.StatusCode);
}
}
}
} finally {
Expand All @@ -324,12 +326,12 @@ public async IAsyncEnumerable<Asset> GetInventoryAsync(ulong steamID = 0, uint a
}
}

if (response?.Content == null) {
if (response == null) {
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(response)));
}

if (response.Content.Result is not EResult.OK) {
throw new HttpRequestException(!string.IsNullOrEmpty(response.Content.ErrorText) ? string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText) : response.Content.Result.HasValue ? string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.Result) : Strings.WarningFailed);
if ((response.Content == null) || (response.StatusCode.IsSuccessCode() != true)) {
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, !string.IsNullOrEmpty(response.Content?.ErrorText) ? response.Content.ErrorText : response.Content?.Result.HasValue == true ? response.Content.Result : response.StatusCode));
}

if ((response.Content.TotalInventoryCount == 0) || (response.Content.Assets.Count == 0)) {
Expand Down
3 changes: 1 addition & 2 deletions ArchiSteamFarm/Steam/Interaction/Actions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Collections;
Expand Down Expand Up @@ -430,7 +429,7 @@ static async () => {
}

inventory = await Bot.ArchiHandler.GetMyInventoryAsync(appID, contextID, true).Where(item => filterFunction(item)).ToHashSetAsync().ConfigureAwait(false);
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
Bot.ArchiLogger.LogGenericWarningException(e);

return (false, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
Expand Down
3 changes: 1 addition & 2 deletions ArchiSteamFarm/Steam/Interaction/Commands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
Expand Down Expand Up @@ -3114,7 +3113,7 @@ internal void OnNewLicenseList() {
completeSuccess = false;
}
}
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
Bot.ArchiLogger.LogGenericWarningException(e);

completeSuccess = false;
Expand Down

0 comments on commit 9a02c79

Please sign in to comment.