diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 0bcadbfeb..6f94d06fb 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -76,6 +76,7 @@ namespace ArchiSteamFarm { private readonly ConcurrentHashSet OwnedPackageIDs = new ConcurrentHashSet(); private readonly string SentryFile; + private readonly Statistics Statistics; private readonly SteamApps SteamApps; private readonly SteamClient SteamClient; private readonly ConcurrentHashSet SteamFamilySharingIDs = new ConcurrentHashSet(); @@ -203,6 +204,10 @@ namespace ArchiSteamFarm { Trading = new Trading(this); + if (Program.GlobalConfig.Statistics) { + Statistics = new Statistics(this); + } + HeartBeatTimer = new Timer(async e => await HeartBeat().ConfigureAwait(false), null, TimeSpan.FromMinutes(1) + TimeSpan.FromMinutes(0.2 * Bots.Count), // Delay TimeSpan.FromMinutes(1) // Period ); @@ -665,9 +670,7 @@ namespace ArchiSteamFarm { try { await SteamApps.PICSGetProductInfo(0, null); - if (Program.GlobalConfig.Statistics) { - Statistics.OnHeartBeat(this).Forget(); - } + Statistics?.OnHeartBeat().Forget(); } catch { if (!IsConnectedAndLoggedOn || (HeartBeatFailures == byte.MaxValue)) { return; @@ -1212,10 +1215,7 @@ namespace ArchiSteamFarm { }).Forget(); } - if (Program.GlobalConfig.Statistics) { - Statistics.OnLoggedOn(this).Forget(); - } - + Statistics?.OnLoggedOn().Forget(); Trading.CheckTrades().Forget(); break; case EResult.InvalidPassword: @@ -1324,9 +1324,7 @@ namespace ArchiSteamFarm { if (callback.FriendID == SteamClient.SteamID) { Events.OnPersonaState(this, callback); - if (Program.GlobalConfig.Statistics) { - Statistics.OnPersonaState(this, callback).Forget(); - } + Statistics?.OnPersonaState(callback).Forget(); } else if ((callback.FriendID == LibraryLockedBySteamID) && (callback.GameID == 0)) { LibraryLockedBySteamID = 0; CheckOccupationStatus(); diff --git a/ArchiSteamFarm/Statistics.cs b/ArchiSteamFarm/Statistics.cs index 1ac98c435..981e23f84 100644 --- a/ArchiSteamFarm/Statistics.cs +++ b/ArchiSteamFarm/Statistics.cs @@ -28,45 +28,55 @@ using System.Threading.Tasks; using SteamKit2; namespace ArchiSteamFarm { - internal static class Statistics { - internal static async Task OnHeartBeat(Bot bot) { + internal sealed class Statistics { + private const byte MinHeartBeatTTL = 5; // Minimum amount of minutes we must wait before sending next HeartBeat + + private readonly Bot Bot; + + private DateTime LastHeartBeat = DateTime.MinValue; + + internal Statistics(Bot bot) { if (bot == null) { - ASF.ArchiLogger.LogNullError(nameof(bot)); + throw new ArgumentNullException(nameof(bot)); + } + + Bot = bot; + } + + internal async Task OnHeartBeat() { + if (DateTime.Now < LastHeartBeat.AddMinutes(MinHeartBeatTTL)) { return; } const string request = SharedInfo.StatisticsServer + "/api/HeartBeat"; Dictionary data = new Dictionary(1) { - { "SteamID", bot.SteamID.ToString() } + { "SteamID", Bot.SteamID.ToString() } }; // We don't need retry logic here - await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false); + if (await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false)) { + LastHeartBeat = DateTime.Now; + } } - internal static async Task OnLoggedOn(Bot bot) { - if (bot == null) { - ASF.ArchiLogger.LogNullError(nameof(bot)); - return; - } - - await bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false); + internal async Task OnLoggedOn() { + await Bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false); const string request = SharedInfo.StatisticsServer + "/api/LoggedOn"; Dictionary data = new Dictionary(4) { - { "SteamID", bot.SteamID.ToString() }, - { "HasMobileAuthenticator", bot.HasMobileAuthenticator ? "1" : "0" }, - { "SteamTradeMatcher", bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher) ? "1" : "0" }, - { "MatchEverything", bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) ? "1" : "0" } + { "SteamID", Bot.SteamID.ToString() }, + { "HasMobileAuthenticator", Bot.HasMobileAuthenticator ? "1" : "0" }, + { "SteamTradeMatcher", Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher) ? "1" : "0" }, + { "MatchEverything", Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) ? "1" : "0" } }; // We don't need retry logic here await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false); } - internal static async Task OnPersonaState(Bot bot, SteamFriends.PersonaStateCallback callback) { - if ((bot == null) || (callback == null)) { - ASF.ArchiLogger.LogNullError(nameof(bot) + " || " + nameof(callback)); + internal async Task OnPersonaState(SteamFriends.PersonaStateCallback callback) { + if (callback == null) { + ASF.ArchiLogger.LogNullError(nameof(callback)); return; } @@ -74,7 +84,7 @@ namespace ArchiSteamFarm { const string request = SharedInfo.StatisticsServer + "/api/PersonaState"; Dictionary data = new Dictionary(2) { - { "SteamID", bot.SteamID.ToString() }, + { "SteamID", Bot.SteamID.ToString() }, { "AvatarHash", avatarHash } }; diff --git a/resources/Statistics.mwb b/resources/Statistics.mwb index 22149cc3d..1f96f222d 100644 Binary files a/resources/Statistics.mwb and b/resources/Statistics.mwb differ diff --git a/resources/Statistics.mwb.bak b/resources/Statistics.mwb.bak new file mode 100644 index 000000000..da2cd2e7c Binary files /dev/null and b/resources/Statistics.mwb.bak differ