mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 06:00:46 +00:00
Code review
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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<string, Bot> Bots = new Dictionary<string, Bot>();
|
||||
internal static readonly ConcurrentDictionary<string, Bot> Bots = new ConcurrentDictionary<string, Bot>();
|
||||
|
||||
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);
|
||||
|
||||
@@ -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<uint> GamesPlayedWhileIdle { get; private set; } = new HashSet<uint>();
|
||||
internal readonly HashSet<uint> GamesPlayedWhileIdle = new HashSet<uint>();
|
||||
|
||||
|
||||
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<uint>(botConfig.GamesPlayedWhileIdle.Take(CardsFarmer.MaxGamesPlayedConcurrently));
|
||||
|
||||
HashSet<uint> validGames = new HashSet<uint>(botConfig.GamesPlayedWhileIdle.Take(CardsFarmer.MaxGamesPlayedConcurrently));
|
||||
botConfig.GamesPlayedWhileIdle.IntersectWith(validGames);
|
||||
botConfig.GamesPlayedWhileIdle.TrimExcess();
|
||||
|
||||
return botConfig;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<uint> GlobalBlacklist = new HashSet<uint> { 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<uint> Blacklist { get; private set; } = new HashSet<uint>(GlobalBlacklist);
|
||||
internal readonly HashSet<uint> Blacklist = new HashSet<uint>(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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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<Asset> Assets { get; private set; }
|
||||
internal readonly List<Asset> Assets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Item> Assets = new HashSet<Item>();
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<bool> 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;
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user