mirror of
https://github.com/Stone-Red-Code/AlwaysUpToDate.git
synced 2026-09-04 00:46:05 +02:00
Migrate update system to XML manifest and improve multi-OS support
This commit is contained in:
@@ -1,44 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AlwaysUpToDate;
|
|
||||||
|
|
||||||
namespace AlwaysUpToDate_Test
|
|
||||||
{
|
|
||||||
internal class Program
|
|
||||||
{
|
|
||||||
static private Updater updater = new Updater(new TimeSpan(0, 0, 1), "https://raw.githubusercontent.com/Stone-Red-Code/Test/main/test.json", "./", true);
|
|
||||||
|
|
||||||
private async static Task Main(string[] args)
|
|
||||||
{
|
|
||||||
updater.Start();
|
|
||||||
updater.ProgressChanged += Updater_ProgressChanged;
|
|
||||||
updater.UpdateAvailible += Updater_UpdateAvailible;
|
|
||||||
updater.NoUpdateAvailible += Updater_NoUpdateAvailible;
|
|
||||||
|
|
||||||
await Task.Delay(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Updater_UpdateAvailible(string version, string additionalInformation)
|
|
||||||
{
|
|
||||||
updater.Stop();
|
|
||||||
Console.WriteLine("New Update avalible: " + version);
|
|
||||||
Console.WriteLine("Do you want to install the new update? (y/n)");
|
|
||||||
|
|
||||||
char input = Console.ReadKey().KeyChar;
|
|
||||||
|
|
||||||
if (char.ToLower(input) == 'y')
|
|
||||||
updater.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Updater_ProgressChanged(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"{totalBytesDownloaded}/{totalFileSize} {progressPercentage}%");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Updater_NoUpdateAvailible()
|
|
||||||
{
|
|
||||||
Console.WriteLine("You are up to date");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<RootNamespace>AlwaysUpToDate_Test</RootNamespace>
|
<RootNamespace>AlwaysUpToDate.Test</RootNamespace>
|
||||||
<StartupObject>AlwaysUpToDate_Test.Program</StartupObject>
|
<StartupObject>AlwaysUpToDate.Test.Program</StartupObject>
|
||||||
<AssemblyVersion>2.0.0.0</AssemblyVersion>
|
<AssemblyVersion>2.0.0.0</AssemblyVersion>
|
||||||
<FileVersion>2.0.0.0</FileVersion>
|
<FileVersion>2.0.0.0</FileVersion>
|
||||||
<PackageTags></PackageTags>
|
<PackageTags></PackageTags>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AlwaysUpToDate.Test;
|
||||||
|
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
private static readonly Updater updater = new Updater(new TimeSpan(0, 0, 1), "https://raw.githubusercontent.com/Stone-Red-Code/Test/main/test.xml", true);
|
||||||
|
|
||||||
|
private static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
updater.ProgressChanged += Updater_ProgressChanged;
|
||||||
|
updater.UpdateAvailable += Updater_UpdateAvailable;
|
||||||
|
updater.NoUpdateAvailable += Updater_NoUpdateAvailable;
|
||||||
|
updater.OnException += Updater_OnException;
|
||||||
|
updater.Start();
|
||||||
|
|
||||||
|
await Task.Delay(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async void Updater_UpdateAvailable(string version, string changelogUrl)
|
||||||
|
{
|
||||||
|
updater.Stop();
|
||||||
|
Console.WriteLine("New Update available: " + version);
|
||||||
|
if (!string.IsNullOrEmpty(changelogUrl))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Changelog: " + changelogUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Do you want to install the new update? (y/n)");
|
||||||
|
|
||||||
|
char input = Console.ReadKey().KeyChar;
|
||||||
|
|
||||||
|
if (char.ToLower(input) == 'y')
|
||||||
|
{
|
||||||
|
await updater.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Updater_ProgressChanged(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{totalBytesDownloaded}/{totalFileSize} {progressPercentage}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Updater_NoUpdateAvailable()
|
||||||
|
{
|
||||||
|
Console.WriteLine("You are up to date!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Updater_OnException(Exception exception)
|
||||||
|
{
|
||||||
|
Console.WriteLine(exception.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,127 +1,181 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Timers;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Timers;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace AlwaysUpToDate
|
namespace AlwaysUpToDate
|
||||||
{
|
{
|
||||||
public class Updater
|
public class Updater : IDisposable
|
||||||
{
|
{
|
||||||
public delegate void UpdaterChangedHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
|
public delegate void UpdaterChangedHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
|
||||||
|
|
||||||
public event UpdaterChangedHandler ProgressChanged;
|
public event UpdaterChangedHandler ProgressChanged;
|
||||||
|
|
||||||
public delegate void UpdateAvalibleHandler(string version, string additionalInformation);
|
public delegate void UpdateAvailableHandler(string version, string changelogUrl);
|
||||||
|
|
||||||
public event UpdateAvalibleHandler UpdateAvailible;
|
public event UpdateAvailableHandler UpdateAvailable;
|
||||||
|
|
||||||
public delegate void NoUpdateAvalibleHandler();
|
public delegate void NoUpdateAvailableHandler();
|
||||||
|
|
||||||
public event NoUpdateAvalibleHandler NoUpdateAvailible;
|
public event NoUpdateAvailableHandler NoUpdateAvailable;
|
||||||
|
|
||||||
public delegate void ExceptionHandler(Exception exception);
|
public delegate void ExceptionHandler(Exception exception);
|
||||||
|
|
||||||
public event ExceptionHandler OnException;
|
public event ExceptionHandler OnException;
|
||||||
|
|
||||||
|
private static readonly XmlSerializer manifestSerializer = new XmlSerializer(typeof(UpdateManifest));
|
||||||
|
private readonly HttpClient httpClient = new HttpClient();
|
||||||
private readonly Timer updateTimer = new Timer();
|
private readonly Timer updateTimer = new Timer();
|
||||||
private readonly string updateInfoUrl;
|
private readonly string updateInfoUrl;
|
||||||
private readonly string installPath;
|
private readonly string installPath;
|
||||||
private string updateUrl;
|
private string updateUrl;
|
||||||
private bool updaing = false;
|
private bool updating;
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
|
public Updater(TimeSpan interval, Uri updateInfoUri, bool onlyUpdateOnce = false) : this(interval, updateInfoUri?.ToString(), "./", onlyUpdateOnce)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public Updater(TimeSpan interval, Uri updateInfoUri, string installPath = "./", bool onlyUpdateOnce = false) : this(interval, updateInfoUri?.ToString(), installPath, onlyUpdateOnce)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Updater(TimeSpan interval, string updateInfoUrl, bool onlyUpdateOnce = false) : this(interval, updateInfoUrl, "./", onlyUpdateOnce)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public Updater(TimeSpan interval, string updateInfoUrl, string installPath = "./", bool onlyUpdateOnce = false)
|
public Updater(TimeSpan interval, string updateInfoUrl, string installPath = "./", bool onlyUpdateOnce = false)
|
||||||
{
|
{
|
||||||
this.updateInfoUrl = updateInfoUrl;
|
this.updateInfoUrl = updateInfoUrl ?? throw new ArgumentNullException(nameof(updateInfoUrl));
|
||||||
this.installPath = installPath;
|
this.installPath = installPath ?? throw new ArgumentNullException(nameof(installPath));
|
||||||
|
|
||||||
if (interval.TotalMilliseconds > 0)
|
if (interval.TotalMilliseconds > 0)
|
||||||
|
{
|
||||||
updateTimer.Interval = interval.TotalMilliseconds;
|
updateTimer.Interval = interval.TotalMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
if (!onlyUpdateOnce)
|
if (!onlyUpdateOnce)
|
||||||
|
{
|
||||||
updateTimer.Elapsed += UpdateTimer_Elapsed;
|
updateTimer.Elapsed += UpdateTimer_Elapsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
if (updateTimer.Interval > 0)
|
if (updateTimer.Interval > 0)
|
||||||
|
{
|
||||||
updateTimer.Start();
|
updateTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
UpdateTimer_Elapsed(null, null);
|
UpdateTimer_Elapsed(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
updateTimer.Stop();
|
updateTimer.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Update()
|
public async Task Update()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(updateUrl) && !updaing)
|
ThrowIfDisposed();
|
||||||
|
if (!string.IsNullOrWhiteSpace(updateUrl) && !updating)
|
||||||
|
{
|
||||||
await DownloadFile();
|
await DownloadFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void UpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
private async void UpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using HttpClient client = new HttpClient();
|
using HttpResponseMessage response = await httpClient.GetAsync(updateInfoUrl);
|
||||||
HttpResponseMessage response = await client.GetAsync(updateInfoUrl);
|
_ = response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
Stream stream = await response.Content.ReadAsStreamAsync();
|
using Stream stream = await response.Content.ReadAsStreamAsync();
|
||||||
UpdateInfo updateInfo = await JsonSerializer.DeserializeAsync<UpdateInfo>(stream);
|
UpdateManifest manifest = (UpdateManifest)manifestSerializer.Deserialize(stream);
|
||||||
|
|
||||||
|
TargetOS currentOS = GetCurrentOS();
|
||||||
|
UpdateItem updateItem = manifest.Items?.FirstOrDefault(i => i.OS == currentOS);
|
||||||
|
|
||||||
|
if (updateItem == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Version assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
|
Version assemblyVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||||
bool succes = Version.TryParse(updateInfo.Version, out Version version);
|
|
||||||
|
|
||||||
if (!succes)
|
if (!Version.TryParse(updateItem.Version, out Version version))
|
||||||
return;
|
|
||||||
|
|
||||||
if (version > assemblyVersion && !updaing)
|
|
||||||
{
|
{
|
||||||
updateUrl = updateInfo.FileUrl;
|
return;
|
||||||
if (!updateInfo.Mandatory)
|
}
|
||||||
|
|
||||||
|
if (version > assemblyVersion && !updating)
|
||||||
|
{
|
||||||
|
updateUrl = updateItem.DownloadUrl;
|
||||||
|
if (!updateItem.IsMandatory)
|
||||||
{
|
{
|
||||||
if (UpdateAvailible != null)
|
UpdateAvailable?.Invoke(updateItem.Version, updateItem.ChangelogUrl);
|
||||||
UpdateAvailible(updateInfo.Version, updateInfo.AdditionalInformation);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Update();
|
await Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NoUpdateAvailible != null)
|
NoUpdateAvailable?.Invoke();
|
||||||
NoUpdateAvailible();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (OnException != null)
|
OnException?.Invoke(ex);
|
||||||
OnException(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TargetOS GetCurrentOS()
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
return TargetOS.Windows;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
|
{
|
||||||
|
return TargetOS.MacOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
|
return TargetOS.Linux;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task DownloadFile()
|
private async Task DownloadFile()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
updateTimer.Stop();
|
updateTimer.Stop();
|
||||||
updaing = true;
|
updating = true;
|
||||||
using HttpClient client = new HttpClient();
|
|
||||||
|
|
||||||
HttpResponseMessage response = client.GetAsync(updateUrl).Result;
|
using HttpResponseMessage response = await httpClient.GetAsync(updateUrl);
|
||||||
using Stream contentStream = response.Content.ReadAsStreamAsync().Result;
|
_ = response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
using Stream contentStream = await response.Content.ReadAsStreamAsync();
|
||||||
await ProcessContentStream(response.Content.Headers.ContentLength, contentStream);
|
await ProcessContentStream(response.Content.Headers.ContentLength, contentStream);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (OnException != null)
|
OnException?.Invoke(ex);
|
||||||
OnException(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,32 +183,48 @@ namespace AlwaysUpToDate
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ZipArchive zipArchive = ZipFile.OpenRead(Path.Join(installPath, "Update.zip"));
|
string executablePath = Process.GetCurrentProcess().MainModule?.FileName ?? Assembly.GetEntryAssembly()?.Location;
|
||||||
string executablePath = Process.GetCurrentProcess().MainModule.FileName;
|
|
||||||
Console.WriteLine(executablePath);
|
|
||||||
|
|
||||||
foreach (ZipArchiveEntry entry in zipArchive.Entries)
|
if (string.IsNullOrEmpty(executablePath))
|
||||||
{
|
{
|
||||||
if (File.Exists(Path.Join(installPath, entry.FullName)))
|
throw new InvalidOperationException("Unable to determine the executable path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (ZipArchive zipArchive = ZipFile.OpenRead(Path.Join(installPath, "Update.zip")))
|
||||||
|
{
|
||||||
|
string fullInstallPath = Path.GetFullPath(installPath + Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
|
foreach (ZipArchiveEntry entry in zipArchive.Entries)
|
||||||
{
|
{
|
||||||
string moveName = entry.FullName;
|
string destinationPath = Path.GetFullPath(Path.Join(installPath, entry.FullName));
|
||||||
while (File.Exists(Path.Join(installPath, moveName)))
|
if (!destinationPath.StartsWith(fullInstallPath, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
moveName += "_OLD_";
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Join(installPath, entry.FullName)))
|
||||||
|
{
|
||||||
|
string moveName = entry.FullName;
|
||||||
|
while (File.Exists(Path.Join(installPath, moveName)))
|
||||||
|
{
|
||||||
|
moveName += "_OLD_";
|
||||||
|
}
|
||||||
|
File.Move(Path.Join(installPath, entry.FullName), Path.Join(installPath, moveName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.FullName.EndsWith('/'))
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(Path.Join(installPath, entry.FullName)))
|
||||||
|
{
|
||||||
|
_ = Directory.CreateDirectory(Path.Join(installPath, entry.FullName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry.ExtractToFile(Path.Join(installPath, entry.FullName), true);
|
||||||
}
|
}
|
||||||
File.Move(Path.Join(installPath, entry.FullName), Path.Join(installPath, moveName));
|
|
||||||
}
|
|
||||||
if (entry.FullName.EndsWith("/"))
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(Path.Join(installPath, entry.FullName)))
|
|
||||||
Directory.CreateDirectory(Path.Join(installPath, entry.FullName));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry.ExtractToFile(Path.Join(installPath, entry.FullName), true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zipArchive.Dispose();
|
|
||||||
|
|
||||||
foreach (string filePath in Directory.GetFiles(installPath, "*.*", SearchOption.AllDirectories))
|
foreach (string filePath in Directory.GetFiles(installPath, "*.*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
@@ -172,14 +242,19 @@ namespace AlwaysUpToDate
|
|||||||
}
|
}
|
||||||
|
|
||||||
File.Delete(Path.Join(installPath, "Update.zip"));
|
File.Delete(Path.Join(installPath, "Update.zip"));
|
||||||
Process.Start(executablePath);
|
|
||||||
|
//if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
//{
|
||||||
|
// Process.Start("chmod", $"+x \"{executablePath}\"")?.WaitForExit();
|
||||||
|
//}
|
||||||
|
|
||||||
|
_ = Process.Start(new ProcessStartInfo(executablePath) { UseShellExecute = false });
|
||||||
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (OnException != null)
|
OnException?.Invoke(ex);
|
||||||
OnException(ex);
|
|
||||||
}
|
}
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream)
|
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream)
|
||||||
@@ -191,10 +266,10 @@ namespace AlwaysUpToDate
|
|||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
bool isMoreToRead = true;
|
bool isMoreToRead = true;
|
||||||
|
|
||||||
using var fileStream = new FileStream($"{installPath}Update.zip", FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
|
using FileStream fileStream = new FileStream(Path.Join(installPath, "Update.zip"), FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int bytesRead = contentStream.ReadAsync(buffer, 0, buffer.Length).Result;
|
int bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
|
||||||
if (bytesRead == 0)
|
if (bytesRead == 0)
|
||||||
{
|
{
|
||||||
isMoreToRead = false;
|
isMoreToRead = false;
|
||||||
@@ -214,27 +289,51 @@ namespace AlwaysUpToDate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (isMoreToRead);
|
while (isMoreToRead);
|
||||||
fileStream.Close();
|
|
||||||
ExtractZipFile();
|
ExtractZipFile();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (OnException != null)
|
OnException?.Invoke(ex);
|
||||||
OnException(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
|
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
|
||||||
{
|
{
|
||||||
if (ProgressChanged == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
double? progressPercentage = null;
|
double? progressPercentage = null;
|
||||||
if (totalDownloadSize.HasValue)
|
if (totalDownloadSize.HasValue)
|
||||||
|
{
|
||||||
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
|
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
|
||||||
|
}
|
||||||
|
|
||||||
if (ProgressChanged != null)
|
ProgressChanged?.Invoke(totalDownloadSize, totalBytesRead, progressPercentage);
|
||||||
ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage);
|
}
|
||||||
|
|
||||||
|
private void ThrowIfDisposed()
|
||||||
|
{
|
||||||
|
if (disposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(Updater));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
updateTimer.Dispose();
|
||||||
|
httpClient.Dispose();
|
||||||
|
}
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,54 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
using System.Xml.Serialization;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace AlwaysUpToDate
|
namespace AlwaysUpToDate
|
||||||
{
|
{
|
||||||
internal class UpdateInfo
|
[XmlRoot("updates")]
|
||||||
|
public class UpdateManifest
|
||||||
{
|
{
|
||||||
|
[XmlElement("item")]
|
||||||
|
public List<UpdateItem> Items { get; set; } = new List<UpdateItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateItem
|
||||||
|
{
|
||||||
|
[XmlElement("os")]
|
||||||
|
public TargetOS OS { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("version")]
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
public string FileUrl { get; set; }
|
|
||||||
public string AdditionalInformation { get; set; }
|
[XmlElement("url")]
|
||||||
public bool Mandatory { get; set; }
|
public string DownloadUrl { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("changelog")]
|
||||||
|
public string ChangelogUrl { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("mandatory")]
|
||||||
|
public bool IsMandatory { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("checksum")]
|
||||||
|
public Checksum Checksum { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Checksum
|
||||||
|
{
|
||||||
|
[XmlAttribute("algorithm")]
|
||||||
|
public string Algorithm { get; set; }
|
||||||
|
|
||||||
|
[XmlText]
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TargetOS
|
||||||
|
{
|
||||||
|
[XmlEnum("windows")]
|
||||||
|
Windows,
|
||||||
|
|
||||||
|
[XmlEnum("macos")]
|
||||||
|
MacOS,
|
||||||
|
|
||||||
|
[XmlEnum("linux")]
|
||||||
|
Linux,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user