2026-07-02 21:33:14 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/// <summary>A GitHub release newer than the running app.</summary>
|
|
|
|
|
public sealed record LatestRelease(string Tag, string HtmlUrl);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 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".
|
|
|
|
|
/// </summary>
|
|
|
|
|
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 async Task<LatestRelease?> CheckAsync(string currentVersion, CancellationToken ct = default)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var http = new HttpClient { 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<GitHubReleaseResponse>(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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Parses "v1.2.3" / "1.2.3-beta" style tags into a comparable <see cref="Version"/>.</summary>
|
2026-07-02 23:20:18 +02:00
|
|
|
internal static bool TryParse(string raw, out Version version)
|
2026-07-02 21:33:14 +02:00
|
|
|
{
|
|
|
|
|
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!);
|
|
|
|
|
}
|
|
|
|
|
}
|