fix(launcher): close LA4 review findings
This commit is contained in:
parent
d0a9c65d85
commit
10a712d66b
19 changed files with 1631 additions and 134 deletions
|
|
@ -99,6 +99,12 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
return platformCapability;
|
||||
}
|
||||
|
||||
LauncherCapability executableCapability = _executables.GetAvailability(mode);
|
||||
if (!executableCapability.IsAvailable)
|
||||
{
|
||||
return executableCapability;
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
|
@ -108,6 +114,33 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
}
|
||||
}
|
||||
|
||||
public LauncherCapability GetAccountLaunchCapability(
|
||||
string serverName,
|
||||
string accountName,
|
||||
LaunchMode mode)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(serverName);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(accountName);
|
||||
|
||||
LauncherCapability capability = GetLaunchCapability(mode);
|
||||
if (!capability.IsAvailable)
|
||||
{
|
||||
return capability;
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
_ = FindAccountLocked(serverName, accountName);
|
||||
ManagedActivity? active = FindActiveActivityLocked(serverName, accountName);
|
||||
return active is null
|
||||
? LauncherCapability.Available
|
||||
: LauncherCapability.Unavailable(
|
||||
$"Stop the running {active.Kind.ToString().ToLowerInvariant()} "
|
||||
+ "for this account before starting another activity.");
|
||||
}
|
||||
}
|
||||
|
||||
public LauncherCapability GetProbeCapability(string serverName, string accountName)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(serverName);
|
||||
|
|
@ -120,6 +153,13 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
return platformCapability;
|
||||
}
|
||||
|
||||
LauncherCapability executableCapability =
|
||||
_executables.GetAvailability(LaunchMode.Headless);
|
||||
if (!executableCapability.IsAvailable)
|
||||
{
|
||||
return executableCapability;
|
||||
}
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
|
@ -254,7 +294,7 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
public Task<LauncherSessionSnapshot> LaunchAsync(
|
||||
string serverName,
|
||||
string accountName,
|
||||
string characterName,
|
||||
string? characterName,
|
||||
LaunchMode mode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
|
@ -268,12 +308,38 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
lock (_gate)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (FindActiveActivityLocked(serverName, accountName) is not null)
|
||||
{
|
||||
throw new LauncherOperationException(
|
||||
"A session or character refresh is already running for this account.");
|
||||
}
|
||||
|
||||
ServerProfile server = FindServerLocked(serverName);
|
||||
AccountProfile account = FindAccountLocked(serverName, accountName);
|
||||
CharacterProfile character = FindCharacterLocked(
|
||||
serverName,
|
||||
accountName,
|
||||
characterName);
|
||||
CharacterProfile character;
|
||||
if (string.IsNullOrWhiteSpace(characterName))
|
||||
{
|
||||
if (mode != LaunchMode.GuiSelect)
|
||||
{
|
||||
throw new LauncherOperationException(
|
||||
"Select a cached character for GUI or headless launch.");
|
||||
}
|
||||
|
||||
character = new CharacterProfile
|
||||
{
|
||||
Name = string.Empty,
|
||||
LaunchMode = LaunchMode.GuiSelect,
|
||||
Plugins = [],
|
||||
LoginCommands = [],
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
character = FindCharacterLocked(
|
||||
serverName,
|
||||
accountName,
|
||||
characterName);
|
||||
}
|
||||
LauncherInstallRecord install = _installRecord
|
||||
?? throw new LauncherOperationException(FirstRunRequired);
|
||||
|
||||
|
|
@ -283,7 +349,7 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
LauncherActivityKind.Play,
|
||||
server.Name,
|
||||
account.Account,
|
||||
character.Name,
|
||||
string.IsNullOrWhiteSpace(characterName) ? null : character.Name,
|
||||
mode,
|
||||
"Preparing session configuration…");
|
||||
_activities.Add(activity);
|
||||
|
|
@ -620,9 +686,12 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
|
||||
lock (_gate)
|
||||
{
|
||||
request.Activity.State = LauncherActivityState.Cancelled;
|
||||
request.Activity.Status = "Operation cancelled.";
|
||||
request.Activity.Error = null;
|
||||
if (!request.Activity.IsTerminal)
|
||||
{
|
||||
request.Activity.State = LauncherActivityState.Cancelled;
|
||||
request.Activity.Status = "Operation cancelled.";
|
||||
request.Activity.Error = null;
|
||||
}
|
||||
}
|
||||
|
||||
RaiseStateChanged();
|
||||
|
|
@ -638,9 +707,12 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
password);
|
||||
lock (_gate)
|
||||
{
|
||||
request.Activity.State = LauncherActivityState.Failed;
|
||||
request.Activity.Status = message;
|
||||
request.Activity.Error = message;
|
||||
if (!request.Activity.IsTerminal)
|
||||
{
|
||||
request.Activity.State = LauncherActivityState.Failed;
|
||||
request.Activity.Status = message;
|
||||
request.Activity.Error = message;
|
||||
}
|
||||
}
|
||||
|
||||
RaiseStateChanged();
|
||||
|
|
@ -681,15 +753,19 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
}
|
||||
break;
|
||||
case LauncherSessionState.Exited:
|
||||
activity.ExitCode = activity.Supervisor?.ExitCode;
|
||||
if (activity.State is not (
|
||||
LauncherActivityState.Failed
|
||||
or LauncherActivityState.Cancelled))
|
||||
activity.ExitCode ??= activity.Supervisor?.ExitCode;
|
||||
if (!activity.IsTerminal)
|
||||
{
|
||||
activity.State = LauncherActivityState.Exited;
|
||||
activity.Status = activity.ExitCode is int code
|
||||
? $"Host process exited with code {code}."
|
||||
: "Host process exited.";
|
||||
activity.Status = activity.HostTerminalStatus
|
||||
?? (activity.ExitCode is int code
|
||||
? $"Host process exited with code {code}."
|
||||
: "Host process exited.");
|
||||
}
|
||||
else if (activity.State == LauncherActivityState.Exited
|
||||
&& activity.HostTerminalStatus is not null)
|
||||
{
|
||||
activity.Status = activity.HostTerminalStatus;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -723,6 +799,27 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
return;
|
||||
}
|
||||
|
||||
if (activity.IsTerminal)
|
||||
{
|
||||
switch (statusEvent)
|
||||
{
|
||||
case ExitedStatusEvent exited:
|
||||
activity.ExitCode ??= exited.Code;
|
||||
activity.HostTerminalStatus ??=
|
||||
$"Exited: {exited.Reason} (code {exited.Code}).";
|
||||
if (activity.State == LauncherActivityState.Exited)
|
||||
{
|
||||
activity.Status = activity.HostTerminalStatus;
|
||||
}
|
||||
break;
|
||||
case CharacterListStatusEvent roster:
|
||||
ApplyRosterLocked(activity, roster, updateStatus: false);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (statusEvent)
|
||||
{
|
||||
case StartedStatusEvent:
|
||||
|
|
@ -762,7 +859,9 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
case ExitedStatusEvent exited:
|
||||
activity.State = LauncherActivityState.Exited;
|
||||
activity.ExitCode = exited.Code;
|
||||
activity.Status = $"Exited: {exited.Reason} (code {exited.Code}).";
|
||||
activity.HostTerminalStatus =
|
||||
$"Exited: {exited.Reason} (code {exited.Code}).";
|
||||
activity.Status = activity.HostTerminalStatus;
|
||||
break;
|
||||
case MalformedStatusEvent malformed:
|
||||
activity.Error = $"Malformed host status event: {malformed.Error}";
|
||||
|
|
@ -778,7 +877,8 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
|
||||
private void ApplyRosterLocked(
|
||||
ManagedActivity activity,
|
||||
CharacterListStatusEvent roster)
|
||||
CharacterListStatusEvent roster,
|
||||
bool updateStatus = true)
|
||||
{
|
||||
if (!string.Equals(
|
||||
roster.AccountName,
|
||||
|
|
@ -792,19 +892,22 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
|
||||
try
|
||||
{
|
||||
_profileStore.MergeRoster(
|
||||
activity.ServerName,
|
||||
activity.AccountName,
|
||||
roster.Characters
|
||||
.Select(character => new CharacterRosterEntry(
|
||||
character.Id,
|
||||
character.Name,
|
||||
character.SecondsGreyedOut))
|
||||
.ToArray());
|
||||
_profileStore.Save();
|
||||
activity.Status = roster.Characters.Count == 1
|
||||
? "Character roster refreshed: 1 character."
|
||||
: $"Character roster refreshed: {roster.Characters.Count} characters.";
|
||||
_profileStore.ExecuteTransaction(() =>
|
||||
_profileStore.MergeRoster(
|
||||
activity.ServerName,
|
||||
activity.AccountName,
|
||||
roster.Characters
|
||||
.Select(character => new CharacterRosterEntry(
|
||||
character.Id,
|
||||
character.Name,
|
||||
character.SecondsGreyedOut))
|
||||
.ToArray()));
|
||||
if (updateStatus)
|
||||
{
|
||||
activity.Status = roster.Characters.Count == 1
|
||||
? "Character roster refreshed: 1 character."
|
||||
: $"Character roster refreshed: {roster.Characters.Count} characters.";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -812,7 +915,10 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
"Could not save the refreshed character roster",
|
||||
ex,
|
||||
secret: null);
|
||||
activity.Status = activity.Error;
|
||||
if (updateStatus)
|
||||
{
|
||||
activity.Status = activity.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -879,8 +985,7 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
lock (_gate)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
mutation();
|
||||
_profileStore.Save();
|
||||
_profileStore.ExecuteTransaction(mutation);
|
||||
}
|
||||
|
||||
RaiseStateChanged();
|
||||
|
|
@ -1125,6 +1230,8 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
|
||||
public string? Error { get; set; }
|
||||
|
||||
public string? HostTerminalStatus { get; set; }
|
||||
|
||||
public ILauncherProcessSupervisor? Supervisor { get; set; }
|
||||
|
||||
public EventHandler<LauncherSessionState>? SupervisorStateHandler { get; set; }
|
||||
|
|
@ -1140,6 +1247,8 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
or LauncherActivityState.Failed
|
||||
or LauncherActivityState.Cancelled);
|
||||
|
||||
public bool IsTerminal => !IsActive;
|
||||
|
||||
public LauncherSessionSnapshot ToSnapshot() =>
|
||||
new(
|
||||
SessionId,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue