mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
169 lines
5.2 KiB
C#
169 lines
5.2 KiB
C#
using System.Net.Http;
|
|
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using LanMountainDesktop.Launcher.Models;
|
|
|
|
namespace LanMountainDesktop.Launcher.Services;
|
|
|
|
/// <summary>
|
|
/// 更新检查服务 - 基于 GitHub Release API
|
|
/// </summary>
|
|
internal sealed class UpdateCheckService
|
|
{
|
|
private const string GitHubApiBase = "https://api.github.com";
|
|
private readonly string _repoOwner;
|
|
private readonly string _repoName;
|
|
private readonly HttpClient _httpClient;
|
|
private readonly JsonSerializerOptions _jsonOptions;
|
|
|
|
public UpdateCheckService(string repoOwner, string repoName)
|
|
{
|
|
_repoOwner = repoOwner;
|
|
_repoName = repoName;
|
|
_httpClient = new HttpClient();
|
|
_httpClient.DefaultRequestHeaders.Add("User-Agent", "LanMountainDesktop-Launcher");
|
|
_httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.github+json");
|
|
|
|
_jsonOptions = new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查更新
|
|
/// </summary>
|
|
public async Task<UpdateCheckResult> CheckForUpdateAsync(
|
|
string currentVersion,
|
|
UpdateChannel channel,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var releases = await FetchReleasesAsync(cancellationToken);
|
|
|
|
// 根据频道过滤版本
|
|
var filteredReleases = channel == UpdateChannel.Stable
|
|
? releases.Where(r => !r.Prerelease).ToList()
|
|
: releases;
|
|
|
|
// 找到最新版本
|
|
var latestRelease = filteredReleases
|
|
.OrderByDescending(r => ParseVersion(r.TagName))
|
|
.FirstOrDefault();
|
|
|
|
if (latestRelease == null)
|
|
{
|
|
return new UpdateCheckResult
|
|
{
|
|
HasUpdate = false,
|
|
CurrentVersion = currentVersion,
|
|
ErrorMessage = "No releases found"
|
|
};
|
|
}
|
|
|
|
var latestVersion = ParseVersionString(latestRelease.TagName);
|
|
var current = ParseVersion(currentVersion);
|
|
var latest = ParseVersion(latestVersion);
|
|
|
|
return new UpdateCheckResult
|
|
{
|
|
HasUpdate = latest > current,
|
|
LatestVersion = latestVersion,
|
|
CurrentVersion = currentVersion,
|
|
Release = latestRelease
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new UpdateCheckResult
|
|
{
|
|
HasUpdate = false,
|
|
CurrentVersion = currentVersion,
|
|
ErrorMessage = ex.Message
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取所有 Release
|
|
/// </summary>
|
|
private async Task<List<ReleaseInfo>> FetchReleasesAsync(CancellationToken cancellationToken)
|
|
{
|
|
var url = $"{GitHubApiBase}/repos/{_repoOwner}/{_repoName}/releases";
|
|
var response = await _httpClient.GetAsync(url, cancellationToken);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync(cancellationToken);
|
|
var releases = JsonSerializer.Deserialize<List<GitHubRelease>>(json, _jsonOptions);
|
|
|
|
return releases?.Select(r => new ReleaseInfo
|
|
{
|
|
TagName = r.TagName ?? "",
|
|
Name = r.Name ?? "",
|
|
Prerelease = r.Prerelease,
|
|
PublishedAt = r.PublishedAt,
|
|
Body = r.Body,
|
|
Assets = r.Assets?.Select(a => new ReleaseAsset
|
|
{
|
|
Name = a.Name ?? "",
|
|
BrowserDownloadUrl = a.BrowserDownloadUrl ?? "",
|
|
Size = a.Size
|
|
}).ToList() ?? []
|
|
}).ToList() ?? [];
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从 tag 解析版本号 (例如: v1.0.0 -> 1.0.0)
|
|
/// </summary>
|
|
private static string ParseVersionString(string tag)
|
|
{
|
|
return tag.TrimStart('v', 'V');
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析版本号
|
|
/// </summary>
|
|
private static Version ParseVersion(string versionString)
|
|
{
|
|
var cleaned = ParseVersionString(versionString);
|
|
return Version.TryParse(cleaned, out var version) ? version : new Version(0, 0, 0);
|
|
}
|
|
|
|
// GitHub API 响应模型
|
|
private sealed class GitHubRelease
|
|
{
|
|
[JsonPropertyName("tag_name")]
|
|
public string? TagName { get; set; }
|
|
|
|
[JsonPropertyName("name")]
|
|
public string? Name { get; set; }
|
|
|
|
[JsonPropertyName("prerelease")]
|
|
public bool Prerelease { get; set; }
|
|
|
|
[JsonPropertyName("published_at")]
|
|
public DateTime PublishedAt { get; set; }
|
|
|
|
[JsonPropertyName("body")]
|
|
public string? Body { get; set; }
|
|
|
|
[JsonPropertyName("assets")]
|
|
public List<GitHubAsset>? Assets { get; set; }
|
|
}
|
|
|
|
private sealed class GitHubAsset
|
|
{
|
|
[JsonPropertyName("name")]
|
|
public string? Name { get; set; }
|
|
|
|
[JsonPropertyName("browser_download_url")]
|
|
public string? BrowserDownloadUrl { get; set; }
|
|
|
|
[JsonPropertyName("size")]
|
|
public long Size { get; set; }
|
|
}
|
|
}
|