using System; using System.Net.Http; using System.Net.Http.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; namespace PalladiumWallet.Core.Net; /// A GitHub release newer than the running app. public sealed record LatestRelease(string Tag, string HtmlUrl); /// /// Checks the latest GitHub release for the project against the running app version. /// Best-effort only: any network/parse failure or an up-to-date app both resolve to null, /// so callers never need to distinguish "no update" from "couldn't check". /// public static class UpdateChecker { private const string ReleasesApiUrl = "https://api.github.com/repos/davide3011/PalladiumWallet/releases/latest"; private sealed class GitHubReleaseResponse { [JsonPropertyName("tag_name")] public string? TagName { get; set; } [JsonPropertyName("html_url")] public string? HtmlUrl { get; set; } } public static Task CheckAsync(string currentVersion, CancellationToken ct = default) => CheckAsync(currentVersion, handler: null, ct); /// Test seam: replaces the real HTTP transport. internal static async Task CheckAsync(string currentVersion, HttpMessageHandler? handler, CancellationToken ct = default) { try { using var http = handler is null ? new HttpClient() : new HttpClient(handler, disposeHandler: false); http.Timeout = TimeSpan.FromSeconds(10); http.DefaultRequestHeaders.UserAgent.ParseAdd("PalladiumWallet"); using var response = await http.GetAsync(ReleasesApiUrl, ct).ConfigureAwait(false); if (!response.IsSuccessStatusCode) return null; var release = await response.Content .ReadFromJsonAsync(ct) .ConfigureAwait(false); if (release?.TagName is not { Length: > 0 } tag) return null; if (!TryParse(tag, out var remote) || !TryParse(currentVersion, out var local)) return null; if (remote <= local) return null; return new LatestRelease(tag, release.HtmlUrl ?? $"https://github.com/davide3011/PalladiumWallet/releases/tag/{tag}"); } catch { return null; } } /// Parses "v1.2.3" / "1.2.3-beta" style tags into a comparable . internal static bool TryParse(string raw, out Version version) { var s = raw.Trim(); if (s.StartsWith('v') || s.StartsWith('V')) s = s[1..]; var dash = s.IndexOf('-'); if (dash >= 0) s = s[..dash]; return Version.TryParse(s, out version!); } }