mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 15:12:57 +08:00
initial implementation
This commit is contained in:
parent
87f2a23263
commit
0ee89183cc
@ -19,7 +19,6 @@ using osu.Desktop.Windows;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Game.Online.Multiplayer;
|
|
||||||
using osu.Game.Performance;
|
using osu.Game.Performance;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using SDL;
|
using SDL;
|
||||||
@ -103,35 +102,22 @@ namespace osu.Desktop
|
|||||||
if (!string.IsNullOrEmpty(packageManaged))
|
if (!string.IsNullOrEmpty(packageManaged))
|
||||||
return new NoActionUpdateManager();
|
return new NoActionUpdateManager();
|
||||||
|
|
||||||
switch (RuntimeInfo.OS)
|
return new VeloUpdateManager();
|
||||||
{
|
|
||||||
case RuntimeInfo.Platform.Windows:
|
|
||||||
Debug.Assert(OperatingSystem.IsWindows());
|
|
||||||
|
|
||||||
return new SquirrelUpdateManager();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return new SimpleUpdateManager();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool RestartAppWhenExited()
|
public override bool RestartAppWhenExited()
|
||||||
{
|
{
|
||||||
switch (RuntimeInfo.OS)
|
try
|
||||||
{
|
{
|
||||||
case RuntimeInfo.Platform.Windows:
|
Process.Start(Process.GetCurrentProcess().MainModule?.FileName ?? throw new InvalidOperationException());
|
||||||
Debug.Assert(OperatingSystem.IsWindows());
|
Environment.Exit(0);
|
||||||
|
return true;
|
||||||
// Of note, this is an async method in squirrel that adds an arbitrary delay before returning
|
}
|
||||||
// likely to ensure the external process is in a good state.
|
catch (Exception e)
|
||||||
//
|
{
|
||||||
// We're not waiting on that here, but the outro playing before the actual exit should be enough
|
Logger.Error(e, "Failed to restart application");
|
||||||
// to cover this.
|
return base.RestartAppWhenExited();
|
||||||
Squirrel.UpdateManager.RestartAppWhenExited().FireAndForget();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.RestartAppWhenExited();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using osu.Desktop.LegacyIpc;
|
using osu.Desktop.LegacyIpc;
|
||||||
using osu.Desktop.Windows;
|
using osu.Desktop.Windows;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
@ -14,7 +13,7 @@ using osu.Game;
|
|||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Game.Tournament;
|
using osu.Game.Tournament;
|
||||||
using SDL;
|
using SDL;
|
||||||
using Squirrel;
|
using Velopack;
|
||||||
|
|
||||||
namespace osu.Desktop
|
namespace osu.Desktop
|
||||||
{
|
{
|
||||||
@ -66,10 +65,10 @@ namespace osu.Desktop
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSquirrel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupVelo();
|
||||||
|
|
||||||
// NVIDIA profiles are based on the executable name of a process.
|
// NVIDIA profiles are based on the executable name of a process.
|
||||||
// Lazer and stable share the same executable name.
|
// Lazer and stable share the same executable name.
|
||||||
// Stable sets this setting to "Off", which may not be what we want, so let's force it back to the default "Auto" on startup.
|
// Stable sets this setting to "Off", which may not be what we want, so let's force it back to the default "Auto" on startup.
|
||||||
@ -177,32 +176,14 @@ namespace osu.Desktop
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
private static void setupVelo()
|
||||||
private static void setupSquirrel()
|
|
||||||
{
|
{
|
||||||
SquirrelAwareApp.HandleEvents(onInitialInstall: (_, tools) =>
|
VelopackApp
|
||||||
{
|
.Build()
|
||||||
tools.CreateShortcutForThisExe();
|
.WithFirstRun(v =>
|
||||||
tools.CreateUninstallerRegistryEntry();
|
{
|
||||||
WindowsAssociationManager.InstallAssociations();
|
if (OperatingSystem.IsWindows()) WindowsAssociationManager.InstallAssociations();
|
||||||
}, onAppUpdate: (_, tools) =>
|
}).Run();
|
||||||
{
|
|
||||||
tools.CreateUninstallerRegistryEntry();
|
|
||||||
WindowsAssociationManager.UpdateAssociations();
|
|
||||||
}, onAppUninstall: (_, tools) =>
|
|
||||||
{
|
|
||||||
tools.RemoveShortcutForThisExe();
|
|
||||||
tools.RemoveUninstallerRegistryEntry();
|
|
||||||
WindowsAssociationManager.UninstallAssociations();
|
|
||||||
}, onEveryRun: (_, _, _) =>
|
|
||||||
{
|
|
||||||
// While setting the `ProcessAppUserModelId` fixes duplicate icons/shortcuts on the taskbar, it currently
|
|
||||||
// causes the right-click context menu to function incorrectly.
|
|
||||||
//
|
|
||||||
// This may turn out to be non-required after an alternative solution is implemented.
|
|
||||||
// see https://github.com/clowd/Clowd.Squirrel/issues/24
|
|
||||||
// tools.SetProcessAppUserModelId();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -10,30 +9,15 @@ using osu.Game;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using Squirrel.SimpleSplat;
|
using osu.Game.Updater;
|
||||||
using Squirrel.Sources;
|
|
||||||
using LogLevel = Squirrel.SimpleSplat.LogLevel;
|
|
||||||
using UpdateManager = osu.Game.Updater.UpdateManager;
|
|
||||||
|
|
||||||
namespace osu.Desktop.Updater
|
namespace osu.Desktop.Updater
|
||||||
{
|
{
|
||||||
[SupportedOSPlatform("windows")]
|
public partial class VeloUpdateManager : UpdateManager
|
||||||
public partial class SquirrelUpdateManager : UpdateManager
|
|
||||||
{
|
{
|
||||||
private Squirrel.UpdateManager? updateManager;
|
private Velopack.UpdateManager? updateManager;
|
||||||
private INotificationOverlay notificationOverlay = null!;
|
private INotificationOverlay notificationOverlay = null!;
|
||||||
|
|
||||||
public Task PrepareUpdateAsync() => Squirrel.UpdateManager.RestartAppWhenExited();
|
|
||||||
|
|
||||||
private static readonly Logger logger = Logger.GetLogger("updater");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether an update has been downloaded but not yet applied.
|
|
||||||
/// </summary>
|
|
||||||
private bool updatePending;
|
|
||||||
|
|
||||||
private readonly SquirrelLogger squirrelLogger = new SquirrelLogger();
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuGameBase game { get; set; } = null!;
|
private OsuGameBase game { get; set; } = null!;
|
||||||
|
|
||||||
@ -44,13 +28,11 @@ namespace osu.Desktop.Updater
|
|||||||
private void load(INotificationOverlay notifications)
|
private void load(INotificationOverlay notifications)
|
||||||
{
|
{
|
||||||
notificationOverlay = notifications;
|
notificationOverlay = notifications;
|
||||||
|
|
||||||
SquirrelLocator.CurrentMutable.Register(() => squirrelLogger, typeof(ILogger));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<bool> PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false);
|
protected override async Task<bool> PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
private async Task<bool> checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification? notification = null)
|
private async Task<bool> checkForUpdateAsync(UpdateProgressNotification? notification = null)
|
||||||
{
|
{
|
||||||
// should we schedule a retry on completion of this check?
|
// should we schedule a retry on completion of this check?
|
||||||
bool scheduleRecheck = true;
|
bool scheduleRecheck = true;
|
||||||
@ -63,27 +45,27 @@ namespace osu.Desktop.Updater
|
|||||||
if (localUserInfo?.IsPlaying.Value == true)
|
if (localUserInfo?.IsPlaying.Value == true)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
updateManager ??= new Squirrel.UpdateManager(new GithubSource(@"https://github.com/ppy/osu", github_token, false), @"osulazer");
|
updateManager ??= new Velopack.UpdateManager(new Velopack.Sources.GithubSource(@"https://github.com/ppy/osu", github_token, false));
|
||||||
|
|
||||||
var info = await updateManager.CheckForUpdate(!useDeltaPatching).ConfigureAwait(false);
|
var info = await updateManager.CheckForUpdatesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (info.ReleasesToApply.Count == 0)
|
if (info == null)
|
||||||
{
|
{
|
||||||
if (updatePending)
|
// If there is an update pending restart, show the notification again.
|
||||||
|
if (updateManager.IsUpdatePendingRestart)
|
||||||
{
|
{
|
||||||
// the user may have dismissed the completion notice, so show it again.
|
|
||||||
notificationOverlay.Post(new UpdateApplicationCompleteNotification
|
notificationOverlay.Post(new UpdateApplicationCompleteNotification
|
||||||
{
|
{
|
||||||
Activated = () =>
|
Activated = () =>
|
||||||
{
|
{
|
||||||
restartToApplyUpdate();
|
restartToApplyUpdate();
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no updates available. bail and retry later.
|
// Otherwise there's no updates available. Bail and retry later.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,31 +85,17 @@ namespace osu.Desktop.Updater
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await updateManager.DownloadReleases(info.ReleasesToApply, p => notification.Progress = p / 100f).ConfigureAwait(false);
|
await updateManager.DownloadUpdatesAsync(info, p => notification.Progress = p / 100f).ConfigureAwait(false);
|
||||||
|
|
||||||
notification.StartInstall();
|
notification.StartInstall();
|
||||||
|
|
||||||
await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f).ConfigureAwait(false);
|
|
||||||
|
|
||||||
notification.State = ProgressNotificationState.Completed;
|
notification.State = ProgressNotificationState.Completed;
|
||||||
updatePending = true;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (useDeltaPatching)
|
|
||||||
{
|
|
||||||
logger.Add(@"delta patching failed; will attempt full download!");
|
|
||||||
|
|
||||||
// could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
|
|
||||||
// try again without deltas.
|
|
||||||
await checkForUpdateAsync(false, notification).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// In the case of an error, a separate notification will be displayed.
|
// In the case of an error, a separate notification will be displayed.
|
||||||
notification.FailDownload();
|
notification.FailDownload();
|
||||||
Logger.Error(e, @"update failed!");
|
Logger.Error(e, @"update failed!");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
@ -149,32 +117,12 @@ namespace osu.Desktop.Updater
|
|||||||
|
|
||||||
private bool restartToApplyUpdate()
|
private bool restartToApplyUpdate()
|
||||||
{
|
{
|
||||||
PrepareUpdateAsync()
|
if (updateManager == null)
|
||||||
.ContinueWith(_ => Schedule(() => game.AttemptExit()));
|
return false;
|
||||||
|
|
||||||
|
updateManager.WaitExitThenApplyUpdates(null);
|
||||||
|
Schedule(() => game.AttemptExit());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
updateManager?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SquirrelLogger : ILogger, IDisposable
|
|
||||||
{
|
|
||||||
public LogLevel Level { get; set; } = LogLevel.Info;
|
|
||||||
|
|
||||||
public void Write(string message, LogLevel logLevel)
|
|
||||||
{
|
|
||||||
if (logLevel < Level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
logger.Add(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,10 +23,10 @@
|
|||||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Clowd.Squirrel" Version="2.11.1" />
|
|
||||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||||
<PackageReference Include="System.IO.Packaging" Version="8.0.0" />
|
<PackageReference Include="System.IO.Packaging" Version="8.0.0" />
|
||||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||||
|
<PackageReference Include="Velopack" Version="0.0.359" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Resources">
|
<ItemGroup Label="Resources">
|
||||||
<EmbeddedResource Include="lazer.ico" />
|
<EmbeddedResource Include="lazer.ico" />
|
||||||
|
Loading…
Reference in New Issue
Block a user