From d2bfc31c0a804ab65245ece712f785629a92ae99 Mon Sep 17 00:00:00 2001 From: Luca Date: Sat, 27 Apr 2024 00:34:35 +0200 Subject: [PATCH] Updater semver support --- ShockOsc/Config/ConfigManager.cs | 5 +-- ShockOsc/Config/ShockOscConfig.cs | 6 ++-- ShockOsc/MauiProgram.cs | 4 +++ ShockOsc/Services/Updater.cs | 42 ++++++++++++----------- ShockOsc/ShockOsc.csproj | 7 ++-- ShockOsc/Ui/Components/UpdateDialog.razor | 6 ++++ ShockOsc/Ui/Components/UpdateLogout.razor | 5 +-- ShockOsc/Ui/Utils/UpdateableVariable.cs | 22 ------------ 8 files changed, 46 insertions(+), 51 deletions(-) delete mode 100644 ShockOsc/Ui/Utils/UpdateableVariable.cs diff --git a/ShockOsc/Config/ConfigManager.cs b/ShockOsc/Config/ConfigManager.cs index 724e1eb..5277cd1 100644 --- a/ShockOsc/Config/ConfigManager.cs +++ b/ShockOsc/Config/ConfigManager.cs @@ -1,6 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Logging; +using OpenShock.SDK.CSharp.Hub.Utils; using OpenShock.ShockOsc.Utils; namespace OpenShock.ShockOsc.Config; @@ -31,7 +32,7 @@ public ConfigManager(ILogger logger) { config = JsonSerializer.Deserialize(json, Options); } - catch (JsonException e) + catch (Exception e) { _logger.LogCritical(e, "Error during deserialization/loading of config"); _logger.LogWarning("Attempting to move old config and generate a new one"); @@ -55,7 +56,7 @@ public ConfigManager(ILogger logger) private static readonly JsonSerializerOptions Options = new() { WriteIndented = true, - Converters = { new JsonStringEnumConverter() } + Converters = { new JsonStringEnumConverter(), new SemVersionJsonConverter() } }; private readonly SemaphoreSlim _saveLock = new(1, 1); diff --git a/ShockOsc/Config/ShockOscConfig.cs b/ShockOsc/Config/ShockOscConfig.cs index 845e530..71dcdbe 100644 --- a/ShockOsc/Config/ShockOscConfig.cs +++ b/ShockOsc/Config/ShockOscConfig.cs @@ -1,4 +1,6 @@ -namespace OpenShock.ShockOsc.Config; +using Semver; + +namespace OpenShock.ShockOsc.Config; public sealed class ShockOscConfig { @@ -7,7 +9,7 @@ public sealed class ShockOscConfig public OpenShockConf OpenShock { get; set; } = new(); public ChatboxConf Chatbox { get; set; } = new(); public IDictionary Groups { get; set; } = new Dictionary(); - public Version? LastIgnoredVersion { get; set; } = null; + public SemVersion? LastIgnoredVersion { get; set; } = null; public AppConfig App { get; set; } = new(); } \ No newline at end of file diff --git a/ShockOsc/MauiProgram.cs b/ShockOsc/MauiProgram.cs index 0ba2b94..0e6500c 100644 --- a/ShockOsc/MauiProgram.cs +++ b/ShockOsc/MauiProgram.cs @@ -7,6 +7,7 @@ using OpenShock.ShockOsc.Logging; using OpenShock.ShockOsc.OscQueryLibrary; using OpenShock.ShockOsc.Services; +using OpenShock.ShockOsc.Utils; using Serilog; using MauiApp = OpenShock.ShockOsc.Ui.MauiApp; @@ -147,6 +148,9 @@ public static Microsoft.Maui.Hosting.MauiApp CreateMauiApp() app.Services.GetRequiredService(); app.Services.GetRequiredService().Start(); + var updater = app.Services.GetRequiredService(); + OsTask.Run(updater.CheckUpdate); + return app; } } \ No newline at end of file diff --git a/ShockOsc/Services/Updater.cs b/ShockOsc/Services/Updater.cs index a6bd2c2..a12a989 100644 --- a/ShockOsc/Services/Updater.cs +++ b/ShockOsc/Services/Updater.cs @@ -2,23 +2,24 @@ using System.Reflection; using System.Text.Json; using Microsoft.Extensions.Logging; +using OpenShock.SDK.CSharp.Updatables; using OpenShock.ShockOsc.Config; using OpenShock.ShockOsc.Models; using OpenShock.ShockOsc.Ui.Utils; +using Semver; namespace OpenShock.ShockOsc.Services; public sealed class Updater { - private const string GithubLatest = "https://api.github.com/repos/OpenShock/ShockOsc/releases/latest"; + private const string GithubLatest = "https://api.github.com/repos/OpenShock/ShockOsc/releases/152715042"; private const string SetupFileName = "ShockOSC_Setup.exe"; // OpenShock.ShockOsc.exe private static readonly HttpClient HttpClient = new(); private readonly string _setupFilePath = Path.Combine(Environment.CurrentDirectory, SetupFileName); - private readonly Version _currentVersion = Assembly.GetEntryAssembly()?.GetName().Version ?? - throw new Exception("Could not determine ShockOsc version"); + private readonly SemVersion _currentVersion = SemVersion.Parse(typeof(Updater).Assembly.GetCustomAttribute()!.InformationalVersion, SemVersionStyles.Strict); private Uri? LatestDownloadUrl { get; set; } @@ -26,8 +27,9 @@ public sealed class Updater private readonly ConfigManager _configManager; - public UpdateableVariable UpdateAvailable { get; } = new(false); - public Version? LatestVersion { get; private set; } + public UpdatableVariable UpdateAvailable { get; } = new(false); + public bool IsPostponed { get; private set; } + public SemVersion? LatestVersion { get; private set; } public Updater(ILogger logger, ConfigManager configManager) @@ -51,7 +53,7 @@ private static bool TryDeleteFile(string fileName) } } - private async Task<(Version, GithubReleaseResponse.Asset)?> GetLatestRelease() + private async Task<(SemVersion, GithubReleaseResponse.Asset)?> GetLatestRelease() { _logger.LogInformation("Checking GitHub for updates..."); @@ -74,23 +76,21 @@ private static bool TryDeleteFile(string fileName) } var tagName = json.TagName; - if (!string.IsNullOrEmpty(tagName) && tagName[0] == 'v') - tagName = tagName[1..]; - if (!Version.TryParse(tagName, out var version)) + if (!SemVersion.TryParse(tagName, SemVersionStyles.AllowV, out var version)) { _logger.LogWarning("Failed to parse version. Value: {Version}", json.TagName); return null; } - var asset = json.Assets.FirstOrDefault(x => x.Name == SetupFileName); + var asset = json.Assets.FirstOrDefault(x => x.Name.Equals(SetupFileName, StringComparison.InvariantCultureIgnoreCase)); if (asset == null) { _logger.LogWarning("Could not find asset with {@SetupName}. Assets found: {@Assets}", SetupFileName, json.Assets); return null; } - + return (version, asset); } catch (Exception e) @@ -102,16 +102,21 @@ private static bool TryDeleteFile(string fileName) public async Task CheckUpdate() { + IsPostponed = false; + UpdateAvailable.Value = false; + var latestVersion = await GetLatestRelease(); if (latestVersion == null) { UpdateAvailable.Value = false; return; } - if (latestVersion.Value.Item1 <= _currentVersion) + + var comparison = _currentVersion.ComparePrecedenceTo(latestVersion.Value.Item1); + if (comparison >= 0) { - _logger.LogInformation("ShockOsc is up to date ([{Version}] >= [{LatestVersion}])", _currentVersion, - latestVersion.Value.Item1); + _logger.LogInformation("ShockOsc is up to date ([{Version}] >= [{LatestVersion}]) ({Comp})", _currentVersion, + latestVersion.Value.Item1, comparison); UpdateAvailable.Value = false; return; } @@ -119,20 +124,17 @@ public async Task CheckUpdate() UpdateAvailable.Value = true; LatestVersion = latestVersion.Value.Item1; LatestDownloadUrl = latestVersion.Value.Item2.BrowserDownloadUrl; - if (_configManager.Config.LastIgnoredVersion != null && - _configManager.Config.LastIgnoredVersion >= latestVersion.Value.Item1) + if (_configManager.Config.LastIgnoredVersion != null && _configManager.Config.LastIgnoredVersion.ComparePrecedenceTo(latestVersion.Value.Item1) >= 0) { _logger.LogInformation( - "ShockOsc is not up to date. Skipping update due to previous postpone. You can reenable the updater by setting 'LastIgnoredVersion' to null"); - UpdateAvailable.Value = false; + "ShockOsc is not up to date. Skipping update due to previous postpone"); + IsPostponed = true; return; } _logger.LogWarning( "ShockOsc is not up to date. Newest version is [{NewVersion}] but you are on [{CurrentVersion}]!", latestVersion.Value.Item1, _currentVersion); - - UpdateAvailable.Value = true; } public async Task DoUpdate() diff --git a/ShockOsc/ShockOsc.csproj b/ShockOsc/ShockOsc.csproj index 9efdfa7..afe2407 100644 --- a/ShockOsc/ShockOsc.csproj +++ b/ShockOsc/ShockOsc.csproj @@ -10,14 +10,13 @@ false enable ShockOsc - com.companyname.shockosc + org.openshock.shockosc 2C147618-324E-4C37-B4B6-C50C8A9BD5ED - 1.0 - 1 OpenShock.ShockOsc OpenShock.ShockOsc OpenShock 2.0.0 + 2.0.0-rc.2 Resources\openshock-icon.ico true ShockOsc @@ -34,6 +33,7 @@ en en-US;en + false @@ -60,6 +60,7 @@ + diff --git a/ShockOsc/Ui/Components/UpdateDialog.razor b/ShockOsc/Ui/Components/UpdateDialog.razor index 01f07d0..85aede1 100644 --- a/ShockOsc/Ui/Components/UpdateDialog.razor +++ b/ShockOsc/Ui/Components/UpdateDialog.razor @@ -16,6 +16,11 @@ await ConfigManager.SaveAsync(); MudDialog.Close(DialogResult.Ok(true)); } + + private void Dismiss() + { + MudDialog.Close(DialogResult.Ok(true)); + } private void DownloadUpdate() { @@ -44,6 +49,7 @@ @if (!_isDownloading) { + Dismiss Skip Update } diff --git a/ShockOsc/Ui/Components/UpdateLogout.razor b/ShockOsc/Ui/Components/UpdateLogout.razor index 111b613..d663f99 100644 --- a/ShockOsc/Ui/Components/UpdateLogout.razor +++ b/ShockOsc/Ui/Components/UpdateLogout.razor @@ -19,10 +19,11 @@ Updater.UpdateAvailable.OnValueChanged += v => { InvokeAsync(StateHasChanged); - OpenUpdateDialog(); + if (v && !Updater.IsPostponed) OpenUpdateDialog(); }; - await Updater.CheckUpdate(); + if (Updater.UpdateAvailable.Value && !Updater.IsPostponed) OpenUpdateDialog(); + } private async Task Logout() diff --git a/ShockOsc/Ui/Utils/UpdateableVariable.cs b/ShockOsc/Ui/Utils/UpdateableVariable.cs deleted file mode 100644 index bfee9fd..0000000 --- a/ShockOsc/Ui/Utils/UpdateableVariable.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace OpenShock.ShockOsc.Ui.Utils; - -public sealed class UpdateableVariable(T internalValue) -{ - public T Value - { - get => internalValue; - set - { - if (internalValue!.Equals(value)) return; - internalValue = value; - OnValueChanged?.Invoke(value); - } - } - - public event Action? OnValueChanged; - - public void UpdateWithoutNotify(T newValue) - { - internalValue = newValue; - } -} \ No newline at end of file