diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs index 2a2be7377..af2d57ff0 100644 --- a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs +++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs @@ -1149,9 +1149,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable { return; } -#pragma warning disable CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose using (await Bot.Actions.GetTradingLock().ConfigureAwait(false)) { -#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose tradesSent = await MatchActively(response.Value.Users, assetsForMatching, acceptedMatchableTypes).ConfigureAwait(false); } diff --git a/ArchiSteamFarm/Collections/ConcurrentHashSet.cs b/ArchiSteamFarm/Collections/ConcurrentHashSet.cs index 0117b1ecb..b859f6ba9 100644 --- a/ArchiSteamFarm/Collections/ConcurrentHashSet.cs +++ b/ArchiSteamFarm/Collections/ConcurrentHashSet.cs @@ -110,7 +110,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public void IntersectWith(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); foreach (T item in this.Where(item => !otherSet.Contains(item))) { Remove(item); @@ -120,7 +120,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public bool IsProperSubsetOf(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); return (otherSet.Count > Count) && IsSubsetOf(otherSet); } @@ -128,7 +128,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public bool IsProperSupersetOf(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); return (otherSet.Count < Count) && IsSupersetOf(otherSet); } @@ -136,7 +136,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public bool IsSubsetOf(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); return this.All(otherSet.Contains); } @@ -144,7 +144,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public bool IsSupersetOf(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); return otherSet.All(Contains); } @@ -152,7 +152,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public bool Overlaps(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); return otherSet.Any(Contains); } @@ -172,7 +172,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public bool SetEquals(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); return (otherSet.Count == Count) && otherSet.All(Contains); } @@ -180,7 +180,7 @@ public sealed class ConcurrentHashSet : IReadOnlySet, ISet where T : no public void SymmetricExceptWith(IEnumerable other) { ArgumentNullException.ThrowIfNull(other); - ISet otherSet = other as ISet ?? other.ToHashSet(); + IReadOnlySet otherSet = other as IReadOnlySet ?? other.ToHashSet(); HashSet removed = []; foreach (T item in otherSet.Where(Contains)) { diff --git a/ArchiSteamFarm/Core/Utilities.cs b/ArchiSteamFarm/Core/Utilities.cs index c6220d923..bbd909407 100644 --- a/ArchiSteamFarm/Core/Utilities.cs +++ b/ArchiSteamFarm/Core/Utilities.cs @@ -288,7 +288,7 @@ public static class Utilities { ASF.ArchiLogger.LogGenericDebug($"{fileName} {progressPercentage}%..."); } - internal static (bool IsWeak, string? Reason) TestPasswordStrength(string password, ISet? additionallyForbiddenPhrases = null) { + internal static (bool IsWeak, string? Reason) TestPasswordStrength(string password, IEnumerable? additionallyForbiddenPhrases = null) { ArgumentException.ThrowIfNullOrEmpty(password); HashSet forbiddenPhrases = ForbiddenPasswordPhrases.ToHashSet(StringComparer.InvariantCultureIgnoreCase); @@ -514,9 +514,7 @@ public static class Utilities { private static bool RelativeDirectoryStartsWith(string directory, params string[] prefixes) { ArgumentException.ThrowIfNullOrEmpty(directory); -#pragma warning disable CA1508 // False positive, params could be null when explicitly set if ((prefixes == null) || (prefixes.Length == 0)) { -#pragma warning restore CA1508 // False positive, params could be null when explicitly set throw new ArgumentNullException(nameof(prefixes)); } diff --git a/ArchiSteamFarm/IPC/Controllers/Api/IPCBansController.cs b/ArchiSteamFarm/IPC/Controllers/Api/IPCBansController.cs index 6daa2e46a..4d21e0f50 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/IPCBansController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/IPCBansController.cs @@ -72,6 +72,6 @@ public sealed class IPCBansController : ArchiController { /// Gets all IP addresses currently blocked by ASFs IPC module /// [HttpGet] - [ProducesResponseType>>((int) HttpStatusCode.OK)] - public ActionResult>> Get() => Ok(new GenericResponse>(ApiAuthenticationMiddleware.GetCurrentlyBannedIPs().Select(static ip => ip.ToString()).ToHashSet())); + [ProducesResponseType>>((int) HttpStatusCode.OK)] + public ActionResult>> Get() => Ok(new GenericResponse>(ApiAuthenticationMiddleware.GetCurrentlyBannedIPs().Select(static ip => ip.ToString()).ToHashSet())); } diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 764912e40..3891486c3 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -488,7 +488,7 @@ internal static class Program { // Stop all the active bots so they can disconnect cleanly if (Bot.Bots?.Count > 0) { // Stop() function can block due to SK2 sockets, don't forget a maximum delay - await Task.WhenAny(Utilities.InParallel(Bot.Bots.Values.Select(static bot => Task.Run(() => bot.Stop(true)))), Task.Delay(Bot.Bots.Count * WebBrowser.MaxTries * 1000)).ConfigureAwait(false); + await Task.WhenAny(Utilities.InParallel(Bot.Bots.Values.Select(static bot => Task.Run(() => bot.Stop(true)))), Task.Delay((Bot.Bots.Count + WebBrowser.MaxTries) * 1000)).ConfigureAwait(false); // Extra second for Steam requests to go through await Task.Delay(1000).ConfigureAwait(false); diff --git a/ArchiSteamFarm/Steam/Bot.cs b/ArchiSteamFarm/Steam/Bot.cs index 62447825d..1e45c7894 100644 --- a/ArchiSteamFarm/Steam/Bot.cs +++ b/ArchiSteamFarm/Steam/Bot.cs @@ -622,17 +622,22 @@ public sealed class Bot : IAsyncDisposable, IDisposable { Regex regex; try { -#pragma warning disable CA3012 - regex = new Regex(botsPattern, botsRegex); -#pragma warning restore CA3012 +#pragma warning disable CA3012 // We're aware of a potential denial of service here, this is why we limit maximum matching time to a sane value + regex = new Regex(botsPattern, botsRegex, TimeSpan.FromSeconds(1)); +#pragma warning restore CA3012 // We're aware of a potential denial of service here, this is why we limit maximum matching time to a sane value } catch (ArgumentException e) { ASF.ArchiLogger.LogGenericWarningException(e); return null; } - IEnumerable regexMatches = Bots.Where(kvp => regex.IsMatch(kvp.Key)).Select(static kvp => kvp.Value); - result.UnionWith(regexMatches); + try { + IEnumerable regexMatches = Bots.Where(kvp => regex.IsMatch(kvp.Key)).Select(static kvp => kvp.Value); + + result.UnionWith(regexMatches); + } catch (RegexMatchTimeoutException e) { + ASF.ArchiLogger.LogGenericException(e); + } continue; } @@ -857,9 +862,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable { throw new ArgumentNullException(nameof(appIDs)); } -#pragma warning disable CA1508 // False positive, not every IReadOnlyCollection is ISet, and this is public API - ISet uniqueAppIDs = appIDs as ISet ?? appIDs.ToHashSet(); -#pragma warning restore CA1508 // False positive, not every IReadOnlyCollection is ISet, and this is public API + IReadOnlySet uniqueAppIDs = appIDs as IReadOnlySet ?? appIDs.ToHashSet(); switch (ASF.GlobalConfig?.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: @@ -3114,6 +3117,14 @@ public sealed class Bot : IAsyncDisposable, IDisposable { Task refreshTask = ASF.GlobalDatabase.RefreshPackages(this, packagesToRefresh); + try { + await refreshTask.WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false); + } catch (TimeoutException) { + ArchiLogger.LogGenericInfo(Strings.BotRefreshingPackagesData); + + displayFinish = true; + } + if (await Task.WhenAny(refreshTask, Task.Delay(5000)).ConfigureAwait(false) != refreshTask) { ArchiLogger.LogGenericInfo(Strings.BotRefreshingPackagesData); diff --git a/ArchiSteamFarm/Steam/Integration/ArchiHandler.cs b/ArchiSteamFarm/Steam/Integration/ArchiHandler.cs index 4a93fa94c..7d2a7bb83 100644 --- a/ArchiSteamFarm/Steam/Integration/ArchiHandler.cs +++ b/ArchiSteamFarm/Steam/Integration/ArchiHandler.cs @@ -860,9 +860,7 @@ public sealed class ArchiHandler : ClientMsgHandler { } if (gameIDs.Count > 0) { -#pragma warning disable CA1508 // False positive, not every IReadOnlyCollection is ISet - ISet uniqueGameIDs = gameIDs as ISet ?? gameIDs.ToHashSet(); -#pragma warning restore CA1508 // False positive, not every IReadOnlyCollection is ISet + IReadOnlySet uniqueGameIDs = gameIDs as IReadOnlySet ?? gameIDs.ToHashSet(); foreach (uint gameID in uniqueGameIDs.Where(static gameID => gameID > 0)) { if (request.Body.games_played.Count >= MaxGamesPlayedConcurrently) { diff --git a/ArchiSteamFarm/Web/WebBrowser.cs b/ArchiSteamFarm/Web/WebBrowser.cs index ec5b38701..89fc5fea1 100644 --- a/ArchiSteamFarm/Web/WebBrowser.cs +++ b/ArchiSteamFarm/Web/WebBrowser.cs @@ -161,9 +161,7 @@ public sealed class WebBrowser : IDisposable { progressReporter?.Report(0); -#pragma warning disable CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose MemoryStream ms = new((int) response.Length); -#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose await using (ms.ConfigureAwait(false)) { byte batch = 0;