From 78cbbede9d6cbe4e05d1f808252df90826f83a37 Mon Sep 17 00:00:00 2001 From: lincube Date: Thu, 16 Jul 2026 10:23:55 +0900 Subject: [PATCH] =?UTF-8?q?feat.=E4=BE=9D=E6=97=A7=E4=BF=AE=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E7=B3=BB=E7=BB=9F=E7=9A=84=E4=B8=80=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Plonds/PlondsHttpClientFactory.cs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 LanMountainDesktop/Services/Plonds/PlondsHttpClientFactory.cs diff --git a/LanMountainDesktop/Services/Plonds/PlondsHttpClientFactory.cs b/LanMountainDesktop/Services/Plonds/PlondsHttpClientFactory.cs new file mode 100644 index 0000000..7c7acc2 --- /dev/null +++ b/LanMountainDesktop/Services/Plonds/PlondsHttpClientFactory.cs @@ -0,0 +1,50 @@ +using System.Net; +using System.Net.Http.Headers; + +namespace LanMountainDesktop.Services.Plonds; + +/// +/// Shared HTTP client for PLONDS manifest and package downloads. +/// CDN buckets (e.g. rains3) commonly reject anonymous clients without a User-Agent. +/// +internal static class PlondsHttpClientFactory +{ + public static HttpClient Create(TimeSpan? timeout = null) + { + var handler = new SocketsHttpHandler + { + AutomaticDecompression = DecompressionMethods.All, + AllowAutoRedirect = true, + PooledConnectionLifetime = TimeSpan.FromMinutes(5) + }; + + var client = new HttpClient(handler) + { + Timeout = timeout ?? TimeSpan.FromMinutes(10) + }; + + client.DefaultRequestHeaders.UserAgent.Clear(); + client.DefaultRequestHeaders.UserAgent.Add( + new ProductInfoHeaderValue("LanMountainDesktop", GetProductVersion())); + client.DefaultRequestHeaders.UserAgent.Add( + new ProductInfoHeaderValue("(+https://github.com/wwiinnddyy/LanMountainDesktop)")); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream")); + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); + + return client; + } + + private static string GetProductVersion() + { + try + { + var version = Shared.Contracts.Launcher.AppVersionProvider.ResolveForCurrentProcess().Version; + return string.IsNullOrWhiteSpace(version) ? "1.0" : version.Trim(); + } + catch + { + return "1.0"; + } + } +}