mirror of
https://github.com/JustArchiNET/ArchiSteamFarm
synced 2024-11-14 00:47:25 +00:00
Closes #3066
This commit is contained in:
parent
263c77da12
commit
adbf0748f8
5 changed files with 31 additions and 29 deletions
|
@ -26,6 +26,7 @@ using System.Collections.Immutable;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ArchiSteamFarm.Core;
|
using ArchiSteamFarm.Core;
|
||||||
using ArchiSteamFarm.Helpers;
|
using ArchiSteamFarm.Helpers;
|
||||||
|
@ -324,14 +325,14 @@ internal sealed class GlobalCache : SerializableFile {
|
||||||
return (depotKey.Length == 64) && Utilities.IsValidHexadecimalText(depotKey);
|
return (depotKey.Length == 64) && Utilities.IsValidHexadecimalText(depotKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<(bool Success, ImmutableHashSet<uint>? Result)> ResolveKnownDepotIDs() {
|
private static async Task<(bool Success, ImmutableHashSet<uint>? Result)> ResolveKnownDepotIDs(CancellationToken cancellationToken = default) {
|
||||||
if (ASF.WebBrowser == null) {
|
if (ASF.WebBrowser == null) {
|
||||||
throw new InvalidOperationException(nameof(ASF.WebBrowser));
|
throw new InvalidOperationException(nameof(ASF.WebBrowser));
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri request = new($"{SharedInfo.ServerURL}/knowndepots.csv");
|
Uri request = new($"{SharedInfo.ServerURL}/knowndepots.csv");
|
||||||
|
|
||||||
StreamResponse? response = await ASF.WebBrowser.UrlGetToStream(request).ConfigureAwait(false);
|
StreamResponse? response = await ASF.WebBrowser.UrlGetToStream(request, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (response?.Content == null) {
|
if (response?.Content == null) {
|
||||||
return (false, null);
|
return (false, null);
|
||||||
|
@ -341,7 +342,7 @@ internal sealed class GlobalCache : SerializableFile {
|
||||||
try {
|
try {
|
||||||
using StreamReader reader = new(response.Content);
|
using StreamReader reader = new(response.Content);
|
||||||
|
|
||||||
string? countText = await reader.ReadLineAsync().ConfigureAwait(false);
|
string? countText = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(countText) || !int.TryParse(countText, out int count) || (count <= 0)) {
|
if (string.IsNullOrEmpty(countText) || !int.TryParse(countText, out int count) || (count <= 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(countText);
|
ASF.ArchiLogger.LogNullError(countText);
|
||||||
|
@ -351,7 +352,7 @@ internal sealed class GlobalCache : SerializableFile {
|
||||||
|
|
||||||
HashSet<uint> result = new(count);
|
HashSet<uint> result = new(count);
|
||||||
|
|
||||||
while (await reader.ReadLineAsync().ConfigureAwait(false) is { Length: > 0 } line) {
|
while (await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false) is { Length: > 0 } line) {
|
||||||
if (!uint.TryParse(line, out uint depotID) || (depotID == 0)) {
|
if (!uint.TryParse(line, out uint depotID) || (depotID == 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(depotID);
|
ASF.ArchiLogger.LogNullError(depotID);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using ArchiSteamFarm.Helpers;
|
using ArchiSteamFarm.Helpers;
|
||||||
|
@ -170,7 +171,7 @@ internal static class ArchiNet {
|
||||||
return authenticateResponse.Content?.Result == bot.SteamID ? HttpStatusCode.OK : HttpStatusCode.Unauthorized;
|
return authenticateResponse.Content?.Result == bot.SteamID ? HttpStatusCode.OK : HttpStatusCode.Unauthorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<(bool Success, IReadOnlyCollection<ulong>? Result)> ResolveCachedBadBots() {
|
private static async Task<(bool Success, IReadOnlyCollection<ulong>? Result)> ResolveCachedBadBots(CancellationToken cancellationToken = default) {
|
||||||
if (ASF.GlobalDatabase == null) {
|
if (ASF.GlobalDatabase == null) {
|
||||||
throw new InvalidOperationException(nameof(ASF.WebBrowser));
|
throw new InvalidOperationException(nameof(ASF.WebBrowser));
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ internal static class ArchiNet {
|
||||||
|
|
||||||
Uri request = new(URL, "/Api/BadBots");
|
Uri request = new(URL, "/Api/BadBots");
|
||||||
|
|
||||||
ObjectResponse<GenericResponse<ImmutableHashSet<ulong>>>? response = await ASF.WebBrowser.UrlGetToJsonObject<GenericResponse<ImmutableHashSet<ulong>>>(request).ConfigureAwait(false);
|
ObjectResponse<GenericResponse<ImmutableHashSet<ulong>>>? response = await ASF.WebBrowser.UrlGetToJsonObject<GenericResponse<ImmutableHashSet<ulong>>>(request, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (response?.Content?.Result == null) {
|
if (response?.Content?.Result == null) {
|
||||||
return (false, ASF.GlobalDatabase.CachedBadBots);
|
return (false, ASF.GlobalDatabase.CachedBadBots);
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace ArchiSteamFarm.Helpers;
|
||||||
public sealed class ArchiCacheable<T> : IDisposable {
|
public sealed class ArchiCacheable<T> : IDisposable {
|
||||||
private readonly TimeSpan CacheLifetime;
|
private readonly TimeSpan CacheLifetime;
|
||||||
private readonly SemaphoreSlim InitSemaphore = new(1, 1);
|
private readonly SemaphoreSlim InitSemaphore = new(1, 1);
|
||||||
private readonly Func<Task<(bool Success, T? Result)>> ResolveFunction;
|
private readonly Func<CancellationToken, Task<(bool Success, T? Result)>> ResolveFunction;
|
||||||
|
|
||||||
private bool IsInitialized => InitializedAt > DateTime.MinValue;
|
private bool IsInitialized => InitializedAt > DateTime.MinValue;
|
||||||
private bool IsPermanentCache => CacheLifetime == Timeout.InfiniteTimeSpan;
|
private bool IsPermanentCache => CacheLifetime == Timeout.InfiniteTimeSpan;
|
||||||
|
@ -39,7 +39,7 @@ public sealed class ArchiCacheable<T> : IDisposable {
|
||||||
private DateTime InitializedAt;
|
private DateTime InitializedAt;
|
||||||
private T? InitializedValue;
|
private T? InitializedValue;
|
||||||
|
|
||||||
public ArchiCacheable(Func<Task<(bool Success, T? Result)>> resolveFunction, TimeSpan? cacheLifetime = null) {
|
public ArchiCacheable(Func<CancellationToken, Task<(bool Success, T? Result)>> resolveFunction, TimeSpan? cacheLifetime = null) {
|
||||||
ArgumentNullException.ThrowIfNull(resolveFunction);
|
ArgumentNullException.ThrowIfNull(resolveFunction);
|
||||||
|
|
||||||
ResolveFunction = resolveFunction;
|
ResolveFunction = resolveFunction;
|
||||||
|
@ -49,7 +49,7 @@ public sealed class ArchiCacheable<T> : IDisposable {
|
||||||
public void Dispose() => InitSemaphore.Dispose();
|
public void Dispose() => InitSemaphore.Dispose();
|
||||||
|
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public async Task<(bool Success, T? Result)> GetValue(ECacheFallback cacheFallback = ECacheFallback.DefaultForType) {
|
public async Task<(bool Success, T? Result)> GetValue(ECacheFallback cacheFallback = ECacheFallback.DefaultForType, CancellationToken cancellationToken = default) {
|
||||||
if (!Enum.IsDefined(cacheFallback)) {
|
if (!Enum.IsDefined(cacheFallback)) {
|
||||||
throw new InvalidEnumArgumentException(nameof(cacheFallback), (int) cacheFallback, typeof(ECacheFallback));
|
throw new InvalidEnumArgumentException(nameof(cacheFallback), (int) cacheFallback, typeof(ECacheFallback));
|
||||||
}
|
}
|
||||||
|
@ -58,14 +58,14 @@ public sealed class ArchiCacheable<T> : IDisposable {
|
||||||
return (true, InitializedValue);
|
return (true, InitializedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
await InitSemaphore.WaitAsync().ConfigureAwait(false);
|
await InitSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (IsInitialized && IsRecent) {
|
if (IsInitialized && IsRecent) {
|
||||||
return (true, InitializedValue);
|
return (true, InitializedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
(bool success, T? result) = await ResolveFunction().ConfigureAwait(false);
|
(bool success, T? result) = await ResolveFunction(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return cacheFallback switch {
|
return cacheFallback switch {
|
||||||
|
@ -86,12 +86,12 @@ public sealed class ArchiCacheable<T> : IDisposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public async Task Reset() {
|
public async Task Reset(CancellationToken cancellationToken = default) {
|
||||||
if (!IsInitialized) {
|
if (!IsInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await InitSemaphore.WaitAsync().ConfigureAwait(false);
|
await InitSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!IsInitialized) {
|
if (!IsInitialized) {
|
||||||
|
|
|
@ -2275,9 +2275,9 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
internal void OnDisconnected() {
|
internal void OnDisconnected() {
|
||||||
Initialized = false;
|
Initialized = false;
|
||||||
|
|
||||||
Utilities.InBackground(CachedAccessToken.Reset);
|
Utilities.InBackground(() => CachedAccessToken.Reset());
|
||||||
Utilities.InBackground(CachedApiKey.Reset);
|
Utilities.InBackground(() => CachedApiKey.Reset());
|
||||||
Utilities.InBackground(CachedEconomyBan.Reset);
|
Utilities.InBackground(() => CachedEconomyBan.Reset());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnVanityURLChanged(string? vanityURL = null) => VanityURL = !string.IsNullOrEmpty(vanityURL) ? vanityURL : null;
|
internal void OnVanityURLChanged(string? vanityURL = null) => VanityURL = !string.IsNullOrEmpty(vanityURL) ? vanityURL : null;
|
||||||
|
@ -2329,10 +2329,10 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
return response?.Content?.Result == EResult.OK;
|
return response?.Content?.Result == EResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(ESteamApiKeyState State, string? Key)> GetApiKeyState() {
|
private async Task<(ESteamApiKeyState State, string? Key)> GetApiKeyState(CancellationToken cancellationToken = default) {
|
||||||
Uri request = new(SteamCommunityURL, "/dev/apikey?l=english");
|
Uri request = new(SteamCommunityURL, "/dev/apikey?l=english");
|
||||||
|
|
||||||
using HtmlDocumentResponse? response = await UrlGetToHtmlDocumentWithSession(request, checkSessionPreemptively: false).ConfigureAwait(false);
|
using HtmlDocumentResponse? response = await UrlGetToHtmlDocumentWithSession(request, checkSessionPreemptively: false, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (response?.Content == null) {
|
if (response?.Content == null) {
|
||||||
return (ESteamApiKeyState.Timeout, null);
|
return (ESteamApiKeyState.Timeout, null);
|
||||||
|
@ -2611,21 +2611,21 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
return await UrlPostWithSession(request, data: data).ConfigureAwait(false);
|
return await UrlPostWithSession(request, data: data).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(bool Success, string? Result)> ResolveAccessToken() {
|
private async Task<(bool Success, string? Result)> ResolveAccessToken(CancellationToken cancellationToken = default) {
|
||||||
Uri request = new(SteamStoreURL, "/pointssummary/ajaxgetasyncconfig");
|
Uri request = new(SteamStoreURL, "/pointssummary/ajaxgetasyncconfig");
|
||||||
|
|
||||||
ObjectResponse<AccessTokenResponse>? response = await UrlGetToJsonObjectWithSession<AccessTokenResponse>(request).ConfigureAwait(false);
|
ObjectResponse<AccessTokenResponse>? response = await UrlGetToJsonObjectWithSession<AccessTokenResponse>(request, cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return !string.IsNullOrEmpty(response?.Content?.Data.WebAPIToken) ? (true, response.Content.Data.WebAPIToken) : (false, null);
|
return !string.IsNullOrEmpty(response?.Content?.Data.WebAPIToken) ? (true, response.Content.Data.WebAPIToken) : (false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(bool Success, string? Result)> ResolveApiKey() {
|
private async Task<(bool Success, string? Result)> ResolveApiKey(CancellationToken cancellationToken = default) {
|
||||||
if (Bot.IsAccountLimited) {
|
if (Bot.IsAccountLimited) {
|
||||||
// API key is permanently unavailable for limited accounts
|
// API key is permanently unavailable for limited accounts
|
||||||
return (true, null);
|
return (true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
(ESteamApiKeyState State, string? Key) result = await GetApiKeyState().ConfigureAwait(false);
|
(ESteamApiKeyState State, string? Key) result = await GetApiKeyState(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
switch (result.State) {
|
switch (result.State) {
|
||||||
case ESteamApiKeyState.AccessDenied:
|
case ESteamApiKeyState.AccessDenied:
|
||||||
|
@ -2641,7 +2641,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should have the key ready, so let's fetch it again
|
// We should have the key ready, so let's fetch it again
|
||||||
result = await GetApiKeyState().ConfigureAwait(false);
|
result = await GetApiKeyState(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (result.State == ESteamApiKeyState.Timeout) {
|
if (result.State == ESteamApiKeyState.Timeout) {
|
||||||
// Request timed out, bad luck, we'll try again later
|
// Request timed out, bad luck, we'll try again later
|
||||||
|
@ -2669,8 +2669,8 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(bool Success, bool? Result)> ResolveEconomyBan() {
|
private async Task<(bool Success, bool? Result)> ResolveEconomyBan(CancellationToken cancellationToken = default) {
|
||||||
(_, string? steamApiKey) = await CachedApiKey.GetValue(ECacheFallback.SuccessPreviously).ConfigureAwait(false);
|
(_, string? steamApiKey) = await CachedApiKey.GetValue(ECacheFallback.SuccessPreviously, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(steamApiKey)) {
|
if (string.IsNullOrEmpty(steamApiKey)) {
|
||||||
return (false, null);
|
return (false, null);
|
||||||
|
@ -2680,7 +2680,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
byte connectionTimeout = ASF.GlobalConfig?.ConnectionTimeout ?? GlobalConfig.DefaultConnectionTimeout;
|
byte connectionTimeout = ASF.GlobalConfig?.ConnectionTimeout ?? GlobalConfig.DefaultConnectionTimeout;
|
||||||
|
|
||||||
for (byte i = 0; (i < connectionTimeout) && !Initialized && Bot.IsConnectedAndLoggedOn; i++) {
|
for (byte i = 0; (i < connectionTimeout) && !Initialized && Bot.IsConnectedAndLoggedOn; i++) {
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Initialized) {
|
if (!Initialized) {
|
||||||
|
@ -2699,7 +2699,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
|
|
||||||
for (byte i = 0; (i < WebBrowser.MaxTries) && (response == null); i++) {
|
for (byte i = 0; (i < WebBrowser.MaxTries) && (response == null); i++) {
|
||||||
if ((i > 0) && (WebLimiterDelay > 0)) {
|
if ((i > 0) && (WebLimiterDelay > 0)) {
|
||||||
await Task.Delay(WebLimiterDelay).ConfigureAwait(false);
|
await Task.Delay(WebLimiterDelay, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
using WebAPI.AsyncInterface service = Bot.SteamConfiguration.GetAsyncWebAPIInterface(SteamUserService);
|
using WebAPI.AsyncInterface service = Bot.SteamConfiguration.GetAsyncWebAPIInterface(SteamUserService);
|
||||||
|
@ -2711,7 +2711,7 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||||
WebAPI.DefaultBaseAddress,
|
WebAPI.DefaultBaseAddress,
|
||||||
|
|
||||||
// ReSharper disable once AccessToDisposedClosure
|
// ReSharper disable once AccessToDisposedClosure
|
||||||
async () => await service.CallAsync(HttpMethod.Get, "GetPlayerBans", args: arguments).ConfigureAwait(false)
|
async () => await service.CallAsync(HttpMethod.Get, "GetPlayerBans", args: arguments).ConfigureAwait(false), cancellationToken
|
||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
} catch (TaskCanceledException e) {
|
} catch (TaskCanceledException e) {
|
||||||
Bot.ArchiLogger.LogGenericDebuggingException(e);
|
Bot.ArchiLogger.LogGenericDebuggingException(e);
|
||||||
|
|
|
@ -375,7 +375,7 @@ public sealed class MobileAuthenticator : IDisposable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(bool Success, string? Result)> ResolveDeviceID() {
|
private async Task<(bool Success, string? Result)> ResolveDeviceID(CancellationToken cancellationToken = default) {
|
||||||
if (Bot == null) {
|
if (Bot == null) {
|
||||||
throw new InvalidOperationException(nameof(Bot));
|
throw new InvalidOperationException(nameof(Bot));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue