86 lines
2.9 KiB
C#
86 lines
2.9 KiB
C#
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Text.Json;
|
|
|
|
namespace ClaudeDo.Releases;
|
|
|
|
public sealed class ReleaseClient : IReleaseClient
|
|
{
|
|
public const string DefaultApiBase = "https://git.kuns.dev/api/v1/repos/releases/ClaudeDo";
|
|
|
|
private readonly HttpClient _http;
|
|
private readonly string _apiBase;
|
|
|
|
public ReleaseClient(HttpClient http, string apiBase = DefaultApiBase)
|
|
{
|
|
_http = http;
|
|
_apiBase = apiBase.TrimEnd('/');
|
|
}
|
|
|
|
public async Task<GiteaRelease?> GetLatestReleaseAsync(CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
using var response = await _http.GetAsync($"{_apiBase}/releases/latest", ct);
|
|
if (!response.IsSuccessStatusCode) return null;
|
|
var json = await response.Content.ReadAsStringAsync(ct);
|
|
return ParseRelease(json);
|
|
}
|
|
catch (HttpRequestException) { return null; }
|
|
catch (TaskCanceledException) when (!ct.IsCancellationRequested) { return null; }
|
|
}
|
|
|
|
public async Task DownloadAsync(string url, string destPath, IProgress<long> progress, CancellationToken ct)
|
|
{
|
|
using var response = await _http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, ct);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
await using var input = await response.Content.ReadAsStreamAsync(ct);
|
|
await using var output = File.Create(destPath);
|
|
|
|
var buffer = new byte[81920];
|
|
long total = 0;
|
|
int read;
|
|
while ((read = await input.ReadAsync(buffer, ct)) > 0)
|
|
{
|
|
await output.WriteAsync(buffer.AsMemory(0, read), ct);
|
|
total += read;
|
|
progress.Report(total);
|
|
}
|
|
}
|
|
|
|
private static GiteaRelease? ParseRelease(string json)
|
|
{
|
|
try
|
|
{
|
|
using var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
if (!root.TryGetProperty("tag_name", out var tagEl)) return null;
|
|
|
|
var tag = tagEl.GetString() ?? "";
|
|
var name = root.TryGetProperty("name", out var nameEl) ? (nameEl.GetString() ?? "") : "";
|
|
|
|
var assets = new List<ReleaseAsset>();
|
|
if (root.TryGetProperty("assets", out var arr) && arr.ValueKind == JsonValueKind.Array)
|
|
{
|
|
foreach (var item in arr.EnumerateArray())
|
|
{
|
|
if (!item.TryGetProperty("name", out var nameField)) continue;
|
|
if (!item.TryGetProperty("browser_download_url", out var urlField)) continue;
|
|
|
|
var aName = nameField.GetString() ?? "";
|
|
var aUrl = urlField.GetString() ?? "";
|
|
var aSize = item.TryGetProperty("size", out var s) ? s.GetInt64() : 0L;
|
|
assets.Add(new ReleaseAsset(aName, aUrl, aSize));
|
|
}
|
|
}
|
|
|
|
return new GiteaRelease(tag, name, assets);
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|