From ad369418520ad9d1e72573578edffba780774a5b Mon Sep 17 00:00:00 2001 From: Bagus Nur Listiyono Date: Wed, 25 Dec 2024 05:56:01 +0700 Subject: [PATCH] [FallbackCDNUtil] Implement retry mechanism in GetURLHttpResponse --- .../Classes/Interfaces/Class/ProgressBase.cs | 4 +- .../RegionManagement/FallbackCDNUtil.cs | 56 +++++++++++++++---- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs index e1c19d575..00098d2d4 100644 --- a/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs +++ b/CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs @@ -751,7 +751,9 @@ protected async ValueTask FetchBilibiliSDK(CancellationToken token) // Get the URL and get the remote stream of the zip file // Also buffer the stream to memory string? url = _gameVersionManager.GameAPIProp.data.sdk.path; - using HttpResponseMessage httpResponse = await FallbackCDNUtil.GetURLHttpResponse(url, token); + if (url == null) throw new NullReferenceException(); + + HttpResponseMessage httpResponse = await FallbackCDNUtil.GetURLHttpResponse(url, token); await using BridgedNetworkStream httpStream = await FallbackCDNUtil.GetHttpStreamFromResponse(httpResponse, token); await using MemoryStream bufferedStream = await BufferSourceStreamToMemoryStream(httpStream, token); using ZipArchive zip = new ZipArchive(bufferedStream, ZipArchiveMode.Read, true); diff --git a/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs b/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs index ded87fafa..26b04d17c 100644 --- a/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs +++ b/CollapseLauncher/Classes/RegionManagement/FallbackCDNUtil.cs @@ -288,7 +288,7 @@ private static async Task TryGetCDNContent(CDNURLProperty { try { - // Get the URL Status then return boolean and and URLStatus + // Get the URL Status then return boolean and URLStatus CDNUtilHTTPStatus urlStatus = await TryGetURLStatus(cdnProp, relativeURL, token, isForceUncompressRequest); // If URL status is false, then return null @@ -433,14 +433,14 @@ private static async ValueTask TryGetURLStatus(CDNURLProperty LogWriteLine($"Getting CDN Content from: {cdnProp.Name} at URL: {absoluteURL}", LogType.Default, true); // Try check the status of the URL - HttpResponseMessage responseMessage = await GetURLHttpResponse(absoluteURL, token, isUncompressRequest); + var httpResponse = await GetURLHttpResponse(absoluteURL, token, isUncompressRequest); // If it's not a successful code, log the information - if (!responseMessage.IsSuccessStatusCode) - LogWriteLine($"CDN content from: {cdnProp.Name} (prefix: {cdnProp.URLPrefix}) (relPath: {relativeURL}) has returned an error code: {responseMessage.StatusCode} ({(int)responseMessage.StatusCode})", LogType.Error, true); + if (!httpResponse.IsSuccessStatusCode) + LogWriteLine($"CDN content from: {cdnProp.Name} (prefix: {cdnProp.URLPrefix}) (relPath: {relativeURL}) has returned an error code: {httpResponse.StatusCode} ({(int)httpResponse.StatusCode})", LogType.Error, true); // Then return the status code - return new CDNUtilHTTPStatus(responseMessage); + return new CDNUtilHTTPStatus(httpResponse); } catch (Exception ex) { @@ -465,12 +465,48 @@ public static CDNURLProperty GetPreferredCDN() // Return the CDN property as per index return CDNList[cdnIndex]; } + + #nullable enable + public static async Task GetURLHttpResponse(string Url, + CancellationToken token, + bool isForceUncompressRequest = false, + int maxRetries = 3, + int delayMilliseconds = 1000) + { + HttpResponseMessage hR; + int attempt = 0; - public static async Task GetURLHttpResponse(string URL, CancellationToken token, bool isForceUncompressRequest = false) - => isForceUncompressRequest ? await _clientNoCompression.GetURLHttpResponse(URL, HttpMethod.Get, token) - : await _client.GetURLHttpResponse(URL, HttpMethod.Get, token); + while (attempt < maxRetries) + { + try + { + if (isForceUncompressRequest) + { + hR = await _clientNoCompression.GetURLHttpResponse(Url, HttpMethod.Get, token); + } + else + { + hR = await _client.GetURLHttpResponse(Url, HttpMethod.Get, token); + } + + return hR; + } + catch (Exception ex) + { + LogWriteLine("Failed to get URL response from: " + Url + "\r\n" + ex, LogType.Error, true); + if (attempt >= maxRetries - 1) + { + throw; + } + } + + attempt++; + await Task.Delay(delayMilliseconds, token); + } + + return new HttpResponseMessage(HttpStatusCode.InternalServerError); + } -#nullable enable public static async Task DownloadAsJSONType(string? URL, JsonTypeInfo typeInfo, CancellationToken token) => await _client.GetFromJsonAsync(URL, typeInfo, token); @@ -489,7 +525,7 @@ public static async ValueTask GetURLStatusCode(this HttpClient client public static async Task GetHttpStreamFromResponse(string URL, CancellationToken token) { - HttpResponseMessage responseMsg = await GetURLHttpResponse(URL, token); + var responseMsg = await GetURLHttpResponse(URL, token); return await GetHttpStreamFromResponse(responseMsg, token); }