diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj
index 007ec6914..3060a18ce 100644
--- a/ArchiSteamFarm/ArchiSteamFarm.csproj
+++ b/ArchiSteamFarm/ArchiSteamFarm.csproj
@@ -136,6 +136,7 @@
+
diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs
index ebc26ab2d..0bcadbfeb 100755
--- a/ArchiSteamFarm/Bot.cs
+++ b/ArchiSteamFarm/Bot.cs
@@ -665,6 +665,9 @@ namespace ArchiSteamFarm {
try {
await SteamApps.PICSGetProductInfo(0, null);
+ if (Program.GlobalConfig.Statistics) {
+ Statistics.OnHeartBeat(this).Forget();
+ }
} catch {
if (!IsConnectedAndLoggedOn || (HeartBeatFailures == byte.MaxValue)) {
return;
@@ -1210,7 +1213,7 @@ namespace ArchiSteamFarm {
}
if (Program.GlobalConfig.Statistics) {
- ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).Forget();
+ Statistics.OnLoggedOn(this).Forget();
}
Trading.CheckTrades().Forget();
@@ -1320,7 +1323,10 @@ namespace ArchiSteamFarm {
}
if (callback.FriendID == SteamClient.SteamID) {
- Events.OnStateUpdated(this, callback);
+ Events.OnPersonaState(this, callback);
+ if (Program.GlobalConfig.Statistics) {
+ Statistics.OnPersonaState(this, callback).Forget();
+ }
} else if ((callback.FriendID == LibraryLockedBySteamID) && (callback.GameID == 0)) {
LibraryLockedBySteamID = 0;
CheckOccupationStatus();
diff --git a/ArchiSteamFarm/Events.cs b/ArchiSteamFarm/Events.cs
index 085220e26..0966611b1 100644
--- a/ArchiSteamFarm/Events.cs
+++ b/ArchiSteamFarm/Events.cs
@@ -38,6 +38,6 @@ namespace ArchiSteamFarm {
Program.Shutdown();
}
- internal static void OnStateUpdated(Bot bot, SteamFriends.PersonaStateCallback callback) { }
+ internal static void OnPersonaState(Bot bot, SteamFriends.PersonaStateCallback callback) { }
}
}
\ No newline at end of file
diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs
index 5fc5e450e..b476f2df0 100644
--- a/ArchiSteamFarm/SharedInfo.cs
+++ b/ArchiSteamFarm/SharedInfo.cs
@@ -43,6 +43,7 @@ namespace ArchiSteamFarm {
internal const string LogFile = "log.txt";
internal const string ServiceDescription = "ASF is an application that allows you to farm steam cards using multiple steam accounts simultaneously.";
internal const string ServiceName = "ArchiSteamFarm";
+ internal const string StatisticsServer = "https://asf.justarchi.net";
internal const string VersionNumber = "2.1.7.0";
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
diff --git a/ArchiSteamFarm/Statistics.cs b/ArchiSteamFarm/Statistics.cs
new file mode 100644
index 000000000..1ac98c435
--- /dev/null
+++ b/ArchiSteamFarm/Statistics.cs
@@ -0,0 +1,85 @@
+/*
+ _ _ _ ____ _ _____
+ / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+ / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+ / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+
+ Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
+ Contact: JustArchi@JustArchi.net
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using SteamKit2;
+
+namespace ArchiSteamFarm {
+ internal static class Statistics {
+ internal static async Task OnHeartBeat(Bot bot) {
+ if (bot == null) {
+ ASF.ArchiLogger.LogNullError(nameof(bot));
+ return;
+ }
+
+ const string request = SharedInfo.StatisticsServer + "/api/HeartBeat";
+ Dictionary data = new Dictionary(1) {
+ { "SteamID", bot.SteamID.ToString() }
+ };
+
+ // We don't need retry logic here
+ await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false);
+ }
+
+ internal static async Task OnLoggedOn(Bot bot) {
+ if (bot == null) {
+ ASF.ArchiLogger.LogNullError(nameof(bot));
+ return;
+ }
+
+ 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" }
+ };
+
+ // 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));
+ return;
+ }
+
+ string avatarHash = BitConverter.ToString(callback.AvatarHash).Replace("-", "").ToLowerInvariant();
+
+ const string request = SharedInfo.StatisticsServer + "/api/PersonaState";
+ Dictionary data = new Dictionary(2) {
+ { "SteamID", bot.SteamID.ToString() },
+ { "AvatarHash", avatarHash }
+ };
+
+ // We don't need retry logic here
+ await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs
index b0516a4c9..e902f85b5 100644
--- a/ArchiSteamFarm/WebBrowser.cs
+++ b/ArchiSteamFarm/WebBrowser.cs
@@ -219,6 +219,17 @@ namespace ArchiSteamFarm {
return null;
}
+ internal async Task UrlPost(string request, IEnumerable> data = null, string referer = null) {
+ if (string.IsNullOrEmpty(request)) {
+ ArchiLogger.LogNullError(nameof(request));
+ return false;
+ }
+
+ using (HttpResponseMessage response = await UrlPostToResponse(request, data, referer).ConfigureAwait(false)) {
+ return response != null;
+ }
+ }
+
internal async Task UrlPostRetry(string request, ICollection> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
@@ -428,17 +439,6 @@ namespace ArchiSteamFarm {
}
}
- private async Task UrlPost(string request, IEnumerable> data = null, string referer = null) {
- if (string.IsNullOrEmpty(request)) {
- ArchiLogger.LogNullError(nameof(request));
- return false;
- }
-
- using (HttpResponseMessage response = await UrlPostToResponse(request, data, referer).ConfigureAwait(false)) {
- return response != null;
- }
- }
-
private async Task UrlPostToContent(string request, IEnumerable> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
diff --git a/GUI/Events.cs b/GUI/Events.cs
index f0b691e12..b040b7c50 100644
--- a/GUI/Events.cs
+++ b/GUI/Events.cs
@@ -31,7 +31,7 @@ namespace ArchiSteamFarm {
internal static class Events {
internal static void OnBotShutdown() { }
- internal static void OnStateUpdated(Bot bot, SteamFriends.PersonaStateCallback callback) {
+ internal static void OnPersonaState(Bot bot, SteamFriends.PersonaStateCallback callback) {
if (bot == null) {
ASF.ArchiLogger.LogNullError(nameof(bot));
return;
diff --git a/GUI/GUI.csproj b/GUI/GUI.csproj
index f6ae2af71..199ca51d4 100644
--- a/GUI/GUI.csproj
+++ b/GUI/GUI.csproj
@@ -145,6 +145,9 @@
SharedInfo.cs
+
+ Statistics.cs
+
Trading.cs
diff --git a/resources/Statistics.mwb b/resources/Statistics.mwb
new file mode 100644
index 000000000..22149cc3d
Binary files /dev/null and b/resources/Statistics.mwb differ