127 lines
4.5 KiB
C#
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;
|
|
}
|
|
}
|