This commit is contained in:
Łukasz Domeradzki 2024-03-27 19:55:07 +01:00
parent 0ae4b6ff18
commit 9a02c79e0a
No known key found for this signature in database
GPG key ID: 6B138B4C64555AEA
7 changed files with 70 additions and 37 deletions

View file

@ -29,7 +29,6 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@ -253,7 +252,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
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;
@ -940,7 +939,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
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)));

View file

@ -33,7 +33,6 @@ using System.ComponentModel.DataAnnotations;
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;
@ -3669,7 +3668,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
.Where(item => appIDs.Contains(item.RealAppID) && BotConfig.CompleteTypesToSend.Contains(item.Type))
.ToHashSetAsync()
.ConfigureAwait(false);
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
ArchiLogger.LogGenericWarningException(e);
return;

View file

@ -25,7 +25,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Collections;
@ -499,7 +498,7 @@ public sealed class Trading : IDisposable {
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)));

View file

@ -26,7 +26,6 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Localization;
@ -34,6 +33,7 @@ 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;
@ -179,14 +179,15 @@ public sealed class ArchiHandler : ClientMsgHandler {
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,
@ -198,23 +199,58 @@ public sealed class ArchiHandler : ClientMsgHandler {
},
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;
try {
serviceMethodResponse = await UnifiedEconService.SendMessage(x => x.GetInventoryItemsWithDescriptions(request)).ToLongRunningTask().ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
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);
}
throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(serviceMethodResponse)));
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));
}
}
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>();

View file

@ -275,7 +275,7 @@ public sealed class ArchiWebHandler : IDisposable {
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);
}
@ -293,22 +293,24 @@ public sealed class ArchiWebHandler : IDisposable {
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 {
@ -324,12 +326,12 @@ public sealed class ArchiWebHandler : IDisposable {
}
}
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)) {

View file

@ -27,7 +27,6 @@ using System.Collections.Immutable;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Collections;
@ -430,7 +429,7 @@ public sealed class Actions : IAsyncDisposable, IDisposable {
}
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));

View file

@ -26,7 +26,6 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@ -3114,7 +3113,7 @@ public sealed class Commands {
completeSuccess = false;
}
}
} catch (HttpRequestException e) {
} catch (TimeoutException e) {
Bot.ArchiLogger.LogGenericWarningException(e);
completeSuccess = false;