From aea9dee4ead6ee1397c5bfb39b28f640ef929e85 Mon Sep 17 00:00:00 2001 From: Archi Date: Wed, 29 Nov 2023 14:26:57 +0100 Subject: [PATCH] Further decrease server load We can keep inventory checksum before deduplication in the cache. If it's determined to be the same, then our inventory state didn't change, so it also doesn't make much sense to ask server for set parts and announcement. --- .../BotCache.cs | 19 ++++++++ .../RemoteCommunication.cs | 45 ++++++++++++++++--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/BotCache.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/BotCache.cs index 3f3c948d6..f29c633fb 100644 --- a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/BotCache.cs +++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/BotCache.cs @@ -50,9 +50,25 @@ internal sealed class BotCache : SerializableFile { } } + internal string? LastInventoryChecksumBeforeDeduplication { + get => BackingLastInventoryChecksumBeforeDeduplication; + + set { + if (BackingLastInventoryChecksumBeforeDeduplication == value) { + return; + } + + BackingLastInventoryChecksumBeforeDeduplication = value; + Utilities.InBackground(Save); + } + } + [JsonProperty] private string? BackingLastAnnouncedTradeToken; + [JsonProperty] + private string? BackingLastInventoryChecksumBeforeDeduplication; + private BotCache(string filePath) : this() { ArgumentException.ThrowIfNullOrEmpty(filePath); @@ -65,6 +81,9 @@ internal sealed class BotCache : SerializableFile { [UsedImplicitly] public bool ShouldSerializeBackingLastAnnouncedTradeToken() => !string.IsNullOrEmpty(BackingLastAnnouncedTradeToken); + [UsedImplicitly] + public bool ShouldSerializeBackingLastInventoryChecksumBeforeDeduplication() => !string.IsNullOrEmpty(BackingLastInventoryChecksumBeforeDeduplication); + [UsedImplicitly] public bool ShouldSerializeLastAnnouncedAssetsForListing() => LastAnnouncedAssetsForListing.Count > 0; diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs index d68dcdbc4..a6a18f5bf 100644 --- a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs +++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs @@ -329,6 +329,27 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { } } + BotCache ??= await BotCache.CreateOrLoad(BotCacheFilePath).ConfigureAwait(false); + + string inventoryChecksumBeforeDeduplication = Backend.GenerateChecksumFor(assetsForListing); + + if ((tradeToken == BotCache.LastAnnouncedTradeToken) && !string.IsNullOrEmpty(BotCache.LastInventoryChecksumBeforeDeduplication)) { + if (inventoryChecksumBeforeDeduplication == BotCache.LastInventoryChecksumBeforeDeduplication) { + // We've determined our state to be the same, we can skip announce entirely and start sending heartbeats exclusively + bool triggerImmediately = !ShouldSendHeartBeats; + + LastAnnouncement = DateTime.UtcNow; + ShouldSendAnnouncementEarlier = false; + ShouldSendHeartBeats = true; + + if (triggerImmediately) { + Utilities.InBackground(() => OnHeartBeatTimer()); + } + + return; + } + } + if (!SignedInWithSteam) { HttpStatusCode? signInWithSteam = await ArchiNet.SignInWithSteam(Bot, WebBrowser).ConfigureAwait(false); @@ -350,8 +371,6 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { SignedInWithSteam = true; } - BotCache ??= await BotCache.CreateOrLoad(BotCacheFilePath).ConfigureAwait(false); - if (!matchEverything) { // We should deduplicate our sets before sending them to the server, for doing that we'll use ASFB set parts data HashSet realAppIDs = new(); @@ -444,6 +463,9 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { LastAnnouncement = DateTime.UtcNow; ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false; + // There is a possibility that our inventory has changed even if our announced assets did not, record that + BotCache.LastInventoryChecksumBeforeDeduplication = inventoryChecksumBeforeDeduplication; + return; } } @@ -453,6 +475,9 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { LastAnnouncement = DateTime.UtcNow; ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false; + // There is a possibility that our inventory has changed even if our announced assets did not, record that + BotCache.LastInventoryChecksumBeforeDeduplication = inventoryChecksumBeforeDeduplication; + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(assetsForListing)} > {MaxItemsCount}")); return; @@ -463,11 +488,18 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { if ((tradeToken == BotCache.LastAnnouncedTradeToken) && (checksum == previousChecksum)) { // We've determined our state to be the same, we can skip announce entirely and start sending heartbeats exclusively + bool triggerImmediately = !ShouldSendHeartBeats; + LastAnnouncement = DateTime.UtcNow; ShouldSendAnnouncementEarlier = false; ShouldSendHeartBeats = true; - Utilities.InBackground(() => OnHeartBeatTimer()); + if (triggerImmediately) { + Utilities.InBackground(() => OnHeartBeatTimer()); + } + + // There is a possibility that our inventory has changed even if our announced assets did not, record that + BotCache.LastInventoryChecksumBeforeDeduplication = inventoryChecksumBeforeDeduplication; return; } @@ -481,7 +513,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { BasicResponse? diffResponse = await Backend.AnnounceDiffForListing(WebBrowser, Bot.SteamID, inventoryAddedChanged, checksum, acceptedMatchableTypes, (uint) inventory.Count, matchEverything, tradeToken, previousInventoryState.Values, previousChecksum, nickname, avatarHash).ConfigureAwait(false); - if (HandleAnnounceResponse(BotCache, tradeToken, previousChecksum, assetsForListing, diffResponse)) { + if (HandleAnnounceResponse(BotCache, tradeToken, inventoryChecksumBeforeDeduplication, assetsForListing, previousChecksum, diffResponse)) { // Our diff announce has succeeded, we have nothing to do further Bot.ArchiLogger.LogGenericInfo(Strings.Success); @@ -493,7 +525,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { BasicResponse? response = await Backend.AnnounceForListing(WebBrowser, Bot.SteamID, assetsForListing, checksum, acceptedMatchableTypes, (uint) inventory.Count, matchEverything, tradeToken, nickname, avatarHash).ConfigureAwait(false); - HandleAnnounceResponse(BotCache, tradeToken, assetsForListing: assetsForListing, response: response); + HandleAnnounceResponse(BotCache, tradeToken, inventoryChecksumBeforeDeduplication, assetsForListing, response: response); } finally { RequestsSemaphore.Release(); } @@ -512,7 +544,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { } } - private bool HandleAnnounceResponse(BotCache botCache, string tradeToken, string? previousInventoryChecksum = null, ICollection? assetsForListing = null, BasicResponse? response = null) { + private bool HandleAnnounceResponse(BotCache botCache, string tradeToken, string? inventoryChecksumBeforeDeduplication = null, ICollection? assetsForListing = null, string? previousInventoryChecksum = null, BasicResponse? response = null) { ArgumentNullException.ThrowIfNull(botCache); ArgumentException.ThrowIfNullOrEmpty(tradeToken); @@ -577,6 +609,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { botCache.LastAnnouncedAssetsForListing.ReplaceWith(assetsForListing); botCache.LastAnnouncedTradeToken = tradeToken; + botCache.LastInventoryChecksumBeforeDeduplication = inventoryChecksumBeforeDeduplication; } return true;