Skip to content

Commit

Permalink
Decrease itemsCountPerRequest to 5000, optimize performance a bit, cl…
Browse files Browse the repository at this point in the history
…oses #3171
  • Loading branch information
JustArchi committed Mar 22, 2024
1 parent 9682d1d commit c5009da
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 11 deletions.
13 changes: 8 additions & 5 deletions ArchiSteamFarm/Steam/Integration/ArchiHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public async Task<bool> AddFriend(ulong steamID) {
}

[PublicAPI]
public async IAsyncEnumerable<Asset> GetMyInventoryAsync(uint appID = Asset.SteamAppID, ulong contextID = Asset.SteamCommunityContextID, bool tradableOnly = false, bool marketableOnly = false, ushort itemsCountPerRequest = 10000) {
public async IAsyncEnumerable<Asset> GetMyInventoryAsync(uint appID = Asset.SteamAppID, ulong contextID = Asset.SteamCommunityContextID, bool tradableOnly = false, bool marketableOnly = false, ushort itemsCountPerRequest = ArchiWebHandler.MaxItemsInSingleInventoryRequest) {
ArgumentOutOfRangeException.ThrowIfZero(appID);
ArgumentOutOfRangeException.ThrowIfZero(contextID);
ArgumentOutOfRangeException.ThrowIfZero(itemsCountPerRequest);
Expand All @@ -189,6 +189,8 @@ public async IAsyncEnumerable<Asset> GetMyInventoryAsync(uint appID = Asset.Stea
// 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) {
ulong currentStartAssetID = startAssetID;

Expand Down Expand Up @@ -226,12 +228,13 @@ public async IAsyncEnumerable<Asset> GetMyInventoryAsync(uint appID = Asset.Stea

assetIDs ??= new HashSet<ulong>((int) response.total_inventory_count);

if ((response.assets.Count == 0) || (response.descriptions.Count == 0)) {
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, $"{nameof(response.assets)} || {nameof(response.descriptions)}"));
if (descriptions == null) {
descriptions = new Dictionary<(ulong ClassID, ulong InstanceID), InventoryDescription>();
} else {
// We don't need descriptions from the previous request
descriptions.Clear();
}

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

foreach (CEconItem_Description? description in response.descriptions) {
if (description.classid == 0) {
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(description.classid)));
Expand Down
21 changes: 15 additions & 6 deletions ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@
namespace ArchiSteamFarm.Steam.Integration;

public sealed class ArchiWebHandler : IDisposable {
// Steam network (ArchiHandler) works unstable with more items than this (throwing upon description details), while Steam web (ArchiWebHandler) silently limits to this value maximum
internal const ushort MaxItemsInSingleInventoryRequest = 5000;

private const string EconService = "IEconService";
private const string LoyaltyRewardsService = "ILoyaltyRewardsService";
private const ushort MaxItemsInSingleInventoryRequest = 5000;
private const byte MinimumSessionValidityInSeconds = 10;
private const string SteamAppsService = "ISteamApps";

Expand Down Expand Up @@ -261,6 +263,8 @@ public async IAsyncEnumerable<Asset> GetInventoryAsync(ulong steamID = 0, uint a
// 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;

int rateLimitingDelay = (ASF.GlobalConfig?.InventoryLimiterDelay ?? GlobalConfig.DefaultInventoryLimiterDelay) * 1000;

while (true) {
Expand Down Expand Up @@ -328,23 +332,28 @@ public async IAsyncEnumerable<Asset> GetInventoryAsync(ulong steamID = 0, uint a
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.TotalInventoryCount == 0) {
if ((response.Content.TotalInventoryCount == 0) || (response.Content.Assets.Count == 0)) {
// Empty inventory
yield break;
}

if (response.Content.Descriptions.Count == 0) {
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(response.Content.Descriptions)));
}

if (response.Content.TotalInventoryCount > Array.MaxLength) {
throw new InvalidOperationException(nameof(response.Content.TotalInventoryCount));
}

assetIDs ??= new HashSet<ulong>((int) response.Content.TotalInventoryCount);

if ((response.Content.Assets.Count == 0) || (response.Content.Descriptions.Count == 0)) {
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, $"{nameof(response.Content.Assets)} || {nameof(response.Content.Descriptions)}"));
if (descriptions == null) {
descriptions = new Dictionary<(ulong ClassID, ulong InstanceID), InventoryDescription>();
} else {
// We don't need descriptions from the previous request
descriptions.Clear();
}

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

foreach (InventoryDescription description in response.Content.Descriptions) {
if (description.ClassID == 0) {
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(description.ClassID)));
Expand Down

0 comments on commit c5009da

Please sign in to comment.