From 96d94931a3f0ab2aed8b25679b5eadc6d7273350 Mon Sep 17 00:00:00 2001 From: Scighost Date: Thu, 1 Aug 2024 13:11:54 +0800 Subject: [PATCH 1/2] adapt to new star rail gacha url #1002 --- src/Starward.Core/Gacha/GachaLogClient.cs | 4 ++-- src/Starward.Core/Gacha/Genshin/GenshinGachaClient.cs | 2 +- src/Starward.Core/Gacha/StarRail/StarRailGachaClient.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Starward.Core/Gacha/GachaLogClient.cs b/src/Starward.Core/Gacha/GachaLogClient.cs index bcd048560..9b24c17ab 100644 --- a/src/Starward.Core/Gacha/GachaLogClient.cs +++ b/src/Starward.Core/Gacha/GachaLogClient.cs @@ -32,8 +32,8 @@ public abstract class GachaLogClient protected const string WEB_CACHE_SR_PATH = @"StarRail_Data\webCaches\Cache\Cache_Data\data_2"; - protected const string API_PREFIX_SR_CN = "https://api-takumi.mihoyo.com/common/gacha_record/api/getGachaLog"; - protected const string API_PREFIX_SR_OS = "https://api-os-takumi.mihoyo.com/common/gacha_record/api/getGachaLog"; + protected const string API_PREFIX_SR_CN = "https://public-operation-hkrpg.mihoyo.com/common/gacha_record/api/getGachaLog"; + protected const string API_PREFIX_SR_OS = "https://public-operation-hkrpg-sg.hoyoverse.com/common/gacha_record/api/getGachaLog"; protected static ReadOnlySpan SPAN_WEB_PREFIX_SR_CN => "https://webstatic.mihoyo.com/hkrpg/event/e20211215gacha-v2/index.html"u8; protected static ReadOnlySpan SPAN_WEB_PREFIX_SR_OS => "https://gs.hoyoverse.com/hkrpg/event/e20211215gacha-v2/index.html"u8; diff --git a/src/Starward.Core/Gacha/Genshin/GenshinGachaClient.cs b/src/Starward.Core/Gacha/Genshin/GenshinGachaClient.cs index 4d9d61185..0ba18768d 100644 --- a/src/Starward.Core/Gacha/Genshin/GenshinGachaClient.cs +++ b/src/Starward.Core/Gacha/Genshin/GenshinGachaClient.cs @@ -44,7 +44,7 @@ protected override string GetGachaUrlPrefix(string gachaUrl, string? lang = null } return gachaUrl; } - match = Regex.Match(gachaUrl, @"(https://hk4e-api[!-z]+)"); + match = Regex.Match(gachaUrl, @"(https://public-operation-hk4e[!-z]+)"); if (match.Success) { gachaUrl = match.Groups[1].Value; diff --git a/src/Starward.Core/Gacha/StarRail/StarRailGachaClient.cs b/src/Starward.Core/Gacha/StarRail/StarRailGachaClient.cs index 60771c2ed..45240d9bb 100644 --- a/src/Starward.Core/Gacha/StarRail/StarRailGachaClient.cs +++ b/src/Starward.Core/Gacha/StarRail/StarRailGachaClient.cs @@ -46,7 +46,7 @@ protected override string GetGachaUrlPrefix(string gachaUrl, string? lang = null } return gachaUrl; } - match = Regex.Match(gachaUrl, @"(https://api[!-z]+)"); + match = Regex.Match(gachaUrl, @"(https://public-operation-hkrpg[!-z]+)"); if (match.Success) { gachaUrl = match.Groups[1].Value; From bf071c4c982bf77ab04e3863a3d7d7d998dff1ad Mon Sep 17 00:00:00 2001 From: Scighost Date: Mon, 5 Aug 2024 20:03:45 +0800 Subject: [PATCH 2/2] improve downloading rate limiter --- .../Controls/InstallGameController.xaml.cs | 1 - .../Pages/Setting/DownloadSettingPage.xaml.cs | 2 +- .../Services/Download/InstallGameManager.cs | 37 ++++++++------- .../Services/Download/InstallGameService.cs | 45 ++++++++++--------- src/Starward/Starward.csproj | 1 + 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/Starward/Controls/InstallGameController.xaml.cs b/src/Starward/Controls/InstallGameController.xaml.cs index e4613bb6b..be2a8b486 100644 --- a/src/Starward/Controls/InstallGameController.xaml.cs +++ b/src/Starward/Controls/InstallGameController.xaml.cs @@ -134,7 +134,6 @@ private void UpdateSpeedState() long totalBytes = 0; long finishedBytes = 0; bool determinate = false; - _installGameManager.UpdateSpeedState(); foreach (var model in InstallServices) { model.UpdateState(); diff --git a/src/Starward/Pages/Setting/DownloadSettingPage.xaml.cs b/src/Starward/Pages/Setting/DownloadSettingPage.xaml.cs index 2fd9c67ca..c4fb06153 100644 --- a/src/Starward/Pages/Setting/DownloadSettingPage.xaml.cs +++ b/src/Starward/Pages/Setting/DownloadSettingPage.xaml.cs @@ -69,7 +69,7 @@ partial void OnDefaultInstallPathChanged(string? value) private int speedLimit = AppConfig.SpeedLimitKBPerSecond; partial void OnSpeedLimitChanged(int value) { - InstallGameManager.SpeedLimitBytesPerSecond = value == 0 ? long.MaxValue : value * 1024; + InstallGameManager.SetRateLimit(value * 1024); AppConfig.SpeedLimitKBPerSecond = value; } diff --git a/src/Starward/Services/Download/InstallGameManager.cs b/src/Starward/Services/Download/InstallGameManager.cs index a189dfb77..a4e47fd72 100644 --- a/src/Starward/Services/Download/InstallGameManager.cs +++ b/src/Starward/Services/Download/InstallGameManager.cs @@ -4,9 +4,8 @@ using Starward.Messages; using System; using System.Collections.Concurrent; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Threading; +using System.Threading.RateLimiting; namespace Starward.Services.Download; @@ -20,8 +19,7 @@ internal class InstallGameManager private InstallGameManager() { _services = new(); - long speed = AppConfig.SpeedLimitKBPerSecond * 1024; - SpeedLimitBytesPerSecond = speed == 0 ? long.MaxValue : speed; + SetRateLimit(AppConfig.SpeedLimitKBPerSecond * 1024); } @@ -30,29 +28,34 @@ private InstallGameManager() - public static long DownloadBytesInSecond; + public static TokenBucketRateLimiter RateLimiter { get; private set; } - public static long SpeedLimitBytesPerSecond { get; set; } - - public static bool IsExceedSpeedLimit => Interlocked.Read(ref DownloadBytesInSecond) >= SpeedLimitBytesPerSecond; - - - private long _lastTimeStamp; - - - public void UpdateSpeedState() + public static void SetRateLimit(int bytesPerSecond) { - long ts = Stopwatch.GetTimestamp(); - if (ts - _lastTimeStamp >= Stopwatch.Frequency) + if (bytesPerSecond <= 0) { - DownloadBytesInSecond = 0; + bytesPerSecond = int.MaxValue; } + else if (bytesPerSecond < (1 << 14)) + { + bytesPerSecond = 1 << 14; + } + RateLimiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions + { + TokenLimit = bytesPerSecond, + ReplenishmentPeriod = TimeSpan.FromSeconds(1), + TokensPerPeriod = bytesPerSecond, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + AutoReplenishment = true + }); } + + public event EventHandler InstallTaskAdded; diff --git a/src/Starward/Services/Download/InstallGameService.cs b/src/Starward/Services/Download/InstallGameService.cs index e9ccd8d4e..4ddb03b4c 100644 --- a/src/Starward/Services/Download/InstallGameService.cs +++ b/src/Starward/Services/Download/InstallGameService.cs @@ -21,6 +21,7 @@ using System.Text; using System.Text.Json.Nodes; using System.Threading; +using System.Threading.RateLimiting; using System.Threading.Tasks; using Vanara.PInvoke; @@ -245,7 +246,7 @@ await Task.Run(() => { File.SetAttributes(file, FileAttributes.Normal); } - }); + }).ConfigureAwait(false); CurrentGameBiz = gameBiz; _installPath = installPath; _initialized = true; @@ -714,7 +715,7 @@ protected void StartTask(InstallGameState state) _cancellationTokenSource = new CancellationTokenSource(); for (int i = 0; i < Environment.ProcessorCount; i++) { - _ = ExecuteTaskItemAsync(_cancellationTokenSource.Token); + _ = ExecuteTaskItemAsync(_cancellationTokenSource.Token).ConfigureAwait(false); } } @@ -981,7 +982,7 @@ protected async Task CleanGameDeprecatedFilesAsync() { File.Delete(file); } - foreach (var file in await _hoYoPlayService.GetGameDeprecatedFilesAsync(CurrentGameBiz)) + foreach (var file in await _hoYoPlayService.GetGameDeprecatedFilesAsync(CurrentGameBiz).ConfigureAwait(false)) { var path = Path.Combine(_installPath, file.Name); if (File.Exists(path)) @@ -989,7 +990,7 @@ protected async Task CleanGameDeprecatedFilesAsync() File.Delete(path); } } - await WriteConfigFileAsync(); + await WriteConfigFileAsync().ConfigureAwait(false); CurrentTaskFinished(); } @@ -1118,19 +1119,19 @@ protected async Task ExecuteTaskItemAsync(CancellationToken cancellationToken = case InstallGameItemType.None: break; case InstallGameItemType.Download: - await DownloadItemAsync(item, cancellationToken); + await DownloadItemAsync(item, cancellationToken).ConfigureAwait(false); Interlocked.Increment(ref _finishCount); break; case InstallGameItemType.Verify: - await VerifyItemAsync(item, cancellationToken); + await VerifyItemAsync(item, cancellationToken).ConfigureAwait(false); Interlocked.Increment(ref _finishCount); break; case InstallGameItemType.Decompress: - await DecompressItemAsync(item, cancellationToken); + await DecompressItemAsync(item, cancellationToken).ConfigureAwait(false); Interlocked.Increment(ref _finishCount); break; case InstallGameItemType.HardLink: - await HardLinkItemAsync(item, cancellationToken); + await HardLinkItemAsync(item, cancellationToken).ConfigureAwait(false); Interlocked.Increment(ref _finishCount); break; default: @@ -1141,7 +1142,7 @@ protected async Task ExecuteTaskItemAsync(CancellationToken cancellationToken = { // network error _installItemQueue.Enqueue(item); - await Task.Delay(1000, CancellationToken.None); + await Task.Delay(1000, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) when (ex is OperationCanceledException or TaskCanceledException) { @@ -1171,7 +1172,7 @@ protected async Task ExecuteTaskItemAsync(CancellationToken cancellationToken = protected async Task DownloadItemAsync(InstallGameItem item, CancellationToken cancellationToken = default) { - const int BUFFER_SIZE = 1 << 14; + const int BUFFER_SIZE = 1 << 10; string file = item.Path; string file_tmp = item.Path + "_tmp"; string file_target; @@ -1203,14 +1204,14 @@ protected async Task DownloadItemAsync(InstallGameItem item, CancellationToken c int length; while ((length = await hs.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0) { - await fs.WriteAsync(buffer.AsMemory(0, length), cancellationToken).ConfigureAwait(false); - Interlocked.Add(ref _finishBytes, length); - Interlocked.Add(ref InstallGameManager.DownloadBytesInSecond, length); - if (InstallGameManager.IsExceedSpeedLimit) + RateLimitLease lease = await InstallGameManager.RateLimiter.AcquireAsync(length, cancellationToken).ConfigureAwait(false); + while (!lease.IsAcquired) { - long t = Stopwatch.GetTimestamp() / (Stopwatch.Frequency / 1000) % 1000; - await Task.Delay((int)(1000 - t), cancellationToken); + await Task.Delay(1, cancellationToken).ConfigureAwait(false); + lease = await InstallGameManager.RateLimiter.AcquireAsync(length, cancellationToken).ConfigureAwait(false); } + await fs.WriteAsync(buffer.AsMemory(0, length), cancellationToken).ConfigureAwait(false); + Interlocked.Add(ref _finishBytes, length); } } } @@ -1246,7 +1247,7 @@ protected async Task VerifyItemAsync(InstallGameItem item, CancellationToken can var buffer = ArrayPool.Shared.Rent(BUFFER_SIZE); try { - await _verifyGlobalSemaphore.WaitAsync(cancellationToken); + await _verifyGlobalSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); using var fs = File.OpenRead(file_target); if (fs.Length != item.Size) { @@ -1293,7 +1294,7 @@ protected async Task DecompressItemAsync(InstallGameItem item, CancellationToken { try { - await _decompressSemaphore.WaitAsync(); + await _decompressSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); using var fs = new FileSliceStream(item.DecompressPackageFiles); if (item.DecompressPackageFiles[0].Contains(".7z", StringComparison.CurrentCultureIgnoreCase)) { @@ -1310,7 +1311,7 @@ await Task.Run(() => }; extra.Extract(item.DecompressPath, true); _finishBytes += fs.Length - sum; - }).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); } else { @@ -1335,8 +1336,8 @@ await Task.Run(async () => } } _finishBytes += fs.Length - sum; - await ApplyDiffFilesAsync(item.DecompressPath); - }).ConfigureAwait(false); + await ApplyDiffFilesAsync(item.DecompressPath).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); } fs.Dispose(); foreach (var file in item.DecompressPackageFiles) @@ -1440,7 +1441,7 @@ protected async Task HardLinkItemAsync(InstallGameItem item, CancellationToken c var buffer = ArrayPool.Shared.Rent(BUFFER_SIZE); try { - await _verifyGlobalSemaphore.WaitAsync(cancellationToken); + await _verifyGlobalSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); using var fs = File.OpenRead(file_source); if (fs.Length != item.Size) { diff --git a/src/Starward/Starward.csproj b/src/Starward/Starward.csproj index cffad5a0f..7e2716f00 100644 --- a/src/Starward/Starward.csproj +++ b/src/Starward/Starward.csproj @@ -43,6 +43,7 @@ +