From 18d5f1938f285aa3b46f2ab43d7cb60205b8aa6e Mon Sep 17 00:00:00 2001 From: JustArchi Date: Mon, 14 Jan 2019 21:50:23 +0100 Subject: [PATCH] Open configs for public API --- ArchiSteamFarm.sln.DotSettings | 5 +- ArchiSteamFarm/ASF.cs | 41 +++- ArchiSteamFarm/Actions.cs | 4 +- ArchiSteamFarm/ArchiCryptoHelper.cs | 4 +- ArchiSteamFarm/ArchiWebHandler.cs | 42 ++-- ArchiSteamFarm/Bot.cs | 30 +-- ArchiSteamFarm/BotConfig.cs | 76 +++---- ArchiSteamFarm/CardsFarmer.cs | 18 +- ArchiSteamFarm/Commands.cs | 8 +- ArchiSteamFarm/Debugging.cs | 2 +- ArchiSteamFarm/GlobalConfig.cs | 61 +++--- .../IPC/Controllers/Api/ASFController.cs | 6 +- .../IPC/Controllers/Api/CommandController.cs | 10 +- .../Middleware/ApiAuthenticationMiddleware.cs | 4 +- ArchiSteamFarm/IPC/Startup.cs | 2 +- ArchiSteamFarm/MobileAuthenticator.cs | 4 +- ArchiSteamFarm/Program.cs | 25 ++- ArchiSteamFarm/Trading.cs | 207 +++++++++--------- ArchiSteamFarm/Utilities.cs | 4 +- ArchiSteamFarm/WebBrowser.cs | 2 +- 20 files changed, 292 insertions(+), 263 deletions(-) diff --git a/ArchiSteamFarm.sln.DotSettings b/ArchiSteamFarm.sln.DotSettings index 8d7a0313d..5229f7f65 100644 --- a/ArchiSteamFarm.sln.DotSettings +++ b/ArchiSteamFarm.sln.DotSettings @@ -1,5 +1,8 @@  - False + True + True + True + True True ExplicitlyExcluded CF84911C-2C4C-4195-8AF3-ABBB6D3DE9AA/d:www diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index f8f22494e..abd51b264 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -37,6 +37,9 @@ using SteamKit2.Discovery; namespace ArchiSteamFarm { public static class ASF { + [PublicAPI] + public static GlobalConfig GlobalConfig { get; private set; } + // This is based on internal Valve guidelines, we're not using it as a hard limit private const byte MaximumRecommendedBotsCount = 10; @@ -60,13 +63,13 @@ namespace ArchiSteamFarm { return false; } - return (steamID == Program.GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID)); + return (steamID == GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID)); } internal static async Task Init() { - WebBrowser = new WebBrowser(ArchiLogger, Program.GlobalConfig.WebProxy, true); + WebBrowser = new WebBrowser(ArchiLogger, GlobalConfig.WebProxy, true); - if (Program.GlobalConfig.IPC) { + if (GlobalConfig.IPC) { await ArchiKestrel.Start().ConfigureAwait(false); } @@ -76,15 +79,29 @@ namespace ArchiSteamFarm { await Task.Delay(10000).ConfigureAwait(false); } - await Core.OnASFInitModules(Program.GlobalConfig.AdditionalProperties).ConfigureAwait(false); + await Core.OnASFInitModules(GlobalConfig.AdditionalProperties).ConfigureAwait(false); await InitBots().ConfigureAwait(false); InitEvents(); } + internal static void InitGlobalConfig(GlobalConfig globalConfig) { + if (globalConfig == null) { + ArchiLogger.LogNullError(nameof(globalConfig)); + + return; + } + + if (GlobalConfig != null) { + return; + } + + GlobalConfig = globalConfig; + } + internal static async Task RestartOrExit() { - if (Program.RestartAllowed && Program.GlobalConfig.AutoRestart) { + if (Program.RestartAllowed && GlobalConfig.AutoRestart) { ArchiLogger.LogGenericInfo(Strings.Restarting); await Task.Delay(5000).ConfigureAwait(false); await Program.Restart().ConfigureAwait(false); @@ -97,7 +114,7 @@ namespace ArchiSteamFarm { [ItemCanBeNull] internal static async Task Update(bool updateOverride = false) { - if (!SharedInfo.BuildInfo.CanUpdate || (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { + if (!SharedInfo.BuildInfo.CanUpdate || (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { return null; } @@ -122,7 +139,7 @@ namespace ArchiSteamFarm { } } - GitHub.ReleaseResponse releaseResponse = await GitHub.GetLatestRelease(Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable).ConfigureAwait(false); + GitHub.ReleaseResponse releaseResponse = await GitHub.GetLatestRelease(GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable).ConfigureAwait(false); if (releaseResponse == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); @@ -151,7 +168,7 @@ namespace ArchiSteamFarm { return SharedInfo.Version; } - if (!updateOverride && (Program.GlobalConfig.UpdatePeriod == 0)) { + if (!updateOverride && (GlobalConfig.UpdatePeriod == 0)) { ArchiLogger.LogGenericInfo(Strings.UpdateNewVersionAvailable); await Task.Delay(5000).ConfigureAwait(false); @@ -252,7 +269,7 @@ namespace ArchiSteamFarm { if (servers?.Any() != true) { ArchiLogger.LogGenericInfo(string.Format(Strings.Initializing, nameof(SteamDirectory))); - SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(Program.GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => WebBrowser.GenerateDisposableHttpClient())); + SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => WebBrowser.GenerateDisposableHttpClient())); try { await SteamDirectory.LoadAsync(steamConfiguration).ConfigureAwait(false); @@ -546,12 +563,12 @@ namespace ArchiSteamFarm { } private static async Task UpdateAndRestart() { - if (!SharedInfo.BuildInfo.CanUpdate || (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { + if (!SharedInfo.BuildInfo.CanUpdate || (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { return; } - if ((AutoUpdatesTimer == null) && (Program.GlobalConfig.UpdatePeriod > 0)) { - TimeSpan autoUpdatePeriod = TimeSpan.FromHours(Program.GlobalConfig.UpdatePeriod); + if ((AutoUpdatesTimer == null) && (GlobalConfig.UpdatePeriod > 0)) { + TimeSpan autoUpdatePeriod = TimeSpan.FromHours(GlobalConfig.UpdatePeriod); AutoUpdatesTimer = new Timer( async e => await UpdateAndRestart().ConfigureAwait(false), diff --git a/ArchiSteamFarm/Actions.cs b/ArchiSteamFarm/Actions.cs index 0a1628482..e4cb288b5 100644 --- a/ArchiSteamFarm/Actions.cs +++ b/ArchiSteamFarm/Actions.cs @@ -375,7 +375,7 @@ namespace ArchiSteamFarm { private ulong GetFirstSteamMasterID() => Bot.BotConfig.SteamUserPermissions.Where(kv => (kv.Key != 0) && (kv.Value == BotConfig.EPermission.Master)).Select(kv => kv.Key).OrderByDescending(steamID => steamID != Bot.SteamID).ThenBy(steamID => steamID).FirstOrDefault(); private static async Task LimitGiftsRequestsAsync() { - if (Program.GlobalConfig.GiftsLimiterDelay == 0) { + if (ASF.GlobalConfig.GiftsLimiterDelay == 0) { return; } @@ -383,7 +383,7 @@ namespace ArchiSteamFarm { Utilities.InBackground( async () => { - await Task.Delay(Program.GlobalConfig.GiftsLimiterDelay * 1000).ConfigureAwait(false); + await Task.Delay(ASF.GlobalConfig.GiftsLimiterDelay * 1000).ConfigureAwait(false); GiftsSemaphore.Release(); } ); diff --git a/ArchiSteamFarm/ArchiCryptoHelper.cs b/ArchiSteamFarm/ArchiCryptoHelper.cs index 59554ec60..9aa3ca8ae 100644 --- a/ArchiSteamFarm/ArchiCryptoHelper.cs +++ b/ArchiSteamFarm/ArchiCryptoHelper.cs @@ -26,7 +26,7 @@ using ArchiSteamFarm.Localization; using SteamKit2; namespace ArchiSteamFarm { - internal static class ArchiCryptoHelper { + public static class ArchiCryptoHelper { private static byte[] EncryptionKey = Encoding.UTF8.GetBytes(nameof(ArchiSteamFarm)); internal static string Decrypt(ECryptoMethod cryptoMethod, string encrypted) { @@ -189,7 +189,7 @@ namespace ArchiSteamFarm { } } - internal enum ECryptoMethod : byte { + public enum ECryptoMethod : byte { PlainText, AES, ProtectedDataForCurrentUser diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index dacfc8d20..75bb29f08 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -88,7 +88,7 @@ namespace ArchiSteamFarm { CachedApiKey = new ArchiCacheable(ResolveApiKey, TimeSpan.FromHours(1)); CachedPublicInventory = new ArchiCacheable(ResolvePublicInventory, TimeSpan.FromHours(1)); - WebBrowser = new WebBrowser(bot.ArchiLogger, Program.GlobalConfig.WebProxy); + WebBrowser = new WebBrowser(bot.ArchiLogger, ASF.GlobalConfig.WebProxy); } public void Dispose() { @@ -102,7 +102,7 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task GetAbsoluteProfileURL(bool waitForInitialization = true) { if (waitForInitialization && (SteamID == 0)) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -152,7 +152,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -227,7 +227,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -302,7 +302,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -377,7 +377,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -452,7 +452,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -560,7 +560,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -668,7 +668,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -779,7 +779,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -1245,7 +1245,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -1277,7 +1277,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -1393,7 +1393,7 @@ namespace ArchiSteamFarm { if (steamID == 0) { if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -1497,12 +1497,12 @@ namespace ArchiSteamFarm { startAssetID = response.LastAssetID; } finally { - if (Program.GlobalConfig.InventoryLimiterDelay == 0) { + if (ASF.GlobalConfig.InventoryLimiterDelay == 0) { InventorySemaphore.Release(); } else { Utilities.InBackground( async () => { - await Task.Delay(Program.GlobalConfig.InventoryLimiterDelay * 1000).ConfigureAwait(false); + await Task.Delay(ASF.GlobalConfig.InventoryLimiterDelay * 1000).ConfigureAwait(false); InventorySemaphore.Release(); } ); @@ -1774,7 +1774,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -1800,7 +1800,7 @@ namespace ArchiSteamFarm { } if (SteamID == 0) { - for (byte i = 0; (i < Program.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { + for (byte i = 0; (i < ASF.GlobalConfig.ConnectionTimeout) && (SteamID == 0) && Bot.IsConnectedAndLoggedOn; i++) { await Task.Delay(1000).ConfigureAwait(false); } @@ -1986,12 +1986,12 @@ namespace ArchiSteamFarm { const string request = "/my/inventory"; await UrlHeadWithSession(SteamCommunityURL, request, false).ConfigureAwait(false); } finally { - if (Program.GlobalConfig.InventoryLimiterDelay == 0) { + if (ASF.GlobalConfig.InventoryLimiterDelay == 0) { InventorySemaphore.Release(); } else { Utilities.InBackground( async () => { - await Task.Delay(Program.GlobalConfig.InventoryLimiterDelay * 1000).ConfigureAwait(false); + await Task.Delay(ASF.GlobalConfig.InventoryLimiterDelay * 1000).ConfigureAwait(false); InventorySemaphore.Release(); } ); @@ -2677,7 +2677,7 @@ namespace ArchiSteamFarm { return default; } - if (Program.GlobalConfig.WebLimiterDelay == 0) { + if (ASF.GlobalConfig.WebLimiterDelay == 0) { return await function().ConfigureAwait(false); } @@ -2701,7 +2701,7 @@ namespace ArchiSteamFarm { // We release rate-limiter semaphore regardless of our task completion, since we use that one only to guarantee rate-limiting of their creation Utilities.InBackground( async () => { - await Task.Delay(Program.GlobalConfig.WebLimiterDelay).ConfigureAwait(false); + await Task.Delay(ASF.GlobalConfig.WebLimiterDelay).ConfigureAwait(false); limiters.RateLimitingSemaphore.Release(); } ); diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 08e2561b0..4bc38364c 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -144,15 +144,15 @@ namespace ArchiSteamFarm { [JsonProperty] public EAccountFlags AccountFlags { get; private set; } + [JsonProperty] + public BotConfig BotConfig { get; private set; } + [JsonProperty] public bool KeepRunning { get; private set; } [JsonProperty] public string Nickname { get; private set; } - [JsonProperty] - internal BotConfig BotConfig { get; private set; } - internal bool PlayingBlocked { get; private set; } internal bool PlayingWasBlocked { get; private set; } internal ulong SteamID { get; private set; } @@ -211,7 +211,7 @@ namespace ArchiSteamFarm { ArchiWebHandler = new ArchiWebHandler(this); - SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(Program.GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => ArchiWebHandler.GenerateDisposableHttpClient())); + SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(ASF.GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => ArchiWebHandler.GenerateDisposableHttpClient())); // Initialize SteamClient = new SteamClient(steamConfiguration); @@ -263,7 +263,7 @@ namespace ArchiSteamFarm { Commands = new Commands(this); Trading = new Trading(this); - if (!Debugging.IsDebugBuild && Program.GlobalConfig.Statistics) { + if (!Debugging.IsDebugBuild && ASF.GlobalConfig.Statistics) { Statistics = new Statistics(this); } @@ -891,7 +891,7 @@ namespace ArchiSteamFarm { } if (BotConfig.ShutdownOnFarmingFinished) { - if (farmedSomething || (Program.GlobalConfig.IdleFarmingPeriod == 0)) { + if (farmedSomething || (ASF.GlobalConfig.IdleFarmingPeriod == 0)) { Stop(); return; @@ -1019,7 +1019,7 @@ namespace ArchiSteamFarm { ArchiLogger.LogChatMessage(true, message, steamID: steamID); - ushort maxMessageLength = (ushort) (MaxMessageLength - ReservedMessageLength - (Program.GlobalConfig.SteamMessagePrefix?.Length ?? 0)); + ushort maxMessageLength = (ushort) (MaxMessageLength - ReservedMessageLength - (ASF.GlobalConfig.SteamMessagePrefix?.Length ?? 0)); // We must escape our message prior to sending it message = Escape(message); @@ -1034,7 +1034,7 @@ namespace ArchiSteamFarm { i--; } - messagePart = Program.GlobalConfig.SteamMessagePrefix + (i > 0 ? "…" : "") + messagePart + (maxMessageLength < message.Length - i ? "…" : ""); + messagePart = ASF.GlobalConfig.SteamMessagePrefix + (i > 0 ? "…" : "") + messagePart + (maxMessageLength < message.Length - i ? "…" : ""); await MessagingSemaphore.WaitAsync().ConfigureAwait(false); @@ -1087,7 +1087,7 @@ namespace ArchiSteamFarm { ArchiLogger.LogChatMessage(true, message, chatGroupID, chatID); - ushort maxMessageLength = (ushort) (MaxMessageLength - ReservedMessageLength - (Program.GlobalConfig.SteamMessagePrefix?.Length ?? 0)); + ushort maxMessageLength = (ushort) (MaxMessageLength - ReservedMessageLength - (ASF.GlobalConfig.SteamMessagePrefix?.Length ?? 0)); // We must escape our message prior to sending it message = Escape(message); @@ -1102,7 +1102,7 @@ namespace ArchiSteamFarm { i--; } - messagePart = Program.GlobalConfig.SteamMessagePrefix + (i > 0 ? "…" : "") + messagePart + (maxMessageLength < message.Length - i ? "…" : ""); + messagePart = ASF.GlobalConfig.SteamMessagePrefix + (i > 0 ? "…" : "") + messagePart + (maxMessageLength < message.Length - i ? "…" : ""); await MessagingSemaphore.WaitAsync().ConfigureAwait(false); @@ -1445,7 +1445,7 @@ namespace ArchiSteamFarm { } try { - if (DateTime.UtcNow.Subtract(ArchiHandler.LastPacketReceived).TotalSeconds > Program.GlobalConfig.ConnectionTimeout) { + if (DateTime.UtcNow.Subtract(ArchiHandler.LastPacketReceived).TotalSeconds > ASF.GlobalConfig.ConnectionTimeout) { await SteamFriends.RequestProfileInfo(SteamClient.SteamID); } @@ -1461,7 +1461,7 @@ namespace ArchiSteamFarm { return; } - if (++HeartBeatFailures >= (byte) Math.Ceiling(Program.GlobalConfig.ConnectionTimeout / 10.0)) { + if (++HeartBeatFailures >= (byte) Math.Ceiling(ASF.GlobalConfig.ConnectionTimeout / 10.0)) { HeartBeatFailures = byte.MaxValue; ArchiLogger.LogGenericWarning(Strings.BotConnectionLost); Utilities.InBackground(() => Connect(true)); @@ -1535,7 +1535,7 @@ namespace ArchiSteamFarm { ConnectionFailureTimer = new Timer( async e => await InitPermanentConnectionFailure().ConfigureAwait(false), null, - TimeSpan.FromMinutes(Math.Ceiling(Program.GlobalConfig.ConnectionTimeout / 30.0)), // Delay + TimeSpan.FromMinutes(Math.Ceiling(ASF.GlobalConfig.ConnectionTimeout / 30.0)), // Delay Timeout.InfiniteTimeSpan // Period ); } @@ -1681,7 +1681,7 @@ namespace ArchiSteamFarm { } private static async Task LimitLoginRequestsAsync() { - if (Program.GlobalConfig.LoginLimiterDelay == 0) { + if (ASF.GlobalConfig.LoginLimiterDelay == 0) { return; } @@ -1689,7 +1689,7 @@ namespace ArchiSteamFarm { Utilities.InBackground( async () => { - await Task.Delay(Program.GlobalConfig.LoginLimiterDelay * 1000).ConfigureAwait(false); + await Task.Delay(ASF.GlobalConfig.LoginLimiterDelay * 1000).ConfigureAwait(false); LoginSemaphore.Release(); } ); diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index ae2c4a830..a672c0ad8 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -71,79 +71,79 @@ namespace ArchiSteamFarm { private static readonly SemaphoreSlim WriteSemaphore = new SemaphoreSlim(1, 1); [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool AcceptGifts = DefaultAcceptGifts; + public readonly bool AcceptGifts = DefaultAcceptGifts; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool AutoSteamSaleEvent = DefaultAutoSteamSaleEvent; + public readonly bool AutoSteamSaleEvent = DefaultAutoSteamSaleEvent; [JsonProperty(Required = Required.DisallowNull)] - internal readonly EBotBehaviour BotBehaviour = DefaultBotBehaviour; + public readonly EBotBehaviour BotBehaviour = DefaultBotBehaviour; [JsonProperty] - internal readonly string CustomGamePlayedWhileFarming = DefaultCustomGamePlayedWhileFarming; + public readonly string CustomGamePlayedWhileFarming = DefaultCustomGamePlayedWhileFarming; [JsonProperty] - internal readonly string CustomGamePlayedWhileIdle = DefaultCustomGamePlayedWhileIdle; + public readonly string CustomGamePlayedWhileIdle = DefaultCustomGamePlayedWhileIdle; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool Enabled = DefaultEnabled; + public readonly bool Enabled = DefaultEnabled; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableList FarmingOrders = DefaultFarmingOrders; + public readonly ImmutableList FarmingOrders = DefaultFarmingOrders; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableHashSet GamesPlayedWhileIdle = DefaultGamesPlayedWhileIdle; + public readonly ImmutableHashSet GamesPlayedWhileIdle = DefaultGamesPlayedWhileIdle; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte HoursUntilCardDrops = DefaultHoursUntilCardDrops; + public readonly byte HoursUntilCardDrops = DefaultHoursUntilCardDrops; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool IdlePriorityQueueOnly = DefaultIdlePriorityQueueOnly; + public readonly bool IdlePriorityQueueOnly = DefaultIdlePriorityQueueOnly; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool IdleRefundableGames = DefaultIdleRefundableGames; + public readonly bool IdleRefundableGames = DefaultIdleRefundableGames; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableHashSet LootableTypes = DefaultLootableTypes; + public readonly ImmutableHashSet LootableTypes = DefaultLootableTypes; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableHashSet MatchableTypes = DefaultMatchableTypes; + public readonly ImmutableHashSet MatchableTypes = DefaultMatchableTypes; [JsonProperty(Required = Required.DisallowNull)] - internal readonly EPersonaState OnlineStatus = DefaultOnlineStatus; + public readonly EPersonaState OnlineStatus = DefaultOnlineStatus; [JsonProperty(Required = Required.DisallowNull)] - internal readonly ArchiCryptoHelper.ECryptoMethod PasswordFormat = DefaultPasswordFormat; + public readonly ArchiCryptoHelper.ECryptoMethod PasswordFormat = DefaultPasswordFormat; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool Paused = DefaultPaused; + public readonly bool Paused = DefaultPaused; [JsonProperty(Required = Required.DisallowNull)] - internal readonly ERedeemingPreferences RedeemingPreferences = DefaultRedeemingPreferences; + public readonly ERedeemingPreferences RedeemingPreferences = DefaultRedeemingPreferences; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool SendOnFarmingFinished = DefaultSendOnFarmingFinished; + public readonly bool SendOnFarmingFinished = DefaultSendOnFarmingFinished; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte SendTradePeriod = DefaultSendTradePeriod; + public readonly byte SendTradePeriod = DefaultSendTradePeriod; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool ShutdownOnFarmingFinished = DefaultShutdownOnFarmingFinished; + public readonly bool ShutdownOnFarmingFinished = DefaultShutdownOnFarmingFinished; [JsonProperty] - internal readonly string SteamTradeToken = DefaultSteamTradeToken; + public readonly string SteamTradeToken = DefaultSteamTradeToken; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableDictionary SteamUserPermissions = DefaultSteamUserPermissions; + public readonly ImmutableDictionary SteamUserPermissions = DefaultSteamUserPermissions; [JsonProperty(Required = Required.DisallowNull)] - internal readonly ETradingPreferences TradingPreferences = DefaultTradingPreferences; + public readonly ETradingPreferences TradingPreferences = DefaultTradingPreferences; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableHashSet TransferableTypes = DefaultTransferableTypes; + public readonly ImmutableHashSet TransferableTypes = DefaultTransferableTypes; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool UseLoginKeys = DefaultUseLoginKeys; + public readonly bool UseLoginKeys = DefaultUseLoginKeys; [JsonExtensionData] internal Dictionary AdditionalProperties { @@ -243,6 +243,9 @@ namespace ArchiSteamFarm { } } + [JsonConstructor] + private BotConfig() { } + internal (bool Valid, string ErrorMessage) CheckValidation() { if (BotBehaviour > EBotBehaviour.All) { return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(BotBehaviour), BotBehaviour)); @@ -370,16 +373,8 @@ namespace ArchiSteamFarm { return true; } - [PublicAPI] - public enum EPermission : byte { - None, - FamilySharing, - Operator, - Master - } - [Flags] - internal enum EBotBehaviour : byte { + public enum EBotBehaviour : byte { None = 0, RejectInvalidFriendInvites = 1, RejectInvalidTrades = 2, @@ -389,7 +384,7 @@ namespace ArchiSteamFarm { All = RejectInvalidFriendInvites | RejectInvalidTrades | RejectInvalidGroupInvites | DismissInventoryNotifications | MarkReceivedMessagesAsRead } - internal enum EFarmingOrder : byte { + public enum EFarmingOrder : byte { Unordered, AppIDsAscending, AppIDsDescending, @@ -408,8 +403,15 @@ namespace ArchiSteamFarm { MarketableDescending } + public enum EPermission : byte { + None, + FamilySharing, + Operator, + Master + } + [Flags] - internal enum ERedeemingPreferences : byte { + public enum ERedeemingPreferences : byte { None = 0, Forwarding = 1, Distributing = 2, @@ -418,7 +420,7 @@ namespace ArchiSteamFarm { } [Flags] - internal enum ETradingPreferences : byte { + public enum ETradingPreferences : byte { None = 0, AcceptDonations = 1, SteamTradeMatcher = 2, diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index 3badbbc9f..fdd1662bd 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -84,12 +84,12 @@ namespace ArchiSteamFarm { internal CardsFarmer([NotNull] Bot bot) { Bot = bot ?? throw new ArgumentNullException(nameof(bot)); - if (Program.GlobalConfig.IdleFarmingPeriod > 0) { + if (ASF.GlobalConfig.IdleFarmingPeriod > 0) { IdleFarmingTimer = new Timer( async e => await CheckGamesForFarming().ConfigureAwait(false), null, - TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) + TimeSpan.FromSeconds(Program.LoadBalancingDelay * Bot.Bots.Count), // Delay - TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) // Period + TimeSpan.FromHours(ASF.GlobalConfig.IdleFarmingPeriod) + TimeSpan.FromSeconds(Program.LoadBalancingDelay * Bot.Bots.Count), // Delay + TimeSpan.FromHours(ASF.GlobalConfig.IdleFarmingPeriod) // Period ); } } @@ -396,7 +396,7 @@ namespace ArchiSteamFarm { continue; } - if (SalesBlacklist.Contains(appID) || Program.GlobalConfig.Blacklist.Contains(appID) || Bot.IsBlacklistedFromIdling(appID) || (Bot.BotConfig.IdlePriorityQueueOnly && !Bot.IsPriorityIdling(appID))) { + if (SalesBlacklist.Contains(appID) || ASF.GlobalConfig.Blacklist.Contains(appID) || Bot.IsBlacklistedFromIdling(appID) || (Bot.BotConfig.IdlePriorityQueueOnly && !Bot.IsPriorityIdling(appID))) { // We're configured to ignore this appID, so skip it continue; } @@ -616,7 +616,7 @@ namespace ArchiSteamFarm { } else { Task task = CheckGame(appID, name, hours, badgeLevel); - switch (Program.GlobalConfig.OptimizationMode) { + switch (ASF.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: await task.ConfigureAwait(false); @@ -769,14 +769,14 @@ namespace ArchiSteamFarm { await Bot.IdleGame(game).ConfigureAwait(false); bool success = true; - DateTime endFarmingDate = DateTime.UtcNow.AddHours(Program.GlobalConfig.MaxFarmingTime); + DateTime endFarmingDate = DateTime.UtcNow.AddHours(ASF.GlobalConfig.MaxFarmingTime); while ((DateTime.UtcNow < endFarmingDate) && (await ShouldFarm(game).ConfigureAwait(false)).GetValueOrDefault(true)) { Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName)); DateTime startFarmingPeriod = DateTime.UtcNow; - if (await FarmingResetSemaphore.WaitAsync(Program.GlobalConfig.FarmingDelay * 60 * 1000 + ExtraFarmingDelaySeconds * 1000).ConfigureAwait(false)) { + if (await FarmingResetSemaphore.WaitAsync(ASF.GlobalConfig.FarmingDelay * 60 * 1000 + ExtraFarmingDelaySeconds * 1000).ConfigureAwait(false)) { success = KeepFarming; } @@ -823,7 +823,7 @@ namespace ArchiSteamFarm { DateTime startFarmingPeriod = DateTime.UtcNow; - if (await FarmingResetSemaphore.WaitAsync(Program.GlobalConfig.FarmingDelay * 60 * 1000 + ExtraFarmingDelaySeconds * 1000).ConfigureAwait(false)) { + if (await FarmingResetSemaphore.WaitAsync(ASF.GlobalConfig.FarmingDelay * 60 * 1000 + ExtraFarmingDelaySeconds * 1000).ConfigureAwait(false)) { success = KeepFarming; } @@ -961,7 +961,7 @@ namespace ArchiSteamFarm { Task mainTask = CheckPage(htmlDocument); - switch (Program.GlobalConfig.OptimizationMode) { + switch (ASF.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: await mainTask.ConfigureAwait(false); diff --git a/ArchiSteamFarm/Commands.cs b/ArchiSteamFarm/Commands.cs index 22c032b4f..45e53088e 100644 --- a/ArchiSteamFarm/Commands.cs +++ b/ArchiSteamFarm/Commands.cs @@ -79,14 +79,14 @@ namespace ArchiSteamFarm { return null; } - if (useCommandPrefix && !string.IsNullOrEmpty(Program.GlobalConfig.CommandPrefix)) { - if (!message.StartsWith(Program.GlobalConfig.CommandPrefix, StringComparison.Ordinal)) { + if (useCommandPrefix && !string.IsNullOrEmpty(ASF.GlobalConfig.CommandPrefix)) { + if (!message.StartsWith(ASF.GlobalConfig.CommandPrefix, StringComparison.Ordinal)) { string pluginsResponse = await Core.OnBotMessage(Bot, steamID, message).ConfigureAwait(false); return !string.IsNullOrEmpty(pluginsResponse) ? pluginsResponse : null; } - message = message.Substring(Program.GlobalConfig.CommandPrefix.Length); + message = message.Substring(ASF.GlobalConfig.CommandPrefix.Length); } string[] args = message.Split((char[]) null, StringSplitOptions.RemoveEmptyEntries); @@ -1287,7 +1287,7 @@ namespace ArchiSteamFarm { return null; } - if (!Program.GlobalConfig.Headless) { + if (!ASF.GlobalConfig.Headless) { return FormatBotResponse(Strings.ErrorFunctionOnlyInHeadlessMode); } diff --git a/ArchiSteamFarm/Debugging.cs b/ArchiSteamFarm/Debugging.cs index 6b4f2cd7a..543834763 100644 --- a/ArchiSteamFarm/Debugging.cs +++ b/ArchiSteamFarm/Debugging.cs @@ -29,7 +29,7 @@ namespace ArchiSteamFarm { internal static bool IsDebugBuild => false; #endif - internal static bool IsUserDebugging => IsDebugBuild || Program.GlobalConfig.Debug; + internal static bool IsUserDebugging => IsDebugBuild || ASF.GlobalConfig.Debug; internal sealed class DebugListener : IDebugListener { public void WriteLine(string category, string msg) { diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index ec9c011f9..5831ab691 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -69,79 +69,79 @@ namespace ArchiSteamFarm { private static readonly SemaphoreSlim WriteSemaphore = new SemaphoreSlim(1, 1); [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool AutoRestart = DefaultAutoRestart; + public readonly bool AutoRestart = DefaultAutoRestart; [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] - internal readonly ImmutableHashSet Blacklist = DefaultBlacklist; + public readonly ImmutableHashSet Blacklist = DefaultBlacklist; [JsonProperty] - internal readonly string CommandPrefix = DefaultCommandPrefix; + public readonly string CommandPrefix = DefaultCommandPrefix; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte ConfirmationsLimiterDelay = DefaultConfirmationsLimiterDelay; + public readonly byte ConfirmationsLimiterDelay = DefaultConfirmationsLimiterDelay; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte ConnectionTimeout = DefaultConnectionTimeout; + public readonly byte ConnectionTimeout = DefaultConnectionTimeout; [JsonProperty] - internal readonly string CurrentCulture = DefaultCurrentCulture; + public readonly string CurrentCulture = DefaultCurrentCulture; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool Debug = DefaultDebug; + public readonly bool Debug = DefaultDebug; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte FarmingDelay = DefaultFarmingDelay; + public readonly byte FarmingDelay = DefaultFarmingDelay; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte GiftsLimiterDelay = DefaultGiftsLimiterDelay; + public readonly byte GiftsLimiterDelay = DefaultGiftsLimiterDelay; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool Headless = DefaultHeadless; + public readonly bool Headless = DefaultHeadless; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte IdleFarmingPeriod = DefaultIdleFarmingPeriod; + public readonly byte IdleFarmingPeriod = DefaultIdleFarmingPeriod; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte InventoryLimiterDelay = DefaultInventoryLimiterDelay; + public readonly byte InventoryLimiterDelay = DefaultInventoryLimiterDelay; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool IPC = DefaultIPC; + public readonly bool IPC = DefaultIPC; [JsonProperty] - internal readonly string IPCPassword = DefaultIPCPassword; + public readonly string IPCPassword = DefaultIPCPassword; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte LoginLimiterDelay = DefaultLoginLimiterDelay; + public readonly byte LoginLimiterDelay = DefaultLoginLimiterDelay; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte MaxFarmingTime = DefaultMaxFarmingTime; + public readonly byte MaxFarmingTime = DefaultMaxFarmingTime; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte MaxTradeHoldDuration = DefaultMaxTradeHoldDuration; + public readonly byte MaxTradeHoldDuration = DefaultMaxTradeHoldDuration; [JsonProperty(Required = Required.DisallowNull)] - internal readonly EOptimizationMode OptimizationMode = DefaultOptimizationMode; + public readonly EOptimizationMode OptimizationMode = DefaultOptimizationMode; [JsonProperty(Required = Required.DisallowNull)] - internal readonly bool Statistics = DefaultStatistics; + public readonly bool Statistics = DefaultStatistics; [JsonProperty] - internal readonly string SteamMessagePrefix = DefaultSteamMessagePrefix; + public readonly string SteamMessagePrefix = DefaultSteamMessagePrefix; [JsonProperty(Required = Required.DisallowNull)] - internal readonly EUpdateChannel UpdateChannel = DefaultUpdateChannel; + public readonly EUpdateChannel UpdateChannel = DefaultUpdateChannel; [JsonProperty(Required = Required.DisallowNull)] - internal readonly byte UpdatePeriod = DefaultUpdatePeriod; + public readonly byte UpdatePeriod = DefaultUpdatePeriod; [JsonProperty(Required = Required.DisallowNull)] - internal readonly ushort WebLimiterDelay = DefaultWebLimiterDelay; + public readonly ushort WebLimiterDelay = DefaultWebLimiterDelay; [JsonProperty(PropertyName = nameof(WebProxy))] - internal readonly string WebProxyText = DefaultWebProxyText; + public readonly string WebProxyText = DefaultWebProxyText; [JsonProperty] - internal readonly string WebProxyUsername = DefaultWebProxyUsername; + public readonly string WebProxyUsername = DefaultWebProxyUsername; internal WebProxy WebProxy { get { @@ -187,7 +187,6 @@ namespace ArchiSteamFarm { } [JsonExtensionData] - [PublicAPI] internal Dictionary AdditionalProperties { get; [UsedImplicitly] @@ -234,6 +233,9 @@ namespace ArchiSteamFarm { } } + [JsonConstructor] + private GlobalConfig() { } + internal (bool Valid, string ErrorMessage) CheckValidation() { if (ConnectionTimeout == 0) { return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(ConnectionTimeout), ConnectionTimeout)); @@ -342,15 +344,16 @@ namespace ArchiSteamFarm { return true; } - internal enum EOptimizationMode : byte { + public enum EOptimizationMode : byte { MaxPerformance, MinMemoryUsage } - [PublicAPI] - internal enum EUpdateChannel : byte { + public enum EUpdateChannel : byte { None, Stable, + + [PublicAPI] Experimental } diff --git a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs index 54202e8c8..8d3c5ce27 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs @@ -38,7 +38,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { public ActionResult> ASFGet() { uint memoryUsage = (uint) GC.GetTotalMemory(false) / 1024; - ASFResponse result = new ASFResponse(SharedInfo.BuildInfo.Variant, Program.GlobalConfig, memoryUsage, RuntimeCompatibility.ProcessStartTime, SharedInfo.Version); + ASFResponse result = new ASFResponse(SharedInfo.BuildInfo.Variant, ASF.GlobalConfig, memoryUsage, RuntimeCompatibility.ProcessStartTime, SharedInfo.Version); return Ok(new GenericResponse(result)); } @@ -62,8 +62,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, errorMessage)); } - if (!request.GlobalConfig.IsWebProxyPasswordSet && Program.GlobalConfig.IsWebProxyPasswordSet) { - request.GlobalConfig.WebProxyPassword = Program.GlobalConfig.WebProxyPassword; + if (!request.GlobalConfig.IsWebProxyPasswordSet && ASF.GlobalConfig.IsWebProxyPasswordSet) { + request.GlobalConfig.WebProxyPassword = ASF.GlobalConfig.WebProxyPassword; } request.GlobalConfig.ShouldSerializeEverything = false; diff --git a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs index ec2dde7ad..a6854a1fd 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs @@ -45,8 +45,8 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(command)))); } - if (Program.GlobalConfig.SteamOwnerID == 0) { - return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(Program.GlobalConfig.SteamOwnerID)))); + if (ASF.GlobalConfig.SteamOwnerID == 0) { + return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsInvalid, nameof(ASF.GlobalConfig.SteamOwnerID)))); } Bot targetBot = Bot.Bots.OrderBy(bot => bot.Key).Select(bot => bot.Value).FirstOrDefault(); @@ -55,11 +55,11 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, Strings.ErrorNoBotsDefined)); } - if (!string.IsNullOrEmpty(Program.GlobalConfig.CommandPrefix) && command.StartsWith(Program.GlobalConfig.CommandPrefix, StringComparison.Ordinal)) { - command = command.Substring(Program.GlobalConfig.CommandPrefix.Length); + if (!string.IsNullOrEmpty(ASF.GlobalConfig.CommandPrefix) && command.StartsWith(ASF.GlobalConfig.CommandPrefix, StringComparison.Ordinal)) { + command = command.Substring(ASF.GlobalConfig.CommandPrefix.Length); } - string response = await targetBot.Commands.Response(Program.GlobalConfig.SteamOwnerID, command, false).ConfigureAwait(false); + string response = await targetBot.Commands.Response(ASF.GlobalConfig.SteamOwnerID, command, false).ConfigureAwait(false); return Ok(new GenericResponse(response)); } diff --git a/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs b/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs index 5030a2006..d3c658a28 100644 --- a/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs +++ b/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs @@ -80,7 +80,7 @@ namespace ArchiSteamFarm.IPC.Middleware { return HttpStatusCode.InternalServerError; } - if (string.IsNullOrEmpty(Program.GlobalConfig.IPCPassword)) { + if (string.IsNullOrEmpty(ASF.GlobalConfig.IPCPassword)) { return HttpStatusCode.OK; } @@ -96,7 +96,7 @@ namespace ArchiSteamFarm.IPC.Middleware { return HttpStatusCode.Unauthorized; } - bool authorized = passwords.First() == Program.GlobalConfig.IPCPassword; + bool authorized = passwords.First() == ASF.GlobalConfig.IPCPassword; await AuthorizationSemaphore.WaitAsync().ConfigureAwait(false); diff --git a/ArchiSteamFarm/IPC/Startup.cs b/ArchiSteamFarm/IPC/Startup.cs index 1266d5e91..841e54ecf 100644 --- a/ArchiSteamFarm/IPC/Startup.cs +++ b/ArchiSteamFarm/IPC/Startup.cs @@ -58,7 +58,7 @@ namespace ArchiSteamFarm.IPC { // Add support for response compression app.UseResponseCompression(); - if (!string.IsNullOrEmpty(Program.GlobalConfig.IPCPassword)) { + if (!string.IsNullOrEmpty(ASF.GlobalConfig.IPCPassword)) { // We need ApiAuthenticationMiddleware for IPCPassword app.UseWhen(context => context.Request.Path.StartsWithSegments("/Api", StringComparison.OrdinalIgnoreCase), appBuilder => appBuilder.UseMiddleware()); diff --git a/ArchiSteamFarm/MobileAuthenticator.cs b/ArchiSteamFarm/MobileAuthenticator.cs index 7a53f076c..87bccb035 100644 --- a/ArchiSteamFarm/MobileAuthenticator.cs +++ b/ArchiSteamFarm/MobileAuthenticator.cs @@ -436,7 +436,7 @@ namespace ArchiSteamFarm { } private static async Task LimitConfirmationsRequestsAsync() { - if (Program.GlobalConfig.ConfirmationsLimiterDelay == 0) { + if (ASF.GlobalConfig.ConfirmationsLimiterDelay == 0) { return; } @@ -444,7 +444,7 @@ namespace ArchiSteamFarm { Utilities.InBackground( async () => { - await Task.Delay(Program.GlobalConfig.ConfirmationsLimiterDelay * 1000).ConfigureAwait(false); + await Task.Delay(ASF.GlobalConfig.ConfirmationsLimiterDelay * 1000).ConfigureAwait(false); ConfirmationsSemaphore.Release(); } ); diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 760520628..174a32e0b 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -38,9 +38,8 @@ using SteamKit2; namespace ArchiSteamFarm { internal static class Program { - internal static byte LoadBalancingDelay => Math.Max(GlobalConfig?.LoginLimiterDelay ?? 0, (byte) 10); + internal static byte LoadBalancingDelay => Math.Max(ASF.GlobalConfig?.LoginLimiterDelay ?? 0, (byte) 10); - internal static GlobalConfig GlobalConfig { get; private set; } internal static GlobalDatabase GlobalDatabase { get; private set; } internal static bool ProcessRequired { get; private set; } internal static bool RestartAllowed { get; private set; } = true; @@ -69,7 +68,7 @@ namespace ArchiSteamFarm { return null; } - if (GlobalConfig.Headless) { + if (ASF.GlobalConfig.Headless) { ASF.ArchiLogger.LogGenericWarning(Strings.ErrorUserInputRunningInHeadlessMode); return null; @@ -211,7 +210,7 @@ namespace ArchiSteamFarm { ParsePostInitArgs(args); } - OS.Init(SystemRequired, GlobalConfig.OptimizationMode); + OS.Init(SystemRequired, ASF.GlobalConfig.OptimizationMode); await InitGlobalDatabaseAndServices().ConfigureAwait(false); await ASF.Init().ConfigureAwait(false); @@ -248,10 +247,12 @@ namespace ArchiSteamFarm { private static async Task InitGlobalConfigAndLanguage() { string globalConfigFile = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName); - if (File.Exists(globalConfigFile)) { - GlobalConfig = await GlobalConfig.Load(globalConfigFile).ConfigureAwait(false); + GlobalConfig globalConfig; - if (GlobalConfig == null) { + if (File.Exists(globalConfigFile)) { + globalConfig = await GlobalConfig.Load(globalConfigFile).ConfigureAwait(false); + + if (globalConfig == null) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorGlobalConfigNotLoaded, globalConfigFile)); await Task.Delay(5 * 1000).ConfigureAwait(false); await Exit(1).ConfigureAwait(false); @@ -259,17 +260,19 @@ namespace ArchiSteamFarm { return; } } else { - GlobalConfig = GlobalConfig.Create(); + globalConfig = GlobalConfig.Create(); } + ASF.InitGlobalConfig(globalConfig); + if (Debugging.IsUserDebugging) { - ASF.ArchiLogger.LogGenericDebug(SharedInfo.GlobalConfigFileName + ": " + JsonConvert.SerializeObject(GlobalConfig, Formatting.Indented)); + ASF.ArchiLogger.LogGenericDebug(SharedInfo.GlobalConfigFileName + ": " + JsonConvert.SerializeObject(ASF.GlobalConfig, Formatting.Indented)); } - if (!string.IsNullOrEmpty(GlobalConfig.CurrentCulture)) { + if (!string.IsNullOrEmpty(ASF.GlobalConfig.CurrentCulture)) { try { // GetCultureInfo() would be better but we can't use it for specifying neutral cultures such as "en" - CultureInfo culture = CultureInfo.CreateSpecificCulture(GlobalConfig.CurrentCulture); + CultureInfo culture = CultureInfo.CreateSpecificCulture(ASF.GlobalConfig.CurrentCulture); CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = culture; } catch (Exception) { ASF.ArchiLogger.LogGenericError(Strings.ErrorInvalidCurrentCulture); diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index ecc3148da..c8b3bd745 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -45,6 +45,109 @@ namespace ArchiSteamFarm { public void Dispose() => TradesSemaphore.Dispose(); + [PublicAPI] + public static bool IsTradeNeutralOrBetter(HashSet inventory, IReadOnlyCollection itemsToGive, IReadOnlyCollection itemsToReceive) { + if ((inventory == null) || (inventory.Count == 0) || (itemsToGive == null) || (itemsToGive.Count == 0) || (itemsToReceive == null) || (itemsToReceive.Count == 0)) { + ASF.ArchiLogger.LogNullError(nameof(inventory) + " || " + nameof(itemsToGive) + " || " + nameof(itemsToReceive)); + + return false; + } + + // Input of this function is items we're expected to give/receive and our inventory (limited to realAppIDs of itemsToGive/itemsToReceive) + // The objective is to determine whether the new state is beneficial (or at least neutral) towards us + // There are a lot of factors involved here - different realAppIDs, different item types, possibility of user overpaying and more + // All of those cases should be verified by our unit tests to ensure that the logic here matches all possible cases, especially those that were incorrectly handled previously + + // Firstly we get initial sets state of our inventory + Dictionary<(uint AppID, Steam.Asset.EType Type), List> initialSets = GetInventorySets(inventory); + + // Once we have initial state, we remove items that we're supposed to give from our inventory + // This loop is a bit more complex due to the fact that we might have a mix of the same item splitted into different amounts + foreach (Steam.Asset itemToGive in itemsToGive) { + uint amountToGive = itemToGive.Amount; + HashSet itemsToRemove = new HashSet(); + + // Keep in mind that ClassID is unique only within appID scope - we can do it like this because we're not dealing with non-Steam items here (otherwise we'd need to check appID too) + foreach (Steam.Asset item in inventory.Where(item => item.ClassID == itemToGive.ClassID)) { + if (amountToGive >= item.Amount) { + itemsToRemove.Add(item); + amountToGive -= item.Amount; + } else { + item.Amount -= amountToGive; + amountToGive = 0; + } + + if (amountToGive == 0) { + break; + } + } + + if (amountToGive > 0) { + ASF.ArchiLogger.LogNullError(nameof(amountToGive)); + + return false; + } + + if (itemsToRemove.Count > 0) { + inventory.ExceptWith(itemsToRemove); + } + } + + // Now we can add items that we're supposed to receive, this one doesn't require advanced amounts logic since we can just add items regardless + foreach (Steam.Asset itemToReceive in itemsToReceive) { + inventory.Add(itemToReceive); + } + + // Now we can get final sets state of our inventory after the exchange + Dictionary<(uint AppID, Steam.Asset.EType Type), List> finalSets = GetInventorySets(inventory); + + // Once we have both states, we can check overall fairness + foreach (((uint AppID, Steam.Asset.EType Type) set, List afterAmounts) in finalSets) { + List beforeAmounts = initialSets[set]; + + // If amount of unique items in the set decreases, this is always a bad trade (e.g. 1 1 -> 0 2) + if (afterAmounts.Count < beforeAmounts.Count) { + return false; + } + + // If amount of unique items in the set increases, this is always a good trade (e.g. 0 2 -> 1 1) + if (afterAmounts.Count > beforeAmounts.Count) { + continue; + } + + // At this point we're sure that amount of unique items stays the same, so we can evaluate actual sets + // We make use of the fact that our amounts are already sorted in ascending order, so we can just take the first value instead of calculating ourselves + uint beforeSets = beforeAmounts[0]; + uint afterSets = afterAmounts[0]; + + // If amount of our sets for this game decreases, this is always a bad trade (e.g. 2 2 2 -> 3 2 1) + if (afterSets < beforeSets) { + return false; + } + + // If amount of our sets for this game increases, this is always a good trade (e.g. 3 2 1 -> 2 2 2) + if (afterSets > beforeSets) { + continue; + } + + // At this point we're sure that both number of unique items in the set stays the same, as well as number of our actual sets + // We need to ensure set progress here and keep in mind overpaying, so we'll calculate neutrality as a difference in amounts at appropriate indexes + // Neutrality can't reach value below 0 at any single point of calculation, as that would imply a loss of progress even if we'd end up with a positive value by the end + int neutrality = 0; + + for (byte i = 0; i < afterAmounts.Count; i++) { + neutrality += (int) (afterAmounts[i] - beforeAmounts[i]); + + if (neutrality < 0) { + return false; + } + } + } + + // If we didn't find any reason above to reject this trade, it's at least neutral+ for us - it increases our progress towards badge completion + return true; + } + internal static (Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary> FullState, Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary> TradableState) GetDividedInventoryState(IReadOnlyCollection inventory) { if ((inventory == null) || (inventory.Count == 0)) { ASF.ArchiLogger.LogNullError(nameof(inventory)); @@ -296,108 +399,6 @@ namespace ArchiSteamFarm { return sets.ToDictionary(set => set.Key, set => set.Value.Values.OrderBy(amount => amount).ToList()); } - private static bool IsTradeNeutralOrBetter(HashSet inventory, IReadOnlyCollection itemsToGive, IReadOnlyCollection itemsToReceive) { - if ((inventory == null) || (inventory.Count == 0) || (itemsToGive == null) || (itemsToGive.Count == 0) || (itemsToReceive == null) || (itemsToReceive.Count == 0)) { - ASF.ArchiLogger.LogNullError(nameof(inventory) + " || " + nameof(itemsToGive) + " || " + nameof(itemsToReceive)); - - return false; - } - - // Input of this function is items we're expected to give/receive and our inventory (limited to realAppIDs of itemsToGive/itemsToReceive) - // The objective is to determine whether the new state is beneficial (or at least neutral) towards us - // There are a lot of factors involved here - different realAppIDs, different item types, possibility of user overpaying and more - // All of those cases should be verified by our unit tests to ensure that the logic here matches all possible cases, especially those that were incorrectly handled previously - - // Firstly we get initial sets state of our inventory - Dictionary<(uint AppID, Steam.Asset.EType Type), List> initialSets = GetInventorySets(inventory); - - // Once we have initial state, we remove items that we're supposed to give from our inventory - // This loop is a bit more complex due to the fact that we might have a mix of the same item splitted into different amounts - foreach (Steam.Asset itemToGive in itemsToGive) { - uint amountToGive = itemToGive.Amount; - HashSet itemsToRemove = new HashSet(); - - // Keep in mind that ClassID is unique only within appID scope - we can do it like this because we're not dealing with non-Steam items here (otherwise we'd need to check appID too) - foreach (Steam.Asset item in inventory.Where(item => item.ClassID == itemToGive.ClassID)) { - if (amountToGive >= item.Amount) { - itemsToRemove.Add(item); - amountToGive -= item.Amount; - } else { - item.Amount -= amountToGive; - amountToGive = 0; - } - - if (amountToGive == 0) { - break; - } - } - - if (amountToGive > 0) { - ASF.ArchiLogger.LogNullError(nameof(amountToGive)); - - return false; - } - - if (itemsToRemove.Count > 0) { - inventory.ExceptWith(itemsToRemove); - } - } - - // Now we can add items that we're supposed to receive, this one doesn't require advanced amounts logic since we can just add items regardless - foreach (Steam.Asset itemToReceive in itemsToReceive) { - inventory.Add(itemToReceive); - } - - // Now we can get final sets state of our inventory after the exchange - Dictionary<(uint AppID, Steam.Asset.EType Type), List> finalSets = GetInventorySets(inventory); - - // Once we have both states, we can check overall fairness - foreach (((uint AppID, Steam.Asset.EType Type) set, List afterAmounts) in finalSets) { - List beforeAmounts = initialSets[set]; - - // If amount of unique items in the set decreases, this is always a bad trade (e.g. 1 1 -> 0 2) - if (afterAmounts.Count < beforeAmounts.Count) { - return false; - } - - // If amount of unique items in the set increases, this is always a good trade (e.g. 0 2 -> 1 1) - if (afterAmounts.Count > beforeAmounts.Count) { - continue; - } - - // At this point we're sure that amount of unique items stays the same, so we can evaluate actual sets - // We make use of the fact that our amounts are already sorted in ascending order, so we can just take the first value instead of calculating ourselves - uint beforeSets = beforeAmounts[0]; - uint afterSets = afterAmounts[0]; - - // If amount of our sets for this game decreases, this is always a bad trade (e.g. 2 2 2 -> 3 2 1) - if (afterSets < beforeSets) { - return false; - } - - // If amount of our sets for this game increases, this is always a good trade (e.g. 3 2 1 -> 2 2 2) - if (afterSets > beforeSets) { - continue; - } - - // At this point we're sure that both number of unique items in the set stays the same, as well as number of our actual sets - // We need to ensure set progress here and keep in mind overpaying, so we'll calculate neutrality as a difference in amounts at appropriate indexes - // Neutrality can't reach value below 0 at any single point of calculation, as that would imply a loss of progress even if we'd end up with a positive value by the end - int neutrality = 0; - - for (byte i = 0; i < afterAmounts.Count; i++) { - neutrality += (int) (afterAmounts[i] - beforeAmounts[i]); - - if (neutrality < 0) { - return false; - } - } - } - - // If we didn't find any reason above to reject this trade, it's at least neutral+ for us - it increases our progress towards badge completion - return true; - } - private async Task ParseActiveTrades() { HashSet tradeOffers = await Bot.ArchiWebHandler.GetActiveTradeOffers().ConfigureAwait(false); @@ -592,7 +593,7 @@ namespace ArchiSteamFarm { // If user has a trade hold, we add extra logic if (holdDuration.Value > 0) { // If trade hold duration exceeds our max, or user asks for cards with short lifespan, reject the trade - if ((holdDuration.Value > Program.GlobalConfig.MaxTradeHoldDuration) || tradeOffer.ItemsToGive.Any(item => ((item.Type == Steam.Asset.EType.FoilTradingCard) || (item.Type == Steam.Asset.EType.TradingCard)) && CardsFarmer.SalesBlacklist.Contains(item.RealAppID))) { + if ((holdDuration.Value > ASF.GlobalConfig.MaxTradeHoldDuration) || tradeOffer.ItemsToGive.Any(item => ((item.Type == Steam.Asset.EType.FoilTradingCard) || (item.Type == Steam.Asset.EType.TradingCard)) && CardsFarmer.SalesBlacklist.Contains(item.RealAppID))) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, tradeOffer.ItemsToReceive); } } diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index d9b453572..76972e4d5 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -84,7 +84,7 @@ namespace ArchiSteamFarm { IList results; - switch (Program.GlobalConfig.OptimizationMode) { + switch (ASF.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: results = new List(); @@ -110,7 +110,7 @@ namespace ArchiSteamFarm { return; } - switch (Program.GlobalConfig.OptimizationMode) { + switch (ASF.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: foreach (Task task in tasks) { diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index d50767bf5..70025e9b2 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -278,7 +278,7 @@ namespace ArchiSteamFarm { [NotNull] internal HttpClient GenerateDisposableHttpClient(bool extendedTimeout = false) { HttpClient result = new HttpClient(HttpClientHandler) { - Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * Program.GlobalConfig.ConnectionTimeout : Program.GlobalConfig.ConnectionTimeout) + Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * ASF.GlobalConfig.ConnectionTimeout : ASF.GlobalConfig.ConnectionTimeout) }; // Most web services expect that UserAgent is set, so we declare it globally