discovery/test/Discovery.Loader.Avalonia/Services/UpdateService.cs
Kevin Kai Berthold f133c740e1 migration
2025-09-24 22:10:04 +02:00

167 lines
No EOL
5.3 KiB
C#

using Discovery.Loader.Models;
using System;
using System.Diagnostics;
using System.IO.Compression;
using System.Net.Http.Json;
using System.Threading;
namespace Discovery.Loader.Services;
public class UpdateService
{
public DirectoryInfo AppDir { get; private set; }
public UpdateService()
{
var localApps = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
AppDir = new(Path.Combine(localApps.FullName + @"\Discovery"));
}
public bool IsInstalled()
{
if (!AppDir.Exists)
{
return false;
}
if (!AppDir.EnumerateFiles().Where(p => p.Name.Contains("Discovery.exe", StringComparison.InvariantCultureIgnoreCase)).Any())
{
return false;
}
return true;
}
public async Task<Update?> GetUpdateAsync()
{
using var httpClient = new HttpClient();
var update = await httpClient.GetFromJsonAsync(
"https://raw.githubusercontent.com/vaitr/discovery/refs/heads/main/version.json",
UpdateContext.Default.Update,
default);
if (update == null)
{
Console.WriteLine("Source not available");
return null;
}
return update;
}
public bool CompareVersion(Update update)
{
Console.WriteLine(update.Version);
Console.WriteLine(update.Link);
var mainExecutable = new FileInfo(Path.Combine(AppDir.FullName + @"/discovery.exe"));
if (!mainExecutable.Exists)
return false;
var currentVersion = FileVersionInfo.GetVersionInfo(mainExecutable.FullName).FileVersion;
var vCurrent = Version.Parse(currentVersion!);
var vUpdate = Version.Parse(update.Version);
if (vUpdate > vCurrent)
return false;
return true;
}
public async Task<bool> DownloadAsync(Update update, Func<double, Task>? onProgress)
{
try
{
using var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(3);
using var fileStream = new FileStream(Path.Combine(AppDir.FullName + @"/update.zip"), FileMode.Create);
// Get the http headers first to examine the content length
using var response = await httpClient.GetAsync(update.Link, HttpCompletionOption.ResponseHeadersRead);
var contentLength = response.Content.Headers.ContentLength;
using var download = await response.Content.ReadAsStreamAsync(default);
if (onProgress == null || !contentLength.HasValue)
{
await download.CopyToAsync(fileStream);
return true;
}
// Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
var relativeProgress = new Progress<long>(async (totalBytes) =>
{
Console.WriteLine(totalBytes + " / " + contentLength.Value + " / " + (float)totalBytes / contentLength.Value);
await onProgress((float)totalBytes / contentLength.Value);
});
// Use extension method to report progress while downloading
await download.CopyToAsync(fileStream, 81920, relativeProgress, default);
return true;
}
catch
{
return false;
}
}
public void Extract()
{
var archivePath = Path.Combine(AppDir.FullName + @"/update.zip");
using (var archive = ZipFile.OpenRead(archivePath))
{
foreach (var entry in archive.Entries)
{
var file = new FileInfo(Path.Combine(AppDir.FullName, entry.Name));
if (file.Exists)
file.Delete();
entry.ExtractToFile(file.FullName);
}
}
File.Delete(archivePath);
}
public void StartExecutable()
{
var exec = new FileInfo(Path.Combine(AppDir.FullName + @"/discovery.exe"));
_ = Process.Start(new ProcessStartInfo
{
UseShellExecute = true,
FileName = exec.FullName
});
}
}
public static class StreamExtensions
{
public static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<long> progress = null, CancellationToken cancellationToken = default)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (!source.CanRead)
throw new ArgumentException("Has to be readable", nameof(source));
if (destination == null)
throw new ArgumentNullException(nameof(destination));
if (!destination.CanWrite)
throw new ArgumentException("Has to be writable", nameof(destination));
if (bufferSize < 0)
throw new ArgumentOutOfRangeException(nameof(bufferSize));
var buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
progress?.Report(totalBytesRead);
}
}
}