From 4f01dc39fc05f1c9e680c65d61d3606ed7a80899 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Mon, 25 Jul 2016 06:08:45 +0200 Subject: [PATCH] Code review --- ArchiSteamFarm/ArchiWebHandler.cs | 4 +- ArchiSteamFarm/Bot.cs | 3 +- ArchiSteamFarm/BotConfig.cs | 50 ++++++++++++---------- ArchiSteamFarm/ConcurrentHashSet.cs | 2 +- ArchiSteamFarm/GlobalConfig.cs | 60 +++++++++++++-------------- ArchiSteamFarm/GlobalDatabase.cs | 2 +- ArchiSteamFarm/JSON/GitHub.cs | 8 ++-- ArchiSteamFarm/JSON/Steam.cs | 25 ++++------- ArchiSteamFarm/MobileAuthenticator.cs | 10 ++--- ArchiSteamFarm/Program.cs | 46 ++++++++++---------- ArchiSteamFarm/Runtime.cs | 19 ++++----- ArchiSteamFarm/WebBrowser.cs | 19 ++++----- ConfigGenerator/ASFConfig.cs | 8 ++-- ConfigGenerator/Program.cs | 52 ++++++++++++----------- 14 files changed, 150 insertions(+), 158 deletions(-) diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 3ed02c567..4f4783895 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -38,10 +38,10 @@ using ArchiSteamFarm.JSON; namespace ArchiSteamFarm { internal sealed class ArchiWebHandler : IDisposable { private const string SteamCommunityHost = "steamcommunity.com"; - private const byte MinSessionTTL = 15; // Assume session is valid for at least that amount of seconds + private const byte MinSessionTTL = GlobalConfig.DefaultHttpTimeout / 4; // Assume session is valid for at least that amount of seconds private static string SteamCommunityURL = "https://" + SteamCommunityHost; - private static int Timeout = GlobalConfig.DefaultHttpTimeout * 1000; + private static int Timeout = GlobalConfig.DefaultHttpTimeout * 1000; // This must be int type private readonly Bot Bot; private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1); diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index e65664d08..bb0589409 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -26,6 +26,7 @@ using Newtonsoft.Json; using SteamKit2; using SteamKit2.Internal; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -43,7 +44,7 @@ namespace ArchiSteamFarm { private const ushort CallbackSleep = 500; // In miliseconds private const ushort MaxSteamMessageLength = 2048; - internal static readonly Dictionary Bots = new Dictionary(); + internal static readonly ConcurrentDictionary Bots = new ConcurrentDictionary(); private static readonly uint LoginID = MsgClientLogon.ObfuscationMask; // This must be the same for all ASF bots and all ASF processes private static readonly SemaphoreSlim GiftsSemaphore = new SemaphoreSlim(1); diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index c6c21c27b..eee136b67 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -32,12 +32,13 @@ using System.Linq; namespace ArchiSteamFarm { [SuppressMessage("ReSharper", "ClassCannotBeInstantiated")] [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + [SuppressMessage("ReSharper", "ConvertToConstant.Global")] internal sealed class BotConfig { [JsonProperty(Required = Required.DisallowNull)] - internal bool Enabled { get; private set; } = false; + internal readonly bool Enabled = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool StartOnLaunch { get; private set; } = true; + internal readonly bool StartOnLaunch = true; [JsonProperty] internal string SteamLogin { get; set; } @@ -53,64 +54,64 @@ namespace ArchiSteamFarm { internal string SteamParentalPIN { get; set; } = "0"; [JsonProperty] - internal string SteamApiKey { get; private set; } = null; + internal readonly string SteamApiKey = null; [JsonProperty(Required = Required.DisallowNull)] - internal ulong SteamMasterID { get; private set; } = 0; + internal readonly ulong SteamMasterID = 0; [JsonProperty(Required = Required.DisallowNull)] - internal ulong SteamMasterClanID { get; private set; } = 0; + internal readonly ulong SteamMasterClanID = 0; [JsonProperty(Required = Required.DisallowNull)] - internal bool CardDropsRestricted { get; private set; } = false; + internal readonly bool CardDropsRestricted = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool DismissInventoryNotifications { get; private set; } = true; + internal readonly bool DismissInventoryNotifications = true; [JsonProperty(Required = Required.DisallowNull)] - internal bool FarmOffline { get; private set; } = false; + internal readonly bool FarmOffline = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool HandleOfflineMessages { get; private set; } = false; + internal readonly bool HandleOfflineMessages = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool AcceptGifts { get; private set; } = false; + internal readonly bool AcceptGifts = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool IsBotAccount { get; private set; } = false; + internal readonly bool IsBotAccount = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool SteamTradeMatcher { get; private set; } = false; + internal readonly bool SteamTradeMatcher = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool ForwardKeysToOtherBots { get; private set; } = false; + internal readonly bool ForwardKeysToOtherBots = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool DistributeKeys { get; private set; } = false; + internal readonly bool DistributeKeys = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool ShutdownOnFarmingFinished { get; private set; } = false; + internal readonly bool ShutdownOnFarmingFinished = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool SendOnFarmingFinished { get; private set; } = false; + internal readonly bool SendOnFarmingFinished = false; [JsonProperty] - internal string SteamTradeToken { get; private set; } = null; + internal readonly string SteamTradeToken = null; [JsonProperty(Required = Required.DisallowNull)] - internal byte SendTradePeriod { get; private set; } = 0; + internal readonly byte SendTradePeriod = 0; [JsonProperty(Required = Required.DisallowNull)] - internal byte AcceptConfirmationsPeriod { get; private set; } = 0; + internal readonly byte AcceptConfirmationsPeriod = 0; [JsonProperty] - internal string CustomGamePlayedWhileFarming { get; private set; } = null; + internal readonly string CustomGamePlayedWhileFarming = null; [JsonProperty] - internal string CustomGamePlayedWhileIdle { get; private set; } = null; + internal readonly string CustomGamePlayedWhileIdle = null; [JsonProperty(Required = Required.DisallowNull)] - internal HashSet GamesPlayedWhileIdle { get; private set; } = new HashSet(); + internal readonly HashSet GamesPlayedWhileIdle = new HashSet(); internal static BotConfig Load(string filePath) { @@ -145,7 +146,10 @@ namespace ArchiSteamFarm { } Logging.LogGenericWarning("Playing more than " + CardsFarmer.MaxGamesPlayedConcurrently + " games concurrently is not possible, only first " + CardsFarmer.MaxGamesPlayedConcurrently + " entries from GamesPlayedWhileIdle will be used"); - botConfig.GamesPlayedWhileIdle = new HashSet(botConfig.GamesPlayedWhileIdle.Take(CardsFarmer.MaxGamesPlayedConcurrently)); + + HashSet validGames = new HashSet(botConfig.GamesPlayedWhileIdle.Take(CardsFarmer.MaxGamesPlayedConcurrently)); + botConfig.GamesPlayedWhileIdle.IntersectWith(validGames); + botConfig.GamesPlayedWhileIdle.TrimExcess(); return botConfig; } diff --git a/ArchiSteamFarm/ConcurrentHashSet.cs b/ArchiSteamFarm/ConcurrentHashSet.cs index b93fc3774..a8b246824 100644 --- a/ArchiSteamFarm/ConcurrentHashSet.cs +++ b/ArchiSteamFarm/ConcurrentHashSet.cs @@ -100,7 +100,7 @@ namespace ArchiSteamFarm { } } - public void Dispose() => Lock?.Dispose(); + public void Dispose() => Lock.Dispose(); public void CopyTo(T[] array, int arrayIndex) { Lock.EnterReadLock(); diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index bbbd523dd..ae589eeea 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -32,6 +32,7 @@ using System.Net.Sockets; namespace ArchiSteamFarm { [SuppressMessage("ReSharper", "ClassCannotBeInstantiated")] [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + [SuppressMessage("ReSharper", "ConvertToConstant.Global")] internal sealed class GlobalConfig { [SuppressMessage("ReSharper", "UnusedMember.Global")] internal enum EUpdateChannel : byte { @@ -51,64 +52,64 @@ namespace ArchiSteamFarm { internal static readonly HashSet GlobalBlacklist = new HashSet { 267420, 303700, 335590, 368020, 425280, 480730 }; [JsonProperty(Required = Required.DisallowNull)] - internal bool Debug { get; private set; } = false; + internal readonly bool Debug = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool Headless { get; private set; } = false; + internal readonly bool Headless = false; [JsonProperty(Required = Required.DisallowNull)] - internal bool AutoUpdates { get; private set; } = true; + internal readonly bool AutoUpdates = true; [JsonProperty(Required = Required.DisallowNull)] - internal bool AutoRestart { get; private set; } = true; + internal readonly bool AutoRestart = true; [JsonProperty(Required = Required.DisallowNull)] - internal EUpdateChannel UpdateChannel { get; private set; } = EUpdateChannel.Stable; + internal readonly EUpdateChannel UpdateChannel = EUpdateChannel.Stable; [JsonProperty(Required = Required.DisallowNull)] - internal ProtocolType SteamProtocol { get; private set; } = DefaultSteamProtocol; + internal readonly ProtocolType SteamProtocol = DefaultSteamProtocol; [JsonProperty(Required = Required.DisallowNull)] - internal ulong SteamOwnerID { get; private set; } = 0; + internal readonly ulong SteamOwnerID = 0; [JsonProperty(Required = Required.DisallowNull)] - internal byte MaxFarmingTime { get; private set; } = DefaultMaxFarmingTime; + internal readonly byte MaxFarmingTime = DefaultMaxFarmingTime; [JsonProperty(Required = Required.DisallowNull)] - internal byte IdleFarmingPeriod { get; private set; } = 3; + internal readonly byte IdleFarmingPeriod = 3; [JsonProperty(Required = Required.DisallowNull)] internal byte FarmingDelay { get; private set; } = DefaultFarmingDelay; [JsonProperty(Required = Required.DisallowNull)] - internal byte LoginLimiterDelay { get; private set; } = 10; + internal readonly byte LoginLimiterDelay = 10; [JsonProperty(Required = Required.DisallowNull)] - internal byte InventoryLimiterDelay { get; private set; } = 3; + internal readonly byte InventoryLimiterDelay = 3; [JsonProperty(Required = Required.DisallowNull)] - internal byte GiftsLimiterDelay { get; private set; } = 1; + internal readonly byte GiftsLimiterDelay = 1; [JsonProperty(Required = Required.DisallowNull)] - internal byte MaxTradeHoldDuration { get; private set; } = 15; + internal readonly byte MaxTradeHoldDuration = 15; [JsonProperty(Required = Required.DisallowNull)] - internal bool ForceHttp { get; private set; } = false; + internal readonly bool ForceHttp = false; [JsonProperty(Required = Required.DisallowNull)] - internal byte HttpTimeout { get; private set; } = DefaultHttpTimeout; + internal readonly byte HttpTimeout = DefaultHttpTimeout; [JsonProperty] internal string WCFHostname { get; set; } = "localhost"; [JsonProperty(Required = Required.DisallowNull)] - internal ushort WCFPort { get; private set; } = DefaultWCFPort; + internal readonly ushort WCFPort = DefaultWCFPort; [JsonProperty(Required = Required.DisallowNull)] - internal bool Statistics { get; private set; } = true; + internal readonly bool Statistics = true; [JsonProperty(Required = Required.DisallowNull)] - internal HashSet Blacklist { get; private set; } = new HashSet(GlobalBlacklist); + internal readonly HashSet Blacklist = new HashSet(GlobalBlacklist); internal static GlobalConfig Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { @@ -141,21 +142,20 @@ namespace ArchiSteamFarm { case ProtocolType.Udp: break; default: - Logging.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol + ". Value of " + DefaultSteamProtocol + " will be used instead"); - globalConfig.SteamProtocol = DefaultSteamProtocol; - break; + Logging.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol); + return null; } // User might not know what he's doing // Ensure that he can't screw core ASF variables if (globalConfig.MaxFarmingTime == 0) { - Logging.LogGenericWarning("Configured MaxFarmingTime is invalid: " + globalConfig.MaxFarmingTime + ". Value of " + DefaultMaxFarmingTime + " will be used instead"); - globalConfig.MaxFarmingTime = DefaultMaxFarmingTime; + Logging.LogGenericWarning("Configured MaxFarmingTime is invalid: " + globalConfig.MaxFarmingTime); + return null; } if (globalConfig.FarmingDelay == 0) { - Logging.LogGenericWarning("Configured FarmingDelay is invalid: " + globalConfig.FarmingDelay + ". Value of " + DefaultFarmingDelay + " will be used instead"); - globalConfig.FarmingDelay = DefaultFarmingDelay; + Logging.LogGenericWarning("Configured FarmingDelay is invalid: " + globalConfig.FarmingDelay); + return null; } if ((globalConfig.FarmingDelay > 5) && Runtime.RequiresWorkaroundForMonoBug41701()) { @@ -164,18 +164,16 @@ namespace ArchiSteamFarm { } if (globalConfig.HttpTimeout == 0) { - Logging.LogGenericWarning("Configured HttpTimeout is invalid: " + globalConfig.HttpTimeout + ". Value of " + DefaultHttpTimeout + " will be used instead"); - globalConfig.HttpTimeout = DefaultHttpTimeout; + Logging.LogGenericWarning("Configured HttpTimeout is invalid: " + globalConfig.HttpTimeout); + return null; } if (globalConfig.WCFPort != 0) { return globalConfig; } - Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead"); - globalConfig.WCFPort = DefaultWCFPort; - - return globalConfig; + Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort); + return null; } // This constructor is used only by deserializer diff --git a/ArchiSteamFarm/GlobalDatabase.cs b/ArchiSteamFarm/GlobalDatabase.cs index 77f5b6189..b295a1d79 100644 --- a/ArchiSteamFarm/GlobalDatabase.cs +++ b/ArchiSteamFarm/GlobalDatabase.cs @@ -57,7 +57,7 @@ namespace ArchiSteamFarm { [JsonProperty(Required = Required.DisallowNull)] [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Local")] - internal InMemoryServerListProvider ServerListProvider { get; private set; } = new InMemoryServerListProvider(); + internal readonly InMemoryServerListProvider ServerListProvider = new InMemoryServerListProvider(); private readonly object FileLock = new object(); diff --git a/ArchiSteamFarm/JSON/GitHub.cs b/ArchiSteamFarm/JSON/GitHub.cs index fb772febe..2174e16f6 100644 --- a/ArchiSteamFarm/JSON/GitHub.cs +++ b/ArchiSteamFarm/JSON/GitHub.cs @@ -33,17 +33,17 @@ namespace ArchiSteamFarm.JSON { internal sealed class ReleaseResponse { internal sealed class Asset { [JsonProperty(PropertyName = "name", Required = Required.Always)] - internal string Name { get; private set; } + internal readonly string Name; [JsonProperty(PropertyName = "browser_download_url", Required = Required.Always)] - internal string DownloadURL { get; private set; } + internal readonly string DownloadURL; } [JsonProperty(PropertyName = "tag_name", Required = Required.Always)] - internal string Tag { get; private set; } + internal readonly string Tag; [JsonProperty(PropertyName = "assets", Required = Required.Always)] - internal List Assets { get; private set; } + internal readonly List Assets; } } } diff --git a/ArchiSteamFarm/JSON/Steam.cs b/ArchiSteamFarm/JSON/Steam.cs index ac06665b4..40856d9c4 100644 --- a/ArchiSteamFarm/JSON/Steam.cs +++ b/ArchiSteamFarm/JSON/Steam.cs @@ -33,8 +33,7 @@ using SteamKit2; namespace ArchiSteamFarm.JSON { internal static class Steam { - internal sealed class Item { // REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset - // Deserialized from JSON (SteamCommunity) and constructed from code + internal sealed class Item { // REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset | Deserialized from JSON (SteamCommunity) and constructed from code internal const ushort SteamAppID = 753; internal const byte SteamContextID = 6; @@ -219,8 +218,7 @@ namespace ArchiSteamFarm.JSON { } } - internal sealed class TradeOffer { // REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_TradeOffer - // Constructed from code + internal sealed class TradeOffer { // REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_TradeOffer | Constructed from code [SuppressMessage("ReSharper", "UnusedMember.Global")] internal enum ETradeOfferState : byte { Unknown, @@ -330,8 +328,7 @@ namespace ArchiSteamFarm.JSON { } [SuppressMessage("ReSharper", "UnusedMember.Global")] - internal sealed class TradeOfferRequest { - // Constructed from code + internal sealed class TradeOfferRequest { // Constructed from code internal sealed class ItemList { [JsonProperty(PropertyName = "assets", Required = Required.Always)] internal readonly HashSet Assets = new HashSet(); @@ -347,10 +344,9 @@ namespace ArchiSteamFarm.JSON { [SuppressMessage("ReSharper", "ClassCannotBeInstantiated")] [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] - internal sealed class ConfirmationResponse { - // Deserialized from JSON + internal sealed class ConfirmationResponse { // Deserialized from JSON [JsonProperty(PropertyName = "success", Required = Required.Always)] - internal bool Success { get; private set; } + internal readonly bool Success; private ConfirmationResponse() { } } @@ -358,8 +354,7 @@ namespace ArchiSteamFarm.JSON { [SuppressMessage("ReSharper", "ClassCannotBeInstantiated")] [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] - internal sealed class ConfirmationDetails { - // Deserialized from JSON + internal sealed class ConfirmationDetails { // Deserialized from JSON internal enum EType : byte { Unknown, Trade, @@ -382,7 +377,7 @@ namespace ArchiSteamFarm.JSON { } [JsonProperty(PropertyName = "success", Required = Required.Always)] - internal bool Success { get; private set; } + internal readonly bool Success; private EType _Type; private EType Type { @@ -473,10 +468,8 @@ namespace ArchiSteamFarm.JSON { } } -#pragma warning disable 649 - [JsonProperty(PropertyName = "html")] - private string HTML; -#pragma warning restore 649 + [JsonProperty(PropertyName = "html", Required = Required.DisallowNull)] + private readonly string HTML; private uint _OtherSteamID3; private uint OtherSteamID3 { diff --git a/ArchiSteamFarm/MobileAuthenticator.cs b/ArchiSteamFarm/MobileAuthenticator.cs index 5b3440994..13b36cde5 100644 --- a/ArchiSteamFarm/MobileAuthenticator.cs +++ b/ArchiSteamFarm/MobileAuthenticator.cs @@ -68,13 +68,11 @@ namespace ArchiSteamFarm { internal bool HasDeviceID => !string.IsNullOrEmpty(DeviceID); -#pragma warning disable 649 - [JsonProperty(PropertyName = "shared_secret", Required = Required.DisallowNull)] - private string SharedSecret; + [JsonProperty(PropertyName = "shared_secret", Required = Required.Always)] + private readonly string SharedSecret; - [JsonProperty(PropertyName = "identity_secret", Required = Required.DisallowNull)] - private string IdentitySecret; -#pragma warning restore 649 + [JsonProperty(PropertyName = "identity_secret", Required = Required.Always)] + private readonly string IdentitySecret; [JsonProperty(PropertyName = "device_id")] private string DeviceID; diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index c0a4d833a..553d75900 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -72,9 +72,6 @@ namespace ArchiSteamFarm { private static readonly object ConsoleLock = new object(); private static readonly ManualResetEventSlim ShutdownResetEvent = new ManualResetEventSlim(false); - private static readonly string ExecutableFile = Assembly.GetEntryAssembly().Location; - private static readonly string ExecutableName = Path.GetFileName(ExecutableFile); - private static readonly string ExecutableDirectory = Path.GetDirectoryName(ExecutableFile); private static readonly WCF WCF = new WCF(); internal static bool IsRunningAsService { get; private set; } @@ -87,7 +84,8 @@ namespace ArchiSteamFarm { private static WebBrowser WebBrowser; internal static async Task CheckForUpdate(bool updateOverride = false) { - string oldExeFile = ExecutableFile + ".old"; + string exeFile = Assembly.GetEntryAssembly().Location; + string oldExeFile = exeFile + ".old"; // We booted successfully so we can now remove old exe file if (File.Exists(oldExeFile)) { @@ -186,7 +184,8 @@ namespace ArchiSteamFarm { return; } - GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(ExecutableName, StringComparison.OrdinalIgnoreCase)); + string exeFileName = Path.GetFileName(exeFile); + GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(exeFileName, StringComparison.OrdinalIgnoreCase)); if (binaryAsset == null) { Logging.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!"); @@ -206,7 +205,7 @@ namespace ArchiSteamFarm { return; } - string newExeFile = ExecutableFile + ".new"; + string newExeFile = exeFile + ".new"; // Firstly we create new exec try { @@ -218,7 +217,7 @@ namespace ArchiSteamFarm { // Now we move current -> old try { - File.Move(ExecutableFile, oldExeFile); + File.Move(exeFile, oldExeFile); } catch (Exception e) { Logging.LogGenericException(e); try { @@ -232,12 +231,12 @@ namespace ArchiSteamFarm { // Now we move new -> current try { - File.Move(newExeFile, ExecutableFile); + File.Move(newExeFile, exeFile); } catch (Exception e) { Logging.LogGenericException(e); try { // Cleanup - File.Move(oldExeFile, ExecutableFile); + File.Move(oldExeFile, exeFile); File.Delete(newExeFile); } catch { // Ignored @@ -267,7 +266,7 @@ namespace ArchiSteamFarm { InitShutdownSequence(); try { - Process.Start(ExecutableFile, string.Join(" ", Environment.GetCommandLineArgs().Skip(1))); + Process.Start(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1))); } catch (Exception e) { Logging.LogGenericException(e); } @@ -485,22 +484,25 @@ namespace ArchiSteamFarm { Logging.InitCoreLoggers(); Logging.LogGenericInfo("ASF V" + Version); - Directory.SetCurrentDirectory(ExecutableDirectory); + string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (!string.IsNullOrEmpty(homeDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); - // Allow loading configs from source tree if it's a debug build - if (Debugging.IsDebugBuild) { + // Allow loading configs from source tree if it's a debug build + if (Debugging.IsDebugBuild) { - // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up - for (byte i = 0; i < 4; i++) { - Directory.SetCurrentDirectory(".."); - if (Directory.Exists(ConfigDirectory)) { - break; + // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up + for (byte i = 0; i < 4; i++) { + Directory.SetCurrentDirectory(".."); + if (Directory.Exists(ConfigDirectory)) { + break; + } } - } - // If config directory doesn't exist after our adjustment, abort all of that - if (!Directory.Exists(ConfigDirectory)) { - Directory.SetCurrentDirectory(ExecutableDirectory); + // If config directory doesn't exist after our adjustment, abort all of that + if (!Directory.Exists(ConfigDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); + } } } diff --git a/ArchiSteamFarm/Runtime.cs b/ArchiSteamFarm/Runtime.cs index 6447d8380..c0f8e3329 100644 --- a/ArchiSteamFarm/Runtime.cs +++ b/ArchiSteamFarm/Runtime.cs @@ -39,20 +39,17 @@ namespace ArchiSteamFarm { if (Environment.UserInteractive) { _IsUserInteractive = true; - return true; - } - - // If it's non-Mono, we can trust the result - if (!IsRunningOnMono) { + } else if (!IsRunningOnMono) { + // If it's non-Mono, we can trust the result _IsUserInteractive = false; - return false; + } else { + // In Mono, Environment.UserInteractive is always false + // There is really no reliable way for now, so assume always being interactive + // Maybe in future I find out some awful hack or workaround that could be at least semi-reliable + _IsUserInteractive = true; } - // In Mono, Environment.UserInteractive is always false - // There is really no reliable way for now, so assume always being interactive - // Maybe in future I find out some awful hack or workaround that could be at least semi-reliable - _IsUserInteractive = true; - return true; + return _IsUserInteractive.Value; } } diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index 9cdd527b6..65354ff0b 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -39,8 +39,6 @@ namespace ArchiSteamFarm { private 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 private const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it - private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version; - internal readonly CookieContainer CookieContainer = new CookieContainer(); private readonly HttpClient HttpClient; @@ -79,10 +77,7 @@ namespace ArchiSteamFarm { }; // Most web services expect that UserAgent is set, so we declare it globally - HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(DefaultUserAgent); - - // We should always operate in English language, declare it globally - HttpClient.DefaultRequestHeaders.AcceptLanguage.ParseAdd("en-US,en;q=0.8,en-GB;q=0.6"); + HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd("ArchiSteamFarm/" + Program.Version); } internal async Task UrlHeadRetry(string request, string referer = null) { @@ -308,15 +303,15 @@ namespace ArchiSteamFarm { return null; } - string content = await UrlGetToContent(request, referer).ConfigureAwait(false); - if (string.IsNullOrEmpty(content)) { + string json = await UrlGetToContent(request, referer).ConfigureAwait(false); + if (string.IsNullOrEmpty(json)) { return null; } JObject jObject; try { - jObject = JObject.Parse(content); + jObject = JObject.Parse(json); } catch (JsonException e) { Logging.LogGenericException(e, Identifier); return null; @@ -340,15 +335,15 @@ namespace ArchiSteamFarm { return null; } - string content = await UrlGetToContent(request, referer).ConfigureAwait(false); - if (string.IsNullOrEmpty(content)) { + string xml = await UrlGetToContent(request, referer).ConfigureAwait(false); + if (string.IsNullOrEmpty(xml)) { return null; } XmlDocument xmlDocument = new XmlDocument(); try { - xmlDocument.LoadXml(content); + xmlDocument.LoadXml(xml); } catch (XmlException e) { Logging.LogGenericException(e, Identifier); return null; diff --git a/ConfigGenerator/ASFConfig.cs b/ConfigGenerator/ASFConfig.cs index f8b6b40aa..9d262ddc1 100644 --- a/ConfigGenerator/ASFConfig.cs +++ b/ConfigGenerator/ASFConfig.cs @@ -33,6 +33,8 @@ namespace ConfigGenerator { internal string FilePath { get; set; } + private readonly object FileLock = new object(); + protected ASFConfig() { ASFConfigs.Add(this); } @@ -46,7 +48,7 @@ namespace ConfigGenerator { } internal void Save() { - lock (FilePath) { + lock (FileLock) { try { File.WriteAllText(FilePath, JsonConvert.SerializeObject(this, Formatting.Indented)); } catch (Exception e) { @@ -57,7 +59,7 @@ namespace ConfigGenerator { internal void Remove() { string queryPath = Path.GetFileNameWithoutExtension(FilePath); - lock (FilePath) { + lock (FileLock) { foreach (string botFile in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) { try { File.Delete(botFile); @@ -77,7 +79,7 @@ namespace ConfigGenerator { } string queryPath = Path.GetFileNameWithoutExtension(FilePath); - lock (FilePath) { + lock (FileLock) { foreach (string botFile in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) { try { File.Move(botFile, Path.Combine(Program.ConfigDirectory, botName + Path.GetExtension(botFile))); diff --git a/ConfigGenerator/Program.cs b/ConfigGenerator/Program.cs index 2d9a1c524..9b3fe55df 100644 --- a/ConfigGenerator/Program.cs +++ b/ConfigGenerator/Program.cs @@ -39,9 +39,6 @@ namespace ConfigGenerator { private const string ASFDirectory = "ArchiSteamFarm"; private const string ASFExecutableFile = ASF + ".exe"; - private static readonly string ExecutableDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - private static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version; - /// /// The main entry point for the application. /// @@ -57,25 +54,28 @@ namespace ConfigGenerator { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler; - Directory.SetCurrentDirectory(ExecutableDirectory); + string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (!string.IsNullOrEmpty(homeDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); - // Allow loading configs from source tree if it's a debug build - if (Debugging.IsDebugBuild) { + // Allow loading configs from source tree if it's a debug build + if (Debugging.IsDebugBuild) { - // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up - for (byte i = 0; i < 4; i++) { - Directory.SetCurrentDirectory(".."); - if (!Directory.Exists(ASFDirectory)) { - continue; + // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up + for (byte i = 0; i < 4; i++) { + Directory.SetCurrentDirectory(".."); + if (!Directory.Exists(ASFDirectory)) { + continue; + } + + Directory.SetCurrentDirectory(ASFDirectory); + break; } - Directory.SetCurrentDirectory(ASFDirectory); - break; - } - - // If config directory doesn't exist after our adjustment, abort all of that - if (!Directory.Exists(ConfigDirectory)) { - Directory.SetCurrentDirectory(ExecutableDirectory); + // If config directory doesn't exist after our adjustment, abort all of that + if (!Directory.Exists(ConfigDirectory)) { + Directory.SetCurrentDirectory(homeDirectory); + } } } @@ -89,15 +89,17 @@ namespace ConfigGenerator { } FileVersionInfo asfVersionInfo = FileVersionInfo.GetVersionInfo(ASFExecutableFile); - Version asfVersion = new Version(asfVersionInfo.ProductVersion); - if (Version == asfVersion) { + + Version cgVersion = Assembly.GetEntryAssembly().GetName().Version; + + if (asfVersion == cgVersion) { return; } Logging.LogGenericErrorWithoutStacktrace( "Version of ASF and ConfigGenerator doesn't match!" + Environment.NewLine + - "ASF version: " + asfVersion + " | ConfigGenerator version: " + Version + Environment.NewLine + + "ASF version: " + asfVersion + " | ConfigGenerator version: " + cgVersion + Environment.NewLine + Environment.NewLine + "Please use ConfigGenerator from the same ASF release, I'll redirect you to appropriate ASF release..." ); @@ -107,8 +109,8 @@ namespace ConfigGenerator { } private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) { - if ((sender == null) || (args == null) || (args.ExceptionObject == null)) { - Logging.LogNullError(nameof(sender) + " || " + nameof(args) + " || " + nameof(args.ExceptionObject)); + if (args?.ExceptionObject == null) { + Logging.LogNullError(nameof(args) + " || " + nameof(args.ExceptionObject)); return; } @@ -116,8 +118,8 @@ namespace ConfigGenerator { } private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) { - if ((sender == null) || (args == null) || (args.Exception == null)) { - Logging.LogNullError(nameof(sender) + " || " + nameof(args) + " || " + nameof(args.Exception)); + if (args?.Exception == null) { + Logging.LogNullError(nameof(args) + " || " + nameof(args.Exception)); return; }