Files
LMEMappeCatastaliProApp/Services/AppUpdateService.cs

81 lines
3.5 KiB
C#

using System.Net.Http.Json;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Text.Json.Serialization;
namespace LMEMappeCatastaliApp.Services;
public sealed class AppUpdateService
{
private const string ReleasesUrl = "https://gitea.lmcloud.it/api/v1/repos/livio/LMEMappeCatastaliProApp/releases?limit=50";
private static readonly Regex ProTagPattern = new(
@"^v?(?<version>\d+\.\d+\.\d+)-pro(?:[-.].*)?$",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(20) };
public static string CurrentVersion =>
typeof(AppUpdateService).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
.InformationalVersion.Split('+')[0]
?? AppInfo.Current.VersionString;
public async Task<AppUpdateResult> CheckAsync(CancellationToken cancellationToken = default)
{
var releases = await _httpClient.GetFromJsonAsync<GiteaRelease[]>(ReleasesUrl, cancellationToken)
?? throw new InvalidDataException("Risposta aggiornamenti non valida.");
GiteaRelease? selectedRelease = null;
GiteaAsset? selectedApk = null;
Version? selectedVersion = null;
foreach (var release in releases.Where(item => !item.Draft))
{
var match = ProTagPattern.Match(release.TagName ?? string.Empty);
var apk = release.Assets?.FirstOrDefault(item => IsProApk(item.Name));
if (!match.Success || apk is null || !Version.TryParse(match.Groups["version"].Value, out var version))
{
continue;
}
if (selectedVersion is null || version > selectedVersion)
{
selectedRelease = release;
selectedApk = apk;
selectedVersion = version;
}
}
if (selectedRelease is null || selectedApk is null || selectedVersion is null)
{
throw new InvalidDataException("Nessuna release compatibile con LME Mappe Catastali Pro trovata.");
}
_ = Version.TryParse(CurrentVersion, out var current);
return new(
current is not null && selectedVersion > current,
selectedVersion.ToString(3),
selectedRelease.HtmlUrl ?? string.Empty,
selectedApk.BrowserDownloadUrl ?? selectedRelease.HtmlUrl ?? string.Empty,
selectedRelease.Body ?? string.Empty);
}
private static bool IsProApk(string? name) =>
name?.StartsWith("LME-Mappe-Catastali-Pro-", StringComparison.OrdinalIgnoreCase) == true
&& name.EndsWith(".apk", StringComparison.OrdinalIgnoreCase);
private sealed class GiteaRelease
{
[JsonPropertyName("tag_name")] public string? TagName { get; set; }
[JsonPropertyName("html_url")] public string? HtmlUrl { get; set; }
[JsonPropertyName("assets")] public GiteaAsset[]? Assets { get; set; }
[JsonPropertyName("body")] public string? Body { get; set; }
[JsonPropertyName("draft")] public bool Draft { get; set; }
}
private sealed class GiteaAsset
{
[JsonPropertyName("name")] public string? Name { get; set; }
[JsonPropertyName("browser_download_url")] public string? BrowserDownloadUrl { get; set; }
}
}
public sealed record AppUpdateResult(bool IsAvailable, string Version, string ReleaseUrl, string DownloadUrl, string ReleaseNotes);