From 9cea07d6be9afa99406a79537a567a523fbcdc51 Mon Sep 17 00:00:00 2001 From: "j.foucher" Date: Sat, 2 May 2026 19:15:27 +0200 Subject: [PATCH] Downloads: parallel multi-segment, sparse pre-alloc, faster SHA-256, URL auto-refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DownloadManager - Parallel multi-segment download (default 8 connections, configurable up to 16) with per-segment Range requests. Bypasses OVH/Apache per-connection bandwidth throttling — typical speed-up ×4 to ×8 vs single connection. - Reporter task on a dedicated Task with Interlocked aggregate counter (no lock contention with workers). Reports speed/ETA every 250ms even mid-download, fixes the "speed only shows at install transition" bug. - Sparse file pre-allocation via FSCTL_SET_SPARSE before SetLength: no zero-fill, no SeManageVolumePrivilege, instant on any disk type. Removes 5-30s of preparation lag on HDD. - HEAD probe skipped (trust manifest size, signed Ed25519). Falls back to single-segment if first segment returns 200 instead of 206. - Resume URL comparison fixed: ignores HMAC querystring (?exp=&sig=) which changes per request, compares only host+path. Previously every resume started fresh because the old URL never matched the freshly signed one. - Auto-refresh signed URL on 403/410 mid-DL: SemaphoreSlim with 5s debounce so 8 simultaneous segment expirations trigger a single /api/download-url/ call. Slow-connection users (1 Mbps, 30+ hours for 14 GB) keep downloading transparently across multiple TTL cycles. - Per-version hashAlgorithm:none in manifest skips client SHA-256 verification (still relying on Ed25519 manifest signature + HMAC URL). - DangerButton style (red) added to Theme.xaml for the new cancel-resume action. IntegrityService - 16 MiB buffer (was 1 MiB), FileOptions.SequentialScan + Asynchronous, IncrementalHash (uses SHA-NI hardware extensions on .NET 8), double-buffering to overlap CPU and I/O. Typical 14 GB hash verification: 60-180s → 15-40s. HttpClient - MaxConnectionsPerServer=16, EnableMultipleHttp2Connections, HTTP/2 preferred, AutomaticDecompression=None (ZIPs are already compressed), 5min pooled connection lifetime. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/PSLauncher.App/App.xaml.cs | 20 +- src/PSLauncher.App/Resources/Theme.xaml | 33 ++ .../Downloads/DownloadManager.cs | 560 ++++++++++++++++-- .../Downloads/IDownloadManager.cs | 29 +- .../Integrity/IntegrityService.cs | 63 +- src/PSLauncher.Models/DownloadState.cs | 22 +- src/PSLauncher.Models/RemoteManifest.cs | 17 + 7 files changed, 667 insertions(+), 77 deletions(-) diff --git a/src/PSLauncher.App/App.xaml.cs b/src/PSLauncher.App/App.xaml.cs index 7a0f1eb..43c1093 100644 --- a/src/PSLauncher.App/App.xaml.cs +++ b/src/PSLauncher.App/App.xaml.cs @@ -108,13 +108,25 @@ public partial class App : Application services.AddSingleton(sp => { - var http = new HttpClient(new SocketsHttpHandler + // Handler tuné pour les gros téléchargements parallèles : + // - MaxConnectionsPerServer=16 pour autoriser le multi-segment (8 par défaut). + // - AutomaticDecompression sur l'API JSON uniquement (None ici car les builds + // sont des ZIPs déjà compressés ; éviter la CPU+RAM gaspillée par un éventuel + // wrapping gzip côté serveur). + // - PooledConnectionLifetime court pour éviter qu'OVH ferme nos sockets sous nous. + var handler = new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(5), - AutomaticDecompression = System.Net.DecompressionMethods.All - }) + PooledConnectionIdleTimeout = TimeSpan.FromSeconds(60), + MaxConnectionsPerServer = 16, + EnableMultipleHttp2Connections = true, + AutomaticDecompression = System.Net.DecompressionMethods.None, + }; + var http = new HttpClient(handler) { - Timeout = Timeout.InfiniteTimeSpan + Timeout = Timeout.InfiniteTimeSpan, + DefaultRequestVersion = System.Net.HttpVersion.Version20, + DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower, }; http.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("PSLauncher", "0.5")); return http; diff --git a/src/PSLauncher.App/Resources/Theme.xaml b/src/PSLauncher.App/Resources/Theme.xaml index 260f084..dde54d5 100644 --- a/src/PSLauncher.App/Resources/Theme.xaml +++ b/src/PSLauncher.App/Resources/Theme.xaml @@ -135,6 +135,39 @@ + + +