diff --git a/SteamPrefill/Extensions/MiscExtensions.cs b/SteamPrefill/Extensions/MiscExtensions.cs index 39b3f169..dc0e14ba 100644 --- a/SteamPrefill/Extensions/MiscExtensions.cs +++ b/SteamPrefill/Extensions/MiscExtensions.cs @@ -2,9 +2,9 @@ { public static class MiscExtensions { - public static ConcurrentQueue ToConcurrentBag(this IOrderedEnumerable list) + public static bool Empty(this IEnumerable enumerable) { - return new ConcurrentQueue(list); + return !enumerable.Any(); } [SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is required by Steam")] diff --git a/SteamPrefill/Handlers/DownloadHandler.cs b/SteamPrefill/Handlers/DownloadHandler.cs index 66785444..066a380b 100644 --- a/SteamPrefill/Handlers/DownloadHandler.cs +++ b/SteamPrefill/Handlers/DownloadHandler.cs @@ -83,6 +83,7 @@ private async Task> AttemptDownloadAsync(ProgressCo // Running as many requests as possible in parallel, evenly distributed across 3 cdns var cdnServers = _cdnPool.TakeConnections(3).ToList(); + var connCount = cdnServers.Count; await Parallel.ForEachAsync(requestsToDownload, new ParallelOptions { MaxDegreeOfParallelism = 50 }, async (request, _) => { var buffer = new byte[4096]; @@ -90,8 +91,8 @@ private async Task> AttemptDownloadAsync(ProgressCo { var url = ZString.Format("http://{0}/depot/{1}/chunk/{2}", _lancacheAddress, request.DepotId, request.ChunkId); using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); - // Evenly distributes requests across CDNs - requestMessage.Headers.Host = cdnServers[request.ChunkNum % 3].Host; + // Evenly distributes requests the available CDNs + requestMessage.Headers.Host = cdnServers[request.ChunkNum % connCount].Host; var response = await _client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead); using Stream responseStream = await response.Content.ReadAsStreamAsync(); diff --git a/SteamPrefill/Handlers/Steam/CdnPool.cs b/SteamPrefill/Handlers/Steam/CdnPool.cs index 80a62866..86a86397 100644 --- a/SteamPrefill/Handlers/Steam/CdnPool.cs +++ b/SteamPrefill/Handlers/Steam/CdnPool.cs @@ -51,7 +51,7 @@ await _ansiConsole.StatusSpinner().StartAsync("Getting available CDNs", async _ } }); - if (!_availableServerEndpoints.Any()) + if (_availableServerEndpoints.Empty()) { throw new CdnExhaustionException("Unable to get available CDN servers from Steam!"); } @@ -67,21 +67,33 @@ await _ansiConsole.StatusSpinner().StartAsync("Getting available CDNs", async _ /// If no servers are available for use, this exception will be thrown. public Server TakeConnection() { - if (!_availableServerEndpoints.Any()) + if (_availableServerEndpoints.Empty()) { throw new CdnExhaustionException("Available Steam CDN servers exhausted! No more servers available to retry! Try again in a few minutes"); } + var server = _availableServerEndpoints.First(); _availableServerEndpoints.RemoveAt(0); return server; } - public IEnumerable TakeConnections(int connectionCount) + /// + /// Attempts to take multiple available connections from the pool. + /// If the desired number of connections is not available, then the remaining available will be returned. + /// Once finished with the connection, it should be returned to the pool using + /// + /// The desired number of servers to be returned. If the desired amount is not available, the remaining servers will be returned + /// If no servers are available for use, this exception will be thrown. + public List TakeConnections(int targetCount) { - for (int i = 0; i < connectionCount; i++) + if (_availableServerEndpoints.Empty()) { - yield return TakeConnection(); + throw new CdnExhaustionException("Available Steam CDN servers exhausted! No more servers available to retry! Try again in a few minutes"); } + + var connections = _availableServerEndpoints.Take(targetCount).ToList(); + _availableServerEndpoints.RemoveRange(0, connections.Count); + return connections; } ///