diff --git a/ShockOsc/Services/Updater.cs b/ShockOsc/Services/Updater.cs index 978219a..a6bd2c2 100644 --- a/ShockOsc/Services/Updater.cs +++ b/ShockOsc/Services/Updater.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging; using OpenShock.ShockOsc.Config; using OpenShock.ShockOsc.Models; +using OpenShock.ShockOsc.Ui.Utils; namespace OpenShock.ShockOsc.Services; @@ -11,19 +12,23 @@ public sealed class Updater { private const string GithubLatest = "https://api.github.com/repos/OpenShock/ShockOsc/releases/latest"; 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 Version _currentVersion = Assembly.GetEntryAssembly()?.GetName().Version ?? + throw new Exception("Could not determine ShockOsc version"); + private Uri? LatestDownloadUrl { get; set; } - + private readonly ILogger _logger; private readonly ConfigManager _configManager; - public bool UpdateAvailable { get; private set; } + + public UpdateableVariable UpdateAvailable { get; } = new(false); public Version? LatestVersion { get; private set; } - + public Updater(ILogger logger, ConfigManager configManager) { @@ -45,7 +50,7 @@ private static bool TryDeleteFile(string fileName) return false; } } - + private async Task<(Version, GithubReleaseResponse.Asset)?> GetLatestRelease() { _logger.LogInformation("Checking GitHub for updates..."); @@ -55,18 +60,24 @@ private static bool TryDeleteFile(string fileName) var res = await HttpClient.GetAsync(GithubLatest); if (!res.IsSuccessStatusCode) { - _logger.LogWarning("Failed to get latest version information from GitHub. {StatusCode}", res.StatusCode); + _logger.LogWarning("Failed to get latest version information from GitHub. {StatusCode}", + res.StatusCode); return null; } - var json = await JsonSerializer.DeserializeAsync(await res.Content.ReadAsStreamAsync()); + var json = + await JsonSerializer.DeserializeAsync(await res.Content.ReadAsStreamAsync()); if (json == null) { _logger.LogWarning("Could not deserialize json"); return null; } - if (!Version.TryParse(json.TagName[1..], out var version)) + var tagName = json.TagName; + if (!string.IsNullOrEmpty(tagName) && tagName[0] == 'v') + tagName = tagName[1..]; + + if (!Version.TryParse(tagName, out var version)) { _logger.LogWarning("Failed to parse version. Value: {Version}", json.TagName); return null; @@ -75,7 +86,8 @@ private static bool TryDeleteFile(string fileName) var asset = json.Assets.FirstOrDefault(x => x.Name == SetupFileName); if (asset == null) { - _logger.LogWarning("Could not find asset with {@SetupName}. Assets found: {@Assets}", SetupFileName, json.Assets); + _logger.LogWarning("Could not find asset with {@SetupName}. Assets found: {@Assets}", SetupFileName, + json.Assets); return null; } @@ -88,32 +100,39 @@ private static bool TryDeleteFile(string fileName) } } - public async Task CheckUpdate() + public async Task CheckUpdate() { var latestVersion = await GetLatestRelease(); - if (latestVersion is null) return false; + if (latestVersion == null) + { + UpdateAvailable.Value = false; + return; + } if (latestVersion.Value.Item1 <= _currentVersion) { - _logger.LogInformation("ShockOsc is up to date ([{Version}] >= [{LatestVersion}])", _currentVersion, latestVersion.Value.Item1); - UpdateAvailable = false; - return false; + _logger.LogInformation("ShockOsc is up to date ([{Version}] >= [{LatestVersion}])", _currentVersion, + latestVersion.Value.Item1); + UpdateAvailable.Value = false; + return; } - UpdateAvailable = true; + UpdateAvailable.Value = true; LatestVersion = latestVersion.Value.Item1; LatestDownloadUrl = latestVersion.Value.Item2.BrowserDownloadUrl; if (_configManager.Config.LastIgnoredVersion != null && _configManager.Config.LastIgnoredVersion >= latestVersion.Value.Item1) { - _logger.LogInformation("ShockOsc is not up to date. Skipping update due to previous postpone. You can reenable the updater by setting 'LastIgnoredVersion' to null"); - return false; + _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; + return; } - + _logger.LogWarning( "ShockOsc is not up to date. Newest version is [{NewVersion}] but you are on [{CurrentVersion}]!", latestVersion.Value.Item1, _currentVersion); - return true; + UpdateAvailable.Value = true; } public async Task DoUpdate() diff --git a/ShockOsc/Ui/Components/UpdateLogout.razor b/ShockOsc/Ui/Components/UpdateLogout.razor index 365490f..111b613 100644 --- a/ShockOsc/Ui/Components/UpdateLogout.razor +++ b/ShockOsc/Ui/Components/UpdateLogout.razor @@ -16,7 +16,13 @@ protected override async Task OnInitializedAsync() { - if (await Updater.CheckUpdate()) OpenUpdateDialog(); + Updater.UpdateAvailable.OnValueChanged += v => + { + InvokeAsync(StateHasChanged); + OpenUpdateDialog(); + }; + + await Updater.CheckUpdate(); } private async Task Logout() @@ -37,9 +43,9 @@ - - - + + + diff --git a/ShockOsc/Ui/Utils/UpdateableVariable.cs b/ShockOsc/Ui/Utils/UpdateableVariable.cs new file mode 100644 index 0000000..bfee9fd --- /dev/null +++ b/ShockOsc/Ui/Utils/UpdateableVariable.cs @@ -0,0 +1,22 @@ +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