diff --git a/osu.Desktop/Updater/VelopackUpdateManager.cs b/osu.Desktop/Updater/VelopackUpdateManager.cs index 386a62d673..12a8b7a05d 100644 --- a/osu.Desktop/Updater/VelopackUpdateManager.cs +++ b/osu.Desktop/Updater/VelopackUpdateManager.cs @@ -37,7 +37,7 @@ namespace osu.Desktop.Updater scheduledBackgroundCheck = Scheduler.AddDelayed(() => { Logger.Log("Running scheduled background update check..."); - Task.Run(CheckForUpdateAsync); + CheckForUpdate(); }, 60000 * 30); } @@ -60,6 +60,13 @@ namespace osu.Desktop.Updater UpdateInfo? update = await updateManager.CheckForUpdatesAsync().ConfigureAwait(false); + if (cancellationToken.IsCancellationRequested) + { + Logger.Log("Update check cancelled"); + scheduleNextUpdateCheck(); + return true; + } + if (update == null) { // No update is available. @@ -68,9 +75,8 @@ namespace osu.Desktop.Updater return false; } - Logger.Log($"New update available: {update.TargetFullRelease.Version}"); - // Download update in the background while notifying awaiters of the update being available. + Logger.Log($"New update available: {update.TargetFullRelease.Version}"); downloadUpdate(updateManager, update, cancellationToken); return true; } diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index ac6215f3ad..b8a77a7688 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Settings.Sections.General try { - bool foundUpdate = await updateManager.CheckForUpdateAsync().ConfigureAwait(true); + bool foundUpdate = await updateManager.CheckForUpdateAsync(checkingNotification.CancellationToken).ConfigureAwait(true); if (!foundUpdate) { @@ -142,8 +142,9 @@ namespace osu.Game.Overlays.Settings.Sections.General } finally { - // This sequence allows the notification to be immediately dismissed. - checkingNotification.State = ProgressNotificationState.Cancelled; + // This sequence allows the notification to be immediately dismissed without posting a continuation message. + checkingNotification.CompletionTarget = null; + checkingNotification.State = ProgressNotificationState.Completed; checkingNotification.Close(false); checkForUpdatesButton.Enabled.Value = true; } diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 3855ddd0d6..76557a4c77 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -44,6 +44,7 @@ namespace osu.Game.Updater protected IBindable ReleaseStream => releaseStream; private readonly Bindable releaseStream = new Bindable(); + private CancellationTokenSource updateCancellation = new CancellationTokenSource(); protected override void LoadComplete() { @@ -67,22 +68,35 @@ namespace osu.Game.Updater config.SetValue(OsuSetting.Version, version); config.BindWith(OsuSetting.ReleaseStream, releaseStream); - releaseStream.BindValueChanged(_ => CheckForUpdateAsync()); + releaseStream.BindValueChanged(_ => CheckForUpdate()); - CheckForUpdateAsync(); + CheckForUpdate(); } - private CancellationTokenSource? updateCheckCancellation; + /// + /// Immediately checks for any available update. + /// + public void CheckForUpdate() + { + _ = CheckForUpdateAsync(); + } /// - /// Immediately checks for any available updates, or returns the existing update task. + /// Immediately checks for any available update. /// /// true if any updates are available, false otherwise. - public Task CheckForUpdateAsync() + public async Task CheckForUpdateAsync(CancellationToken cancellationToken = default) { - updateCheckCancellation?.Cancel(); - updateCheckCancellation = new CancellationTokenSource(); - return PerformUpdateCheck(updateCheckCancellation.Token); + var cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var lastCancellation = Interlocked.Exchange(ref updateCancellation, cancellation); + + using (lastCancellation) + { + // This serves a dual purpose of nullifying the last update, closing any existing notifications as stale. + await lastCancellation.CancelAsync().ConfigureAwait(false); + } + + return await PerformUpdateCheck(cancellation.Token).ConfigureAwait(false); } /// @@ -91,12 +105,6 @@ namespace osu.Game.Updater /// Whether any update is waiting. May return true if an error occured (there is potentially an update available). protected virtual Task PerformUpdateCheck(CancellationToken cancellationToken) => Task.FromResult(false); - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - updateCheckCancellation?.Cancel(); - } - private partial class UpdateCompleteNotification : SimpleNotification { private readonly string version;