From 74ae4bcb13a90cc0d8817752c2902b9502d34a2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Jul 2025 14:05:01 +0900 Subject: [PATCH] Fix update manager throwing unhandled visible to users See https://discord.com/channels/188630481301012481/1097318920991559880/1395623942437474405. --- osu.Desktop/Updater/VelopackUpdateManager.cs | 51 ++++++++++++-------- osu.Game/Updater/UpdateManager.cs | 14 +++++- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/osu.Desktop/Updater/VelopackUpdateManager.cs b/osu.Desktop/Updater/VelopackUpdateManager.cs index 3b79313f8c..cba050c638 100644 --- a/osu.Desktop/Updater/VelopackUpdateManager.cs +++ b/osu.Desktop/Updater/VelopackUpdateManager.cs @@ -53,33 +53,44 @@ namespace osu.Desktop.Updater return false; } - IUpdateSource updateSource = new GithubSource(@"https://github.com/ppy/osu", null, ReleaseStream.Value == Game.Configuration.ReleaseStream.Tachyon); - Velopack.UpdateManager updateManager = new Velopack.UpdateManager(updateSource, new UpdateOptions + try { - AllowVersionDowngrade = true - }); + IUpdateSource updateSource = new GithubSource(@"https://github.com/ppy/osu", null, ReleaseStream.Value == Game.Configuration.ReleaseStream.Tachyon); + Velopack.UpdateManager updateManager = new Velopack.UpdateManager(updateSource, new UpdateOptions + { + AllowVersionDowngrade = true + }); - UpdateInfo? update = await updateManager.CheckForUpdatesAsync().ConfigureAwait(false); + UpdateInfo? update = await updateManager.CheckForUpdatesAsync().ConfigureAwait(false); - if (cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) + { + log("Update check cancelled"); + scheduleNextUpdateCheck(); + return true; + } + + if (update == null) + { + // No update is available. + log("No update found"); + scheduleNextUpdateCheck(); + return false; + } + + // Download update in the background while notifying awaiters of the update being available. + log($"New update available: {update.TargetFullRelease.Version}"); + downloadUpdate(updateManager, update, cancellationToken); + return true; + } + catch (Exception e) { - log("Update check cancelled"); + log($"Update check failed with error ({e.Message})"); + + // we shouldn't crash on a web failure. or any failure for the matter. scheduleNextUpdateCheck(); return true; } - - if (update == null) - { - // No update is available. - log("No update found"); - scheduleNextUpdateCheck(); - return false; - } - - // Download update in the background while notifying awaiters of the update being available. - log($"New update available: {update.TargetFullRelease.Version}"); - downloadUpdate(updateManager, update, cancellationToken); - return true; } private void downloadUpdate(Velopack.UpdateManager updateManager, UpdateInfo update, CancellationToken cancellationToken) => Task.Run(async () => diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 4ce3914df0..8917f07a50 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -14,6 +15,7 @@ using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Localisation; +using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Utils; @@ -93,7 +95,7 @@ namespace osu.Game.Updater /// public void CheckForUpdate() { - _ = CheckForUpdateAsync(); + CheckForUpdateAsync().FireAndForget(); } /// @@ -111,7 +113,15 @@ namespace osu.Game.Updater using (var lastCts = Interlocked.Exchange(ref updateCancellationSource, cts)) await lastCts.CancelAsync().ConfigureAwait(false); - return await PerformUpdateCheck(cts.Token).ConfigureAwait(false); + try + { + return await PerformUpdateCheck(cts.Token).ConfigureAwait(false); + } + catch (Exception e) + { + Logger.Log($"{nameof(PerformUpdateCheck)} failed ({e.Message})"); + return false; + } }, cancellationToken).ConfigureAwait(false); ///