acdream/src/AcDream.Launcher/App.axaml.cs

127 lines
4.5 KiB
C#

using System.Reflection;
using AcDream.Launcher.Core.Installation;
using AcDream.Launcher.Core.Launching;
using AcDream.Launcher.Core.Orchestration;
using AcDream.Launcher.Core.Profiles;
using AcDream.Launcher.Core.Updates;
using AcDream.Launcher.ViewModels;
using AcDream.Platform;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace AcDream.Launcher;
public sealed partial class App : Application
{
private readonly LauncherStartupOptions? _startupOptions;
private LauncherOrchestrator? _orchestrator;
private LauncherWindowViewModel? _viewModel;
private LauncherUpdateComposition? _updateComposition;
public App()
{
}
internal App(LauncherStartupOptions startupOptions)
{
_startupOptions = startupOptions
?? throw new ArgumentNullException(nameof(startupOptions));
}
internal LauncherStartupOptions StartupOptions => _startupOptions
?? throw new InvalidOperationException(
"Launcher startup options were not supplied by the composition root.");
public override void Initialize() => AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
LauncherStartupOptions startupOptions = StartupOptions;
ApplicationPathSet paths = startupOptions.Paths;
LauncherProfileStore profiles = LauncherProfileStore.ForApplicationPaths(paths);
string rid = LauncherRuntimeIdentity.DetectRid();
string executableSuffix = OperatingSystem.IsWindows() ? ".exe" : string.Empty;
var installer = new LauncherInstaller(
paths,
Path.Combine(
AppContext.BaseDirectory,
"acdream-bake" + executableSuffix));
InstallRecordVerification verification;
try
{
// Hashing the package before constructing the orchestrator is
// intentional: no launch action is enabled until the persisted
// size/SHA/tool-version record has been verified.
verification = installer.LoadExistingAsync()
.GetAwaiter()
.GetResult();
}
catch (Exception ex)
{
verification = new InstallRecordVerification(
InstallRecordVerificationState.Invalid,
null,
$"Client content verification failed: {ex.Message}");
}
LauncherUpdateComposition updates = LauncherUpdateComposition.Create(
paths,
rid,
GetLauncherVersion(),
AppContext.BaseDirectory,
() => _orchestrator?.GetSnapshot().Sessions.Any(session => session.IsActive)
== true,
updateManifestUri: startupOptions.UpdateManifestUri);
_updateComposition = updates;
_orchestrator = new LauncherOrchestrator(
profiles,
paths,
updates.Executables,
verification.Record,
installationStatus: verification.Status,
updateSessionBarrier: updates.Versions.Barrier);
_viewModel = new LauncherWindowViewModel(
_orchestrator,
new AvaloniaUiDispatcher(),
installer,
updates.Updater);
_viewModel.Initialize();
desktop.MainWindow = new MainWindow
{
DataContext = _viewModel,
};
desktop.Exit += OnDesktopExit;
}
base.OnFrameworkInitializationCompleted();
}
private void OnDesktopExit(object? sender, ControlledApplicationLifetimeExitEventArgs e)
{
_viewModel?.Dispose();
_orchestrator?.Dispose();
_updateComposition?.Dispose();
_viewModel = null;
_orchestrator = null;
_updateComposition = null;
}
private static LauncherVersion GetLauncherVersion()
{
string? informationalVersion = typeof(App).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
.InformationalVersion;
if (!LauncherVersion.TryParse(informationalVersion, out LauncherVersion? version))
{
throw new InvalidOperationException(
$"Launcher informational version '{informationalVersion}' is not SemVer 2.0.");
}
return version;
}
}