mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2024-11-22 16:42:51 +01:00
90 lines
3.0 KiB
C#
90 lines
3.0 KiB
C#
using System.Diagnostics;
|
|
using Phantom.Agent.Minecraft.Command;
|
|
using Phantom.Agent.Minecraft.Instance;
|
|
using Phantom.Common.Data.Instance;
|
|
using Phantom.Common.Data.Minecraft;
|
|
using Phantom.Common.Data.Replies;
|
|
|
|
namespace Phantom.Agent.Services.Instances.States;
|
|
|
|
sealed class InstanceStoppingState : IInstanceState, IDisposable {
|
|
private readonly InstanceContext context;
|
|
private readonly InstanceProcess process;
|
|
private readonly IDisposable sessionDisposer;
|
|
|
|
public InstanceStoppingState(InstanceContext context, InstanceProcess process, IDisposable sessionDisposer) {
|
|
this.context = context;
|
|
this.process = process;
|
|
this.sessionDisposer = sessionDisposer;
|
|
}
|
|
|
|
public void Initialize() {
|
|
context.Logger.Information("Session stopping.");
|
|
context.SetStatus(InstanceStatus.Stopping);
|
|
context.Services.TaskManager.Run("Stop procedure for instance " + context.ShortName, DoStop);
|
|
}
|
|
|
|
private async Task DoStop() {
|
|
try {
|
|
// Do not release the semaphore after this point.
|
|
if (!await process.BackupSemaphore.CancelAndWait(TimeSpan.FromSeconds(1))) {
|
|
context.Logger.Information("Waiting for backup to finish...");
|
|
await process.BackupSemaphore.CancelAndWait(Timeout.InfiniteTimeSpan);
|
|
}
|
|
|
|
context.Logger.Information("Sending stop command...");
|
|
await DoSendStopCommand();
|
|
|
|
context.Logger.Information("Waiting for session to end...");
|
|
await DoWaitForSessionToEnd();
|
|
} finally {
|
|
context.Logger.Information("Session stopped.");
|
|
context.ReportEvent(InstanceEvent.Stopped);
|
|
context.TransitionState(new InstanceNotRunningState(), InstanceStatus.NotRunning);
|
|
}
|
|
}
|
|
|
|
private async Task DoSendStopCommand() {
|
|
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
|
try {
|
|
await process.SendCommand(MinecraftCommand.Stop, timeout.Token);
|
|
} catch (OperationCanceledException) {
|
|
// ignore
|
|
} catch (ObjectDisposedException e) when (e.ObjectName == typeof(Process).FullName && process.HasEnded) {
|
|
// ignore
|
|
} catch (Exception e) {
|
|
context.Logger.Warning(e, "Caught exception while sending stop command.");
|
|
}
|
|
}
|
|
|
|
private async Task DoWaitForSessionToEnd() {
|
|
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(55));
|
|
try {
|
|
await process.WaitForExit(timeout.Token);
|
|
} catch (OperationCanceledException) {
|
|
try {
|
|
context.Logger.Warning("Waiting timed out, killing session...");
|
|
process.Kill();
|
|
} catch (Exception e) {
|
|
context.Logger.Error(e, "Caught exception while killing session.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public (IInstanceState, LaunchInstanceResult) Launch(InstanceContext context) {
|
|
return (this, LaunchInstanceResult.InstanceIsStopping);
|
|
}
|
|
|
|
public (IInstanceState, StopInstanceResult) Stop(MinecraftStopStrategy stopStrategy) {
|
|
return (this, StopInstanceResult.InstanceAlreadyStopping); // TODO maybe provide a way to kill?
|
|
}
|
|
|
|
public Task<bool> SendCommand(string command, CancellationToken cancellationToken) {
|
|
return Task.FromResult(false);
|
|
}
|
|
|
|
public void Dispose() {
|
|
sessionDisposer.Dispose();
|
|
}
|
|
}
|