Code review

This commit is contained in:
JustArchi
2016-07-25 06:08:45 +02:00
parent 52de999443
commit 4f01dc39fc
14 changed files with 150 additions and 158 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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();

View File

@@ -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;
}
}
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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)));

View File

@@ -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;
}