1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2024-11-25 07:42:58 +01:00

Compare commits

..

2 Commits

7 changed files with 40 additions and 34 deletions

View File

@ -59,7 +59,7 @@ sealed class BackupScheduler : CancellableBackgroundTask {
} }
try { try {
return await context.Actor.Request(new InstanceActor.BackupInstanceCommand(backupManager, CancellationToken)); return await context.Actor.Request(new InstanceActor.BackupInstanceCommand(backupManager));
} finally { } finally {
backupSemaphore.Release(); backupSemaphore.Release();
} }

View File

@ -13,28 +13,32 @@ using Phantom.Utils.Logging;
namespace Phantom.Agent.Services.Instances; namespace Phantom.Agent.Services.Instances;
sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> { sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
public readonly record struct Init(Guid InstanceGuid, string ShortName, InstanceServices Services, AgentState AgentState); public readonly record struct Init(AgentState AgentState, Guid InstanceGuid, string ShortName, InstanceServices InstanceServices, InstanceTicketManager InstanceTicketManager, CancellationToken ShutdownCancellationToken);
public static Props<ICommand> Factory(Init init) { public static Props<ICommand> Factory(Init init) {
return Props<ICommand>.Create(() => new InstanceActor(init), new ActorConfiguration { SupervisorStrategy = SupervisorStrategies.Resume, MailboxType = UnboundedJumpAheadMailbox.Name }); return Props<ICommand>.Create(() => new InstanceActor(init), new ActorConfiguration { SupervisorStrategy = SupervisorStrategies.Resume, MailboxType = UnboundedJumpAheadMailbox.Name });
} }
private readonly Guid instanceGuid;
private readonly InstanceServices services;
private readonly AgentState agentState; private readonly AgentState agentState;
private readonly CancellationToken shutdownCancellationToken;
private readonly Guid instanceGuid;
private readonly InstanceServices instanceServices;
private readonly InstanceTicketManager instanceTicketManager;
private readonly InstanceContext context; private readonly InstanceContext context;
private IInstanceStatus currentStatus = InstanceStatus.NotRunning; private IInstanceStatus currentStatus = InstanceStatus.NotRunning;
private InstanceRunningState? runningState = null; private InstanceRunningState? runningState = null;
private InstanceActor(Init init) { private InstanceActor(Init init) {
this.instanceGuid = init.InstanceGuid;
this.services = init.Services;
this.agentState = init.AgentState; this.agentState = init.AgentState;
this.instanceGuid = init.InstanceGuid;
this.instanceServices = init.InstanceServices;
this.instanceTicketManager = init.InstanceTicketManager;
this.shutdownCancellationToken = init.ShutdownCancellationToken;
var logger = PhantomLogger.Create<InstanceActor>(init.ShortName); var logger = PhantomLogger.Create<InstanceActor>(init.ShortName);
this.context = new InstanceContext(instanceGuid, init.ShortName, logger, services, SelfTyped); this.context = new InstanceContext(instanceGuid, init.ShortName, logger, instanceServices, SelfTyped);
Receive<ReportInstanceStatusCommand>(ReportInstanceStatus); Receive<ReportInstanceStatusCommand>(ReportInstanceStatus);
ReceiveAsync<LaunchInstanceCommand>(LaunchInstance); ReceiveAsync<LaunchInstanceCommand>(LaunchInstance);
@ -52,7 +56,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
private void ReportCurrentStatus() { private void ReportCurrentStatus() {
agentState.UpdateInstance(new Instance(instanceGuid, currentStatus)); agentState.UpdateInstance(new Instance(instanceGuid, currentStatus));
services.ControllerConnection.Send(new ReportInstanceStatusMessage(instanceGuid, currentStatus)); instanceServices.ControllerConnection.Send(new ReportInstanceStatusMessage(instanceGuid, currentStatus));
} }
private void TransitionState(InstanceRunningState? newState) { private void TransitionState(InstanceRunningState? newState) {
@ -60,10 +64,6 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
return; return;
} }
if (runningState is not null && newState is null) {
context.Services.InstanceTicketManager.Release(runningState.Ticket);
}
runningState?.Dispose(); runningState?.Dispose();
runningState = newState; runningState = newState;
runningState?.Initialize(); runningState?.Initialize();
@ -73,13 +73,13 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
public sealed record ReportInstanceStatusCommand : ICommand; public sealed record ReportInstanceStatusCommand : ICommand;
public sealed record LaunchInstanceCommand(InstanceConfiguration Configuration, IServerLauncher Launcher, InstanceTicketManager.Ticket Ticket, bool IsRestarting, CancellationToken CancellationToken) : ICommand; public sealed record LaunchInstanceCommand(InstanceConfiguration Configuration, IServerLauncher Launcher, InstanceTicketManager.Ticket Ticket, bool IsRestarting) : ICommand;
public sealed record StopInstanceCommand(MinecraftStopStrategy StopStrategy, CancellationToken CancellationToken) : ICommand; public sealed record StopInstanceCommand(MinecraftStopStrategy StopStrategy) : ICommand;
public sealed record SendCommandToInstanceCommand(string Command, CancellationToken CancellationToken) : ICommand, ICanReply<SendCommandToInstanceResult>; public sealed record SendCommandToInstanceCommand(string Command) : ICommand, ICanReply<SendCommandToInstanceResult>;
public sealed record BackupInstanceCommand(BackupManager BackupManager, CancellationToken CancellationToken) : ICommand, ICanReply<BackupCreationResult>; public sealed record BackupInstanceCommand(BackupManager BackupManager) : ICommand, ICanReply<BackupCreationResult>;
public sealed record HandleProcessEndedCommand(IInstanceStatus Status) : ICommand, IJumpAhead; public sealed record HandleProcessEndedCommand(IInstanceStatus Status) : ICommand, IJumpAhead;
@ -93,9 +93,9 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
if (command.IsRestarting || runningState is null) { if (command.IsRestarting || runningState is null) {
SetAndReportStatus(command.IsRestarting ? InstanceStatus.Restarting : InstanceStatus.Launching); SetAndReportStatus(command.IsRestarting ? InstanceStatus.Restarting : InstanceStatus.Launching);
var newState = await InstanceLaunchProcedure.Run(context, command.Configuration, command.Launcher, command.Ticket, SetAndReportStatus, command.CancellationToken); var newState = await InstanceLaunchProcedure.Run(context, command.Configuration, command.Launcher, instanceTicketManager, command.Ticket, SetAndReportStatus, shutdownCancellationToken);
if (newState is null) { if (newState is null) {
context.Services.InstanceTicketManager.Release(command.Ticket); instanceTicketManager.Release(command.Ticket);
} }
TransitionState(newState); TransitionState(newState);
@ -110,7 +110,8 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
IInstanceStatus oldStatus = currentStatus; IInstanceStatus oldStatus = currentStatus;
SetAndReportStatus(InstanceStatus.Stopping); SetAndReportStatus(InstanceStatus.Stopping);
if (await InstanceStopProcedure.Run(context, command.StopStrategy, runningState, SetAndReportStatus, command.CancellationToken)) { if (await InstanceStopProcedure.Run(context, command.StopStrategy, runningState, SetAndReportStatus, shutdownCancellationToken)) {
instanceTicketManager.Release(runningState.Ticket);
TransitionState(null); TransitionState(null);
} }
else { else {
@ -123,7 +124,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
return SendCommandToInstanceResult.InstanceNotRunning; return SendCommandToInstanceResult.InstanceNotRunning;
} }
else { else {
return await runningState.SendCommand(command.Command, command.CancellationToken); return await runningState.SendCommand(command.Command, shutdownCancellationToken);
} }
} }
@ -132,7 +133,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
return new BackupCreationResult(BackupCreationResultKind.InstanceNotRunning); return new BackupCreationResult(BackupCreationResultKind.InstanceNotRunning);
} }
else { else {
return await command.BackupManager.CreateBackup(context.ShortName, runningState.Process, command.CancellationToken); return await command.BackupManager.CreateBackup(context.ShortName, runningState.Process, shutdownCancellationToken);
} }
} }
@ -140,12 +141,13 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
if (runningState is { Process.HasEnded: true }) { if (runningState is { Process.HasEnded: true }) {
SetAndReportStatus(command.Status); SetAndReportStatus(command.Status);
context.ReportEvent(InstanceEvent.Stopped); context.ReportEvent(InstanceEvent.Stopped);
instanceTicketManager.Release(runningState.Ticket);
TransitionState(null); TransitionState(null);
} }
} }
private async Task Shutdown(ShutdownCommand command) { private async Task Shutdown(ShutdownCommand command) {
await StopInstance(new StopInstanceCommand(MinecraftStopStrategy.Instant, CancellationToken.None)); await StopInstance(new StopInstanceCommand(MinecraftStopStrategy.Instant));
Context.Stop(Self); Context.Stop(Self);
} }
} }

View File

@ -20,7 +20,7 @@ namespace Phantom.Agent.Services.Instances;
sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand> { sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand> {
private static readonly ILogger Logger = PhantomLogger.Create<InstanceManagerActor>(); private static readonly ILogger Logger = PhantomLogger.Create<InstanceManagerActor>();
public readonly record struct Init(ControllerConnection ControllerConnection, AgentFolders AgentFolders, AgentState AgentState, JavaRuntimeRepository JavaRuntimeRepository, InstanceTicketManager TicketManager, TaskManager TaskManager, BackupManager BackupManager); public readonly record struct Init(ControllerConnection ControllerConnection, AgentFolders AgentFolders, AgentState AgentState, JavaRuntimeRepository JavaRuntimeRepository, InstanceTicketManager InstanceTicketManager, TaskManager TaskManager, BackupManager BackupManager);
public static Props<ICommand> Factory(Init init) { public static Props<ICommand> Factory(Init init) {
return Props<ICommand>.Create(() => new InstanceManagerActor(init), new ActorConfiguration { SupervisorStrategy = SupervisorStrategies.Resume }); return Props<ICommand>.Create(() => new InstanceManagerActor(init), new ActorConfiguration { SupervisorStrategy = SupervisorStrategies.Resume });
@ -30,6 +30,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
private readonly string basePath; private readonly string basePath;
private readonly InstanceServices instanceServices; private readonly InstanceServices instanceServices;
private readonly InstanceTicketManager instanceTicketManager;
private readonly Dictionary<Guid, InstanceInfo> instances = new (); private readonly Dictionary<Guid, InstanceInfo> instances = new ();
private readonly CancellationTokenSource shutdownCancellationTokenSource = new (); private readonly CancellationTokenSource shutdownCancellationTokenSource = new ();
@ -40,12 +41,13 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
private InstanceManagerActor(Init init) { private InstanceManagerActor(Init init) {
this.agentState = init.AgentState; this.agentState = init.AgentState;
this.basePath = init.AgentFolders.InstancesFolderPath; this.basePath = init.AgentFolders.InstancesFolderPath;
this.instanceTicketManager = init.InstanceTicketManager;
this.shutdownCancellationToken = shutdownCancellationTokenSource.Token; this.shutdownCancellationToken = shutdownCancellationTokenSource.Token;
var minecraftServerExecutables = new MinecraftServerExecutables(init.AgentFolders.ServerExecutableFolderPath); var minecraftServerExecutables = new MinecraftServerExecutables(init.AgentFolders.ServerExecutableFolderPath);
var launchServices = new LaunchServices(minecraftServerExecutables, init.JavaRuntimeRepository); var launchServices = new LaunchServices(minecraftServerExecutables, init.JavaRuntimeRepository);
this.instanceServices = new InstanceServices(init.ControllerConnection, init.TaskManager, init.TicketManager, init.BackupManager, launchServices); this.instanceServices = new InstanceServices(init.ControllerConnection, init.TaskManager, init.BackupManager, launchServices);
ReceiveAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance); ReceiveAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
ReceiveAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance); ReceiveAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
@ -116,7 +118,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
} }
} }
else { else {
var instanceInit = new InstanceActor.Init(instanceGuid, GetInstanceLoggerName(instanceGuid), instanceServices, agentState); var instanceInit = new InstanceActor.Init(agentState, instanceGuid, GetInstanceLoggerName(instanceGuid), instanceServices, instanceTicketManager, shutdownCancellationToken);
instances[instanceGuid] = instance = new InstanceInfo(Context.ActorOf(InstanceActor.Factory(instanceInit), "Instance-" + instanceGuid), configuration, launcher); instances[instanceGuid] = instance = new InstanceInfo(Context.ActorOf(InstanceActor.Factory(instanceInit), "Instance-" + instanceGuid), configuration, launcher);
Logger.Information("Created instance \"{Name}\" (GUID {Guid}).", configuration.InstanceName, instanceGuid); Logger.Information("Created instance \"{Name}\" (GUID {Guid}).", configuration.InstanceName, instanceGuid);
@ -137,7 +139,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
return InstanceActionResult.General<LaunchInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist); return InstanceActionResult.General<LaunchInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
} }
var ticket = instanceServices.InstanceTicketManager.Reserve(instanceInfo.Configuration); var ticket = instanceTicketManager.Reserve(instanceInfo.Configuration);
if (ticket is Result<InstanceTicketManager.Ticket, LaunchInstanceResult>.Fail fail) { if (ticket is Result<InstanceTicketManager.Ticket, LaunchInstanceResult>.Fail fail) {
return InstanceActionResult.Concrete(fail.Error); return InstanceActionResult.Concrete(fail.Error);
} }
@ -153,7 +155,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
} }
// TODO report status? // TODO report status?
instanceInfo.Actor.Tell(new InstanceActor.LaunchInstanceCommand(instanceInfo.Configuration, instanceInfo.Launcher, ticket.Value, IsRestarting: false, shutdownCancellationToken)); instanceInfo.Actor.Tell(new InstanceActor.LaunchInstanceCommand(instanceInfo.Configuration, instanceInfo.Launcher, ticket.Value, IsRestarting: false));
return InstanceActionResult.Concrete(LaunchInstanceResult.LaunchInitiated); return InstanceActionResult.Concrete(LaunchInstanceResult.LaunchInitiated);
} }
@ -173,7 +175,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
} }
} }
instanceInfo.Actor.Tell(new InstanceActor.StopInstanceCommand(command.StopStrategy, shutdownCancellationToken)); instanceInfo.Actor.Tell(new InstanceActor.StopInstanceCommand(command.StopStrategy));
return InstanceActionResult.Concrete(StopInstanceResult.StopInitiated); return InstanceActionResult.Concrete(StopInstanceResult.StopInitiated);
} }
@ -184,7 +186,7 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
} }
try { try {
return InstanceActionResult.Concrete(await instanceInfo.Actor.Request(new InstanceActor.SendCommandToInstanceCommand(command.Command, shutdownCancellationToken), shutdownCancellationToken)); return InstanceActionResult.Concrete(await instanceInfo.Actor.Request(new InstanceActor.SendCommandToInstanceCommand(command.Command), shutdownCancellationToken));
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.AgentShuttingDown); return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.AgentShuttingDown);
} }

View File

@ -5,4 +5,4 @@ using Phantom.Utils.Tasks;
namespace Phantom.Agent.Services.Instances; namespace Phantom.Agent.Services.Instances;
sealed record InstanceServices(ControllerConnection ControllerConnection, TaskManager TaskManager, InstanceTicketManager InstanceTicketManager, BackupManager BackupManager, LaunchServices LaunchServices); sealed record InstanceServices(ControllerConnection ControllerConnection, TaskManager TaskManager, BackupManager BackupManager, LaunchServices LaunchServices);

View File

@ -7,12 +7,12 @@ using Phantom.Utils.Tasks;
namespace Phantom.Agent.Services.Instances.State; namespace Phantom.Agent.Services.Instances.State;
static class InstanceLaunchProcedure { static class InstanceLaunchProcedure {
public static async Task<InstanceRunningState?> Run(InstanceContext context, InstanceConfiguration configuration, IServerLauncher launcher, InstanceTicketManager.Ticket ticket, Action<IInstanceStatus> reportStatus, CancellationToken cancellationToken) { public static async Task<InstanceRunningState?> Run(InstanceContext context, InstanceConfiguration configuration, IServerLauncher launcher, InstanceTicketManager ticketManager, InstanceTicketManager.Ticket ticket, Action<IInstanceStatus> reportStatus, CancellationToken cancellationToken) {
context.Logger.Information("Session starting..."); context.Logger.Information("Session starting...");
Result<InstanceProcess, InstanceLaunchFailReason> result; Result<InstanceProcess, InstanceLaunchFailReason> result;
if (context.Services.InstanceTicketManager.IsValid(ticket)) { if (ticketManager.IsValid(ticket)) {
try { try {
result = await LaunchInstance(context, launcher, reportStatus, cancellationToken); result = await LaunchInstance(context, launcher, reportStatus, cancellationToken);
} catch (OperationCanceledException) { } catch (OperationCanceledException) {

View File

@ -72,7 +72,7 @@ sealed class InstanceRunningState : IDisposable {
else { else {
context.Logger.Information("Session ended unexpectedly, restarting..."); context.Logger.Information("Session ended unexpectedly, restarting...");
context.ReportEvent(InstanceEvent.Crashed); context.ReportEvent(InstanceEvent.Crashed);
context.Actor.Tell(new InstanceActor.LaunchInstanceCommand(configuration, launcher, Ticket, IsRestarting: true, cancellationToken)); context.Actor.Tell(new InstanceActor.LaunchInstanceCommand(configuration, launcher, Ticket, IsRestarting: true));
} }
} }

View File

@ -75,6 +75,8 @@ static class InstanceStopProcedure {
// Ignore. // Ignore.
} catch (ObjectDisposedException e) when (e.ObjectName == typeof(Process).FullName && process.HasEnded) { } catch (ObjectDisposedException e) when (e.ObjectName == typeof(Process).FullName && process.HasEnded) {
// Ignore. // Ignore.
} catch (IOException e) when (e.HResult == -2147024664 /* The pipe is being closed */) {
// Ignore.
} catch (Exception e) { } catch (Exception e) {
context.Logger.Warning(e, "Caught exception while sending stop command."); context.Logger.Warning(e, "Caught exception while sending stop command.");
} }