diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index 4ec79db87..148ad6965 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -29,6 +29,8 @@ using System.Threading; using System.Threading.Tasks; using ArchiSteamFarm.Localization; using ArchiSteamFarm.NLog; +using SteamKit2; +using SteamKit2.Discovery; namespace ArchiSteamFarm { internal static class ASF { @@ -48,8 +50,22 @@ namespace ArchiSteamFarm { return; } - // Before attempting to connect, initialize our configuration - await Bot.InitializeSteamConfiguration(Program.GlobalConfig.SteamProtocols, Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false); + // Ensure that we ask for a list of servers if we don't have any saved servers available + IEnumerable servers = await Program.GlobalDatabase.ServerListProvider.FetchServerListAsync().ConfigureAwait(false); + + if (servers?.Any() != true) { + ArchiLogger.LogGenericInfo(string.Format(Strings.Initializing, nameof(SteamDirectory))); + + SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(Program.GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => Program.WebBrowser.GenerateDisposableHttpClient())); + + try { + await SteamDirectory.LoadAsync(steamConfiguration).ConfigureAwait(false); + ArchiLogger.LogGenericInfo(Strings.Success); + } catch { + ArchiLogger.LogGenericWarning(Strings.BotSteamDirectoryInitializationFailed); + await Task.Delay(5000).ConfigureAwait(false); + } + } HashSet botNames; diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index ec647759b..8fa2538ea 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -25,6 +25,7 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -227,7 +228,6 @@ namespace ArchiSteamFarm { // ReSharper disable once AccessToDisposedClosure async () => await iEconService.DeclineTradeOffer( method: WebRequestMethods.Http.Post, - secure: true, tradeofferid: tradeID ) ).ConfigureAwait(false); @@ -248,6 +248,8 @@ namespace ArchiSteamFarm { return true; } + internal HttpClient GenerateDisposableHttpClient() => WebBrowser.GenerateDisposableHttpClient(); + internal async Task> GenerateNewDiscoveryQueue() { const string request = "/explore/generatenewdiscoveryqueue"; @@ -281,7 +283,6 @@ namespace ArchiSteamFarm { active_only: 1, get_descriptions: 1, get_received_offers: 1, - secure: true, time_historical_cutoff: uint.MaxValue ) ).ConfigureAwait(false); @@ -408,7 +409,7 @@ namespace ArchiSteamFarm { WebAPI.DefaultBaseAddress.Host, // ReSharper disable once AccessToDisposedClosure - async () => await iSteamApps.GetAppList2(secure: true) + async () => await iSteamApps.GetAppList2() ).ConfigureAwait(false); } catch (TaskCanceledException e) { Bot.ArchiLogger.LogGenericDebuggingException(e); @@ -800,7 +801,6 @@ namespace ArchiSteamFarm { // ReSharper disable once AccessToDisposedClosure async () => await iPlayerService.GetOwnedGames( include_appinfo: 1, - secure: true, steamid: steamID ) ).ConfigureAwait(false); @@ -849,10 +849,7 @@ namespace ArchiSteamFarm { WebAPI.DefaultBaseAddress.Host, // ReSharper disable once AccessToDisposedClosure - async () => await iTwoFactorService.QueryTime( - method: WebRequestMethods.Http.Post, - secure: true - ) + async () => await iTwoFactorService.QueryTime(method: WebRequestMethods.Http.Post) ).ConfigureAwait(false); } catch (TaskCanceledException e) { Bot.ArchiLogger.LogGenericDebuggingException(e); @@ -960,7 +957,6 @@ namespace ArchiSteamFarm { // ReSharper disable once AccessToDisposedClosure async () => await iEconService.GetTradeHoldDurations( - secure: true, steamid_target: steamID, trade_offer_access_token: tradeToken ?? "" // TODO: Change me once https://github.com/SteamRE/SteamKit/pull/522 is merged ) @@ -1115,7 +1111,6 @@ namespace ArchiSteamFarm { async () => await iSteamUserAuth.AuthenticateUser( encrypted_loginkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(encryptedLoginKey, 0, encryptedLoginKey.Length)), method: WebRequestMethods.Http.Post, - secure: true, sessionkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(encryptedSessionKey, 0, encryptedSessionKey.Length)), steamid: steamID ) diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index c051c675c..b1aff5791 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -36,7 +36,6 @@ using ArchiSteamFarm.Localization; using ArchiSteamFarm.NLog; using Newtonsoft.Json; using SteamKit2; -using SteamKit2.Discovery; using SteamKit2.Unified.Internal; namespace ArchiSteamFarm { @@ -58,8 +57,6 @@ namespace ArchiSteamFarm { private static readonly SemaphoreSlim BotsSemaphore = new SemaphoreSlim(1, 1); private static readonly SemaphoreSlim LoginSemaphore = new SemaphoreSlim(1, 1); - private static SteamConfiguration SteamConfiguration; - internal readonly Actions Actions; internal readonly ArchiHandler ArchiHandler; internal readonly ArchiLogger ArchiLogger; @@ -123,7 +120,7 @@ namespace ArchiSteamFarm { internal bool PlayingWasBlocked { get; private set; } internal ulong SteamID { get; private set; } - internal int WalletBalance { get; private set; } + internal uint WalletBalance { get; private set; } internal ECurrencyCode WalletCurrency { get; private set; } [JsonProperty] @@ -181,8 +178,12 @@ namespace ArchiSteamFarm { BotDatabase.MobileAuthenticator.Init(this); } + ArchiWebHandler = new ArchiWebHandler(this); + + SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(Program.GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => ArchiWebHandler.GenerateDisposableHttpClient())); + // Initialize - SteamClient = new SteamClient(SteamConfiguration); + SteamClient = new SteamClient(steamConfiguration); if (Debugging.IsUserDebugging && Directory.Exists(SharedInfo.DebugDirectory)) { string debugListenerPath = Path.Combine(SharedInfo.DebugDirectory, botName); @@ -227,7 +228,6 @@ namespace ArchiSteamFarm { CallbackManager.Subscribe(OnVanityURLChangedCallback); Actions = new Actions(this); - ArchiWebHandler = new ArchiWebHandler(this); CardsFarmer = new CardsFarmer(this); Commands = new Commands(this); Trading = new Trading(this); @@ -748,30 +748,6 @@ namespace ArchiSteamFarm { } } - internal static async Task InitializeSteamConfiguration(ProtocolTypes protocolTypes, uint cellID, IServerListProvider serverListProvider) { - if (serverListProvider == null) { - ASF.ArchiLogger.LogNullError(nameof(serverListProvider)); - - return; - } - - SteamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(protocolTypes).WithCellID(cellID).WithServerListProvider(serverListProvider)); - - // Ensure that we ask for a list of servers if we don't have any saved servers available - IEnumerable servers = await SteamConfiguration.ServerListProvider.FetchServerListAsync().ConfigureAwait(false); - - if (servers?.Any() != true) { - ASF.ArchiLogger.LogGenericInfo(string.Format(Strings.Initializing, nameof(SteamDirectory))); - - try { - await SteamDirectory.LoadAsync(SteamConfiguration).ConfigureAwait(false); - ASF.ArchiLogger.LogGenericInfo(Strings.Success); - } catch { - ASF.ArchiLogger.LogGenericWarning(Strings.BotSteamDirectoryInitializationFailed); - } - } - } - internal bool IsBlacklistedFromIdling(uint appID) { if (appID == 0) { ArchiLogger.LogNullError(nameof(appID)); @@ -2456,7 +2432,7 @@ namespace ArchiSteamFarm { return; } - WalletBalance = callback.Balance; + WalletBalance = (uint) callback.LongBalance; WalletCurrency = callback.Currency; } diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index 7be09665f..3f1bf5087 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -45,30 +45,45 @@ namespace ArchiSteamFarm { private readonly ArchiLogger ArchiLogger; private readonly HttpClient HttpClient; + private readonly HttpClientHandler HttpClientHandler; internal WebBrowser(ArchiLogger archiLogger, IWebProxy webProxy = null, bool extendedTimeout = false) { ArchiLogger = archiLogger ?? throw new ArgumentNullException(nameof(archiLogger)); - HttpClientHandler httpClientHandler = new HttpClientHandler { + HttpClientHandler = new HttpClientHandler { AllowAutoRedirect = false, // This must be false if we want to handle custom redirection schemes such as "steammobile://" AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, - CookieContainer = CookieContainer, - Proxy = webProxy, - UseProxy = webProxy != null + CookieContainer = CookieContainer }; - if (!RuntimeCompatibility.IsRunningOnMono) { - httpClientHandler.MaxConnectionsPerServer = MaxConnections; + if (webProxy != null) { + HttpClientHandler.Proxy = webProxy; + HttpClientHandler.UseProxy = true; } - HttpClient = new HttpClient(httpClientHandler) { Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * Program.GlobalConfig.ConnectionTimeout : Program.GlobalConfig.ConnectionTimeout) }; + if (!RuntimeCompatibility.IsRunningOnMono) { + HttpClientHandler.MaxConnectionsPerServer = MaxConnections; + } - // Most web services expect that UserAgent is set, so we declare it globally - // If you by any chance came here with a very "clever" idea of changing default ASF user-agent then here is a very good advice from me: don't, for your own safety - you've been warned - HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(SharedInfo.PublicIdentifier + "/" + SharedInfo.Version + " (+" + SharedInfo.ProjectURL + ")"); + HttpClient = GenerateDisposableHttpClient(extendedTimeout); } - public void Dispose() => HttpClient.Dispose(); + public void Dispose() { + HttpClient.Dispose(); + HttpClientHandler.Dispose(); + } + + internal HttpClient GenerateDisposableHttpClient(bool extendedTimeout = false) { + HttpClient result = new HttpClient(HttpClientHandler) { + Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * Program.GlobalConfig.ConnectionTimeout : Program.GlobalConfig.ConnectionTimeout) + }; + + // Most web services expect that UserAgent is set, so we declare it globally + // If you by any chance came here with a very "clever" idea of hiding your ass by changing default ASF user-agent then here is a very good advice from me: don't, for your own safety - you've been warned + result.DefaultRequestHeaders.UserAgent.ParseAdd(SharedInfo.PublicIdentifier + "/" + SharedInfo.Version + " (+" + SharedInfo.ProjectURL + ")"); + + return result; + } internal static void Init() { // Set max connection limit from default of 2 to desired value diff --git a/ArchiSteamFarm/lib/SteamKit2.dll b/ArchiSteamFarm/lib/SteamKit2.dll index f36e2474d..b8733d74e 100644 Binary files a/ArchiSteamFarm/lib/SteamKit2.dll and b/ArchiSteamFarm/lib/SteamKit2.dll differ diff --git a/ArchiSteamFarm/lib/SteamKit2.xml b/ArchiSteamFarm/lib/SteamKit2.xml index 7d4a08ed3..4d9fe1173 100644 --- a/ArchiSteamFarm/lib/SteamKit2.xml +++ b/ArchiSteamFarm/lib/SteamKit2.xml @@ -4879,7 +4879,12 @@ - Gets the balance of the wallet, in cents. + Gets the balance of the wallet as a 32-bit integer, in cents. + + + + + Gets the balance of the wallet as a 64-bit integer, in cents. @@ -5935,6 +5940,13 @@ Whether or not to use the Steam Directory to discover available servers. A builder with modified configuration. + + + Configures this with custom HTTP behaviour. + + A function to create and configure a new HttpClient. + A builder with modified configuration. + Configures how this will be used to connect to Steam. @@ -5973,6 +5985,13 @@ Keys can be obtained from https://steamcommunity.com/dev or the Steamworks Partner site. A builder with modified configuration. + + + Factory function to create a user-configured HttpClient. + The HttpClient will be disposed of after use. + + A new to be used to send HTTP requests. + Configuration object to use. @@ -6012,6 +6031,11 @@ when calling SteamFriends.RequestFriendInfo without specifying flags. + + + Factory function to create a user-configured HttpClient. + + The supported protocol types to use when attempting to connect to Steam. @@ -6338,6 +6362,7 @@ A object representing the results of the Web API call. The function name or request method provided were null. An network error occurred when performing the request. + A network error occurred when performing the request. An error occured when parsing the response from the WebAPI. @@ -6351,6 +6376,7 @@ A object representing the results of the Web API call. The function name or request method provided were null. An network error occurred when performing the request. + A network error occurred when performing the request. An error occured when parsing the response from the WebAPI. @@ -6389,10 +6415,6 @@ The dynamic method name was not in the correct format. All API function calls must be in the format 'FunctionName###' where the optional ###'s represent a version number. - - The reserved named parameter 'secure' was not a boolean value. - This parameter is used when requests must go through the secure API. - The function version number specified was out of range. @@ -6423,6 +6445,7 @@ A that contains a object representing the results of the Web API call. The function name or request method provided were null. An network error occurred when performing the request. + A network error occurred when performing the request. An error occured when parsing the response from the WebAPI. @@ -6461,10 +6484,6 @@ The dynamic method name was not in the correct format. All API function calls must be in the format 'FunctionName###' where the optional ###'s represent a version number. - - The reserved named parameter 'secure' was not a boolean value. - This parameter is used when requests must go through the secure API. - The function version number specified was out of range. @@ -6503,6 +6522,28 @@ An optional API key to be used for authorized requests. A dynamic object to interact with the Web API. + + + Thrown when WebAPI request fails. + + + + + Represents the status code of the HTTP response. + + + + + Represents the collection of HTTP response headers. + + + + + Initializes a new instance of the class. + + The message that describes the error. + HTTP response message including the status code and data. + Represents a Steam3 depot manifest. @@ -6586,6 +6627,31 @@ true if the filenames are encrypted; otherwise, false. + + + Gets the depot id. + + + + + Gets the manifest id. + + + + + Gets the depot creation time. + + + + + Gets the total uncompressed size of all files in this depot. + + + + + Gets the total compressed size of all files in this depot. + + Attempts to decrypts file names with the given encryption key. @@ -6640,6 +6706,20 @@ The 32bit app id to assign this GameID from. + + + Initializes a new instance of the class. + + The base app id of the mod. + The game folder name of the mod. + + + + Initializes a new instance of the class. + + The path to the executable, usually quoted. + The name of the application shortcut. + Sets the various components of this GameID from a 64bit integer form. diff --git a/tools/NetHook2/NetHook2.dll b/tools/NetHook2/NetHook2.dll index 8349de15e..021e08ef5 100644 Binary files a/tools/NetHook2/NetHook2.dll and b/tools/NetHook2/NetHook2.dll differ diff --git a/tools/NetHookAnalyzer2/NetHookAnalyzer2.exe b/tools/NetHookAnalyzer2/NetHookAnalyzer2.exe index 8721bda31..1a478b31e 100644 Binary files a/tools/NetHookAnalyzer2/NetHookAnalyzer2.exe and b/tools/NetHookAnalyzer2/NetHookAnalyzer2.exe differ diff --git a/tools/NetHookAnalyzer2/SteamKit2.dll b/tools/NetHookAnalyzer2/SteamKit2.dll index f36e2474d..b8733d74e 100644 Binary files a/tools/NetHookAnalyzer2/SteamKit2.dll and b/tools/NetHookAnalyzer2/SteamKit2.dll differ diff --git a/tools/NetHookAnalyzer2/SteamKit2.xml b/tools/NetHookAnalyzer2/SteamKit2.xml index 7d4a08ed3..4d9fe1173 100644 --- a/tools/NetHookAnalyzer2/SteamKit2.xml +++ b/tools/NetHookAnalyzer2/SteamKit2.xml @@ -4879,7 +4879,12 @@ - Gets the balance of the wallet, in cents. + Gets the balance of the wallet as a 32-bit integer, in cents. + + + + + Gets the balance of the wallet as a 64-bit integer, in cents. @@ -5935,6 +5940,13 @@ Whether or not to use the Steam Directory to discover available servers. A builder with modified configuration. + + + Configures this with custom HTTP behaviour. + + A function to create and configure a new HttpClient. + A builder with modified configuration. + Configures how this will be used to connect to Steam. @@ -5973,6 +5985,13 @@ Keys can be obtained from https://steamcommunity.com/dev or the Steamworks Partner site. A builder with modified configuration. + + + Factory function to create a user-configured HttpClient. + The HttpClient will be disposed of after use. + + A new to be used to send HTTP requests. + Configuration object to use. @@ -6012,6 +6031,11 @@ when calling SteamFriends.RequestFriendInfo without specifying flags. + + + Factory function to create a user-configured HttpClient. + + The supported protocol types to use when attempting to connect to Steam. @@ -6338,6 +6362,7 @@ A object representing the results of the Web API call. The function name or request method provided were null. An network error occurred when performing the request. + A network error occurred when performing the request. An error occured when parsing the response from the WebAPI. @@ -6351,6 +6376,7 @@ A object representing the results of the Web API call. The function name or request method provided were null. An network error occurred when performing the request. + A network error occurred when performing the request. An error occured when parsing the response from the WebAPI. @@ -6389,10 +6415,6 @@ The dynamic method name was not in the correct format. All API function calls must be in the format 'FunctionName###' where the optional ###'s represent a version number. - - The reserved named parameter 'secure' was not a boolean value. - This parameter is used when requests must go through the secure API. - The function version number specified was out of range. @@ -6423,6 +6445,7 @@ A that contains a object representing the results of the Web API call. The function name or request method provided were null. An network error occurred when performing the request. + A network error occurred when performing the request. An error occured when parsing the response from the WebAPI. @@ -6461,10 +6484,6 @@ The dynamic method name was not in the correct format. All API function calls must be in the format 'FunctionName###' where the optional ###'s represent a version number. - - The reserved named parameter 'secure' was not a boolean value. - This parameter is used when requests must go through the secure API. - The function version number specified was out of range. @@ -6503,6 +6522,28 @@ An optional API key to be used for authorized requests. A dynamic object to interact with the Web API. + + + Thrown when WebAPI request fails. + + + + + Represents the status code of the HTTP response. + + + + + Represents the collection of HTTP response headers. + + + + + Initializes a new instance of the class. + + The message that describes the error. + HTTP response message including the status code and data. + Represents a Steam3 depot manifest. @@ -6586,6 +6627,31 @@ true if the filenames are encrypted; otherwise, false. + + + Gets the depot id. + + + + + Gets the manifest id. + + + + + Gets the depot creation time. + + + + + Gets the total uncompressed size of all files in this depot. + + + + + Gets the total compressed size of all files in this depot. + + Attempts to decrypts file names with the given encryption key. @@ -6640,6 +6706,20 @@ The 32bit app id to assign this GameID from. + + + Initializes a new instance of the class. + + The base app id of the mod. + The game folder name of the mod. + + + + Initializes a new instance of the class. + + The path to the executable, usually quoted. + The name of the application shortcut. + Sets the various components of this GameID from a 64bit integer form.