From 292ec97b1c9acdaeca240900d1cb5251e67590fe Mon Sep 17 00:00:00 2001 From: JustArchi Date: Sun, 6 Mar 2016 23:28:56 +0100 Subject: [PATCH] Work on GlobalConfig, #131 --- ArchiSteamFarm/ArchiSteamFarm.csproj | 4 ++ ArchiSteamFarm/ArchiWebHandler.cs | 6 +- ArchiSteamFarm/BotConfig.cs | 2 - ArchiSteamFarm/CardsFarmer.cs | 2 +- ArchiSteamFarm/GlobalConfig.cs | 83 ++++++++++++++++++++++++++++ ArchiSteamFarm/Logging.cs | 14 ++--- ArchiSteamFarm/Program.cs | 35 ++++++++---- ArchiSteamFarm/Trading.cs | 2 +- ArchiSteamFarm/WCF.cs | 6 +- ArchiSteamFarm/WebBrowser.cs | 13 +++-- 10 files changed, 138 insertions(+), 29 deletions(-) create mode 100644 ArchiSteamFarm/GlobalConfig.cs diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj index 8ee1f151f..1aad44939 100644 --- a/ArchiSteamFarm/ArchiSteamFarm.csproj +++ b/ArchiSteamFarm/ArchiSteamFarm.csproj @@ -106,6 +106,7 @@ + @@ -120,6 +121,9 @@ + + PreserveNewest + PreserveNewest diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 57b8f7646..526bf2972 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -34,13 +34,17 @@ using System.Threading.Tasks; namespace ArchiSteamFarm { internal sealed class ArchiWebHandler { - private const int Timeout = 1000 * WebBrowser.HttpTimeout; // In miliseconds + private static int Timeout; private readonly Bot Bot; private readonly Dictionary Cookie = new Dictionary(4); private ulong SteamID; + internal static void Init() { + Timeout = Program.GlobalConfig.HttpTimeout * 1000; + } + internal ArchiWebHandler(Bot bot) { Bot = bot; } diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index a0eaa9c84..e2f6d7af5 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -30,8 +30,6 @@ using System.Xml; namespace ArchiSteamFarm { internal sealed class BotConfig { - internal static readonly HashSet GlobalBlacklist = new HashSet { 303700, 335590, 368020, 425280 }; - [JsonProperty(Required = Required.DisallowNull)] internal bool Enabled { get; private set; } = false; diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index b0d25ecb4..1c07b9dab 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -329,7 +329,7 @@ namespace ArchiSteamFarm { continue; } - if (BotConfig.GlobalBlacklist.Contains(appID)) { + if (GlobalConfig.GlobalBlacklist.Contains(appID) || Program.GlobalConfig.Blacklist.Contains(appID)) { continue; } diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs new file mode 100644 index 000000000..fd1148bc4 --- /dev/null +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -0,0 +1,83 @@ +/* + _ _ _ ____ _ _____ + / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ + / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ + / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| + + 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 Newtonsoft.Json; +using SteamAuth; +using System; +using System.Collections.Generic; +using System.IO; + +namespace ArchiSteamFarm { + internal sealed class GlobalConfig { + internal enum EUpdateChannel : byte { + Unknown, + Stable, + Experimental + } + + // This is hardcoded blacklist which should not be possible to change + internal static readonly HashSet GlobalBlacklist = new HashSet { 303700, 335590, 368020, 425280 }; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool AutoUpdates { get; private set; } = true; + + [JsonProperty(Required = Required.DisallowNull)] + internal EUpdateChannel UpdateChannel { get; private set; } = GlobalConfig.EUpdateChannel.Stable; + + [JsonProperty(Required = Required.DisallowNull)] + internal byte HttpTimeout { get; private set; } = 30; + + [JsonProperty(Required = Required.DisallowNull)] + internal byte RequestLimiterDelay { get; private set; } = 7; + + [JsonProperty(Required = Required.DisallowNull)] + internal string WCFHostname { get; private set; } = "localhost"; + + [JsonProperty(Required = Required.DisallowNull)] + internal ushort WCFPort { get; private set; } = 1242; + + [JsonProperty(Required = Required.DisallowNull)] + internal HashSet Blacklist { get; private set; } = new HashSet(GlobalBlacklist); + + internal static GlobalConfig Load() { + string filePath = Path.Combine(Program.ConfigDirectory, Program.GlobalConfigFile); + if (!File.Exists(filePath)) { + return null; + } + + GlobalConfig globalConfig; + try { + globalConfig = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + } catch (Exception e) { + Logging.LogGenericException(e); + return null; + } + + return globalConfig; + } + + // This constructor is used only by deserializer + private GlobalConfig() { } + } +} diff --git a/ArchiSteamFarm/Logging.cs b/ArchiSteamFarm/Logging.cs index d69eeece7..6ab73c278 100644 --- a/ArchiSteamFarm/Logging.cs +++ b/ArchiSteamFarm/Logging.cs @@ -31,17 +31,18 @@ namespace ArchiSteamFarm { internal static class Logging { private static readonly object FileLock = new object(); - internal static bool LogToFile { get; set; } = false; + internal static bool? LogToFile { get; set; } = null; internal static void Init() { + if (!LogToFile.HasValue) { + LogToFile = true; + } + lock (FileLock) { try { File.Delete(Program.LogFile); } catch (Exception e) { - bool logToFile = LogToFile; - LogToFile = false; LogGenericException(e); - LogToFile = logToFile; } } } @@ -121,15 +122,14 @@ namespace ArchiSteamFarm { Console.Write(loggedMessage); } - if (LogToFile) { + if (LogToFile.GetValueOrDefault()) { lock (FileLock) { try { File.AppendAllText(Program.LogFile, loggedMessage); } catch (Exception e) { - bool logToFile = LogToFile; LogToFile = false; LogGenericException(e); - LogToFile = logToFile; + LogToFile = true; } } } diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 70f36cc48..f07ce9357 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -51,6 +51,7 @@ namespace ArchiSteamFarm { private const string LatestGithubReleaseURL = "https://api.github.com/repos/JustArchi/ArchiSteamFarm/releases/latest"; internal const string ConfigDirectory = "config"; internal const string LogFile = "log.txt"; + internal const string GlobalConfigFile = "ASF.json"; private static readonly object ConsoleLock = new object(); private static readonly SemaphoreSlim SteamSemaphore = new SemaphoreSlim(1); @@ -62,10 +63,11 @@ namespace ArchiSteamFarm { internal static readonly string Version = Assembly.GetName().Version.ToString(); - private static EMode Mode; - + internal static GlobalConfig GlobalConfig { get; private set; } internal static bool ConsoleIsBusy { get; private set; } = false; + private static EMode Mode = EMode.Normal; + private static async Task CheckForUpdate() { JObject response = await WebBrowser.UrlGetToJObject(LatestGithubReleaseURL).ConfigureAwait(false); if (response == null) { @@ -105,7 +107,7 @@ namespace ArchiSteamFarm { internal static async Task LimitSteamRequestsAsync() { await SteamSemaphore.WaitAsync().ConfigureAwait(false); Task.Run(async () => { - await Utilities.SleepAsync(7000).ConfigureAwait(false); // We must add some delay to not get caught by Steam rate limiter + await Utilities.SleepAsync(GlobalConfig.RequestLimiterDelay * 1000).ConfigureAwait(false); SteamSemaphore.Release(); }).Forget(); } @@ -166,8 +168,16 @@ namespace ArchiSteamFarm { } private static void InitServices() { - Logging.Init(); + GlobalConfig = GlobalConfig.Load(); + if (GlobalConfig == null) { + Logging.LogGenericError("Global config could not be loaded, please make sure that ASF.db exists and is valid!"); + Thread.Sleep(5000); + Exit(1); + } + + ArchiWebHandler.Init(); WebBrowser.Init(); + WCF.Init(); } private static void ParseArgs(string[] args) { @@ -244,11 +254,7 @@ namespace ArchiSteamFarm { } } - // By default we're operating on normal mode - Mode = EMode.Normal; - Logging.LogToFile = true; - - // But that can be overriden by arguments + // Parse args ParseArgs(args); // If we ran ASF as a client, we're done by now @@ -256,7 +262,8 @@ namespace ArchiSteamFarm { return; } - Task.Run(async () => await CheckForUpdate().ConfigureAwait(false)).Wait(); + // From now on it's server mode + Logging.Init(); if (!Directory.Exists(ConfigDirectory)) { Logging.LogGenericError("Config directory doesn't exist!"); @@ -264,11 +271,19 @@ namespace ArchiSteamFarm { Exit(1); } + Task.Run(async () => await CheckForUpdate().ConfigureAwait(false)).Wait(); + // Before attempting to connect, initialize our list of CMs Bot.RefreshCMs().Wait(); + string globalConfigName = GlobalConfigFile.Substring(0, GlobalConfigFile.LastIndexOf('.')); + foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.json")) { string botName = Path.GetFileNameWithoutExtension(configFile); + if (botName.Equals(globalConfigName)) { + continue; + } + Bot bot = new Bot(botName); if (!bot.BotConfig.Enabled) { Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName); diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index fcd9bb2ec..f5b74b4a5 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -40,7 +40,7 @@ namespace ArchiSteamFarm { internal static async Task LimitInventoryRequestsAsync() { await InventorySemaphore.WaitAsync().ConfigureAwait(false); Task.Run(async () => { - await Utilities.SleepAsync(3000).ConfigureAwait(false); // We must add some delay to not get caught by Steam rate limiter + await Utilities.SleepAsync(Program.GlobalConfig.RequestLimiterDelay * 1000).ConfigureAwait(false); InventorySemaphore.Release(); }).Forget(); } diff --git a/ArchiSteamFarm/WCF.cs b/ArchiSteamFarm/WCF.cs index 9ef7073dd..dd2c360de 100644 --- a/ArchiSteamFarm/WCF.cs +++ b/ArchiSteamFarm/WCF.cs @@ -35,11 +35,15 @@ namespace ArchiSteamFarm { internal sealed class WCF : IWCF { - private const string URL = "http://localhost:1242/ASF"; // 1242 = 1024 + A(65) + S(83) + F(70) + private static string URL = "http://localhost:1242/ASF"; // 1242 = 1024 + A(65) + S(83) + F(70) private ServiceHost ServiceHost; private Client Client; + internal static void Init() { + URL = "http://" + Program.GlobalConfig.WCFHostname + ":" + Program.GlobalConfig.WCFPort + "/ASF"; + } + internal bool IsServerRunning() { return ServiceHost != null; } diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index 7e4892952..993966955 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -33,19 +33,20 @@ using System.Threading.Tasks; namespace ArchiSteamFarm { internal static class WebBrowser { - internal const byte HttpTimeout = 180; // In seconds, how long we can wait for server's response internal const byte MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state internal const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it internal const byte MaxRetries = 5; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility) private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version; - private static readonly HttpClient HttpClient = new HttpClient(new HttpClientHandler { - UseCookies = false - }) { - Timeout = TimeSpan.FromSeconds(HttpTimeout) - }; + private static HttpClient HttpClient; internal static void Init() { + HttpClient = new HttpClient(new HttpClientHandler { + UseCookies = false + }) { + Timeout = TimeSpan.FromSeconds(Program.GlobalConfig.HttpTimeout) + }; + // Most web services expect that UserAgent is set, so we declare it globally // Any request can override that on as-needed basis (see: RequestOptions.FakeUserAgent) HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(DefaultUserAgent);