128 lines
4.4 KiB
C#
128 lines
4.4 KiB
C#
using System.Net;
|
|
using System.Security;
|
|
using System.Text.Json;
|
|
using AcDream.Launcher.Core.Orchestration;
|
|
using AcDream.Launcher.Core.Updates;
|
|
using AcDream.Launcher.ViewModels;
|
|
using AcDream.Platform;
|
|
|
|
namespace AcDream.Launcher;
|
|
|
|
/// <summary>
|
|
/// Testable startup transaction for versioned-client/update services. Storage
|
|
/// failures produce a fail-closed executable resolver and an unavailable UI
|
|
/// projection; they do not abort profile/installer window construction.
|
|
/// </summary>
|
|
internal sealed class LauncherUpdateComposition : IDisposable
|
|
{
|
|
private readonly HttpClient? _artifactClient;
|
|
private readonly ReleaseManifestClient? _manifestClient;
|
|
|
|
private LauncherUpdateComposition(
|
|
ClientVersionStore versions,
|
|
LauncherExecutableSet executables,
|
|
ILauncherUpdater updater,
|
|
HttpClient? artifactClient,
|
|
ReleaseManifestClient? manifestClient)
|
|
{
|
|
Versions = versions;
|
|
Executables = executables;
|
|
Updater = updater;
|
|
_artifactClient = artifactClient;
|
|
_manifestClient = manifestClient;
|
|
}
|
|
|
|
public ClientVersionStore Versions { get; }
|
|
|
|
public LauncherExecutableSet Executables { get; }
|
|
|
|
public ILauncherUpdater Updater { get; }
|
|
|
|
public static LauncherUpdateComposition Create(
|
|
ApplicationPathSet paths,
|
|
string rid,
|
|
LauncherVersion launcherVersion,
|
|
string launcherTargetDirectory,
|
|
Func<bool> hasRunningSessions,
|
|
Func<ClientVersionStore, string, ClientVersionResolution>? initialize = null)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(paths);
|
|
ArgumentNullException.ThrowIfNull(launcherVersion);
|
|
ArgumentNullException.ThrowIfNull(hasRunningSessions);
|
|
var versions = new ClientVersionStore(paths);
|
|
HttpClient? artifactClient = null;
|
|
ReleaseManifestClient? manifestClient = null;
|
|
try
|
|
{
|
|
_ = initialize is null
|
|
? versions.LoadAndRecoverAsync(rid).GetAwaiter().GetResult()
|
|
: initialize(versions, rid);
|
|
artifactClient = new HttpClient(
|
|
new HttpClientHandler
|
|
{
|
|
AllowAutoRedirect = false,
|
|
UseCookies = false,
|
|
AutomaticDecompression = DecompressionMethods.None,
|
|
},
|
|
disposeHandler: true)
|
|
{
|
|
Timeout = TimeSpan.FromSeconds(15),
|
|
};
|
|
artifactClient.DefaultRequestHeaders.UserAgent.ParseAdd("acdream-launcher/1");
|
|
manifestClient = new ReleaseManifestClient(TimeSpan.FromSeconds(15));
|
|
var selfUpdates = new LauncherSelfUpdateManager(paths, artifactClient);
|
|
var updater = new LauncherUpdater(
|
|
manifestClient,
|
|
artifactClient,
|
|
versions,
|
|
selfUpdates,
|
|
launcherVersion,
|
|
rid,
|
|
launcherTargetDirectory,
|
|
hasRunningSessions);
|
|
return new LauncherUpdateComposition(
|
|
versions,
|
|
LauncherExecutableSet.FromCurrentVersionStore(versions),
|
|
updater,
|
|
artifactClient,
|
|
manifestClient);
|
|
}
|
|
catch (Exception ex) when (IsStorageFailure(ex))
|
|
{
|
|
manifestClient?.Dispose();
|
|
artifactClient?.Dispose();
|
|
string status = "Versioned client update storage is unavailable: "
|
|
+ (string.IsNullOrWhiteSpace(ex.Message)
|
|
? "the storage operation failed."
|
|
: ex.Message);
|
|
var resolution = new ClientVersionResolution(
|
|
ClientVersionState.Invalid,
|
|
status,
|
|
null,
|
|
null,
|
|
null,
|
|
null);
|
|
return new LauncherUpdateComposition(
|
|
versions,
|
|
LauncherExecutableSet.Unavailable(status),
|
|
new UnavailableLauncherUpdater(status, resolution),
|
|
artifactClient: null,
|
|
manifestClient: null);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_manifestClient?.Dispose();
|
|
_artifactClient?.Dispose();
|
|
}
|
|
|
|
private static bool IsStorageFailure(Exception exception) => exception is
|
|
IOException
|
|
or UnauthorizedAccessException
|
|
or SecurityException
|
|
or JsonException
|
|
or FormatException
|
|
or NotSupportedException
|
|
or LauncherUpdateException;
|
|
}
|