diff --git a/src/Tgstation.Server.Api/Models/DreamDaemon.cs b/src/Tgstation.Server.Api/Models/DreamDaemon.cs
index 49571a3fa3..4a332b36dd 100644
--- a/src/Tgstation.Server.Api/Models/DreamDaemon.cs
+++ b/src/Tgstation.Server.Api/Models/DreamDaemon.cs
@@ -18,7 +18,7 @@ namespace Tgstation.Server.Api.Models
/// The current status of
///
[Permissions(DenyWrite = true, ReadRight = DreamDaemonRights.ReadMetadata)]
- public DreamDaemonStatus? Status { get; set; }
+ public bool? Running { get; set; }
///
/// The current of
diff --git a/src/Tgstation.Server.Host/Components/DreamDaemon.cs b/src/Tgstation.Server.Host/Components/DreamDaemon.cs
new file mode 100644
index 0000000000..6ca1a8fc6b
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/DreamDaemon.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+using Tgstation.Server.Api.Models;
+using Tgstation.Server.Api.Models.Internal;
+using Tgstation.Server.Host.Core;
+using Tgstation.Server.Host.Security;
+
+namespace Tgstation.Server.Host.Components
+{
+ ///
+ sealed class DreamDaemon : IDreamDaemon, IDisposable
+ {
+ ///
+ public bool Running { get; private set; }
+
+ ///
+ public ushort? CurrentPort { get; private set; }
+
+ ///
+ public string AccessToken { get; private set; }
+
+ ///
+ public DreamDaemonSecurity? CurrentSecurity { get; private set; }
+
+ ///
+ public bool SoftRebooting { get; private set; }
+
+ ///
+ public bool SoftStopping { get; private set; }
+
+ ///
+ /// The for
+ ///
+ readonly IEventConsumer eventConsumer;
+ ///
+ /// The for
+ ///
+ readonly IByond byond;
+ ///
+ /// The for
+ ///
+ readonly ICryptographySuite cryptographySuite;
+ ///
+ /// The for
+ ///
+ readonly IInterop interop;
+ ///
+ /// The for
+ ///
+ readonly IInstanceShutdownMethod instanceShutdownMethod;
+ readonly IIOManager ioManager;
+
+ readonly bool autoStart;
+
+ readonly SemaphoreSlim semaphore;
+
+ DreamDaemonLaunchParameters currentLaunchParameters;
+
+ CancellationTokenSource watchdogCancellationTokenSource;
+ Task watchdogTask;
+
+ public DreamDaemon(IEventConsumer eventConsumer, IByond byond, ICryptographySuite cryptographySuite, IInterop interop, IInstanceShutdownMethod instanceShutdownMethod, DreamDaemonSettings initialSettings)
+ {
+ this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
+ this.byond = byond ?? throw new ArgumentNullException(nameof(byond));
+ this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
+ this.interop = interop ?? throw new ArgumentNullException(nameof(interop));
+ this.instanceShutdownMethod = instanceShutdownMethod ?? throw new ArgumentNullException(nameof(instanceShutdownMethod));
+
+ interop.SetServerControlHandler(OnServerControl);
+
+ currentLaunchParameters = initialSettings ?? throw new ArgumentNullException(nameof(initialSettings));
+ autoStart = initialSettings.AutoStart;
+
+ semaphore = new SemaphoreSlim(1);
+ }
+
+ public void Dispose()
+ {
+ if (watchdogCancellationTokenSource != null)
+ watchdogCancellationTokenSource.Dispose();
+ semaphore.Dispose();
+ }
+
+ Task OnServerControl(ServerControlEventArgs serverControlEventArgs, CancellationToken cancellationToken)
+ {
+ lock (this)
+ {
+ CancelGracefulActions();
+ if (serverControlEventArgs.ProcessRestart)
+ return Restart(serverControlEventArgs.Graceful, cancellationToken);
+ if(!serverControlEventArgs.ServerReboot)
+ return Terminate(serverControlEventArgs.Graceful, cancellationToken);
+ return Task.CompletedTask;
+ }
+ }
+
+ static string SecurityWord(DreamDaemonSecurity securityLevel)
+ {
+ switch (securityLevel)
+ {
+ case DreamDaemonSecurity.Safe:
+ return "safe";
+ case DreamDaemonSecurity.Trusted:
+ return "trusted";
+ case DreamDaemonSecurity.Ultrasafe:
+ return "ultrasafe";
+ default:
+ throw new ArgumentOutOfRangeException(nameof(securityLevel), securityLevel, String.Format(CultureInfo.InvariantCulture, "Bad DreamDaemon security level: {0}", securityLevel));
+ }
+ }
+
+ async Task Watchdog(DreamDaemonLaunchParameters launchParameters, TaskCompletionSource
bool Running { get; }
+ ///
+ /// If DreamDaemon is going to soft reboot
+ ///
+ bool SoftRebooting { get; }
+
+ ///
+ /// If DreamDaemon is going to soft stop
+ ///
+ bool SoftStopping { get; }
+
///
/// The port DreamDaemon is currently running on
///
ushort? CurrentPort { get; }
+ ///
+ /// The current of
+ ///
+ DreamDaemonSecurity? CurrentSecurity { get; }
+
///
/// The access token used for communication with the DMAPI
///
@@ -37,7 +53,9 @@ namespace Tgstation.Server.Host.Components
/// Changes the if currently . Triggers a graceful restart
///
/// The new
- void ChangeSettings(DreamDaemonLaunchParameters launchParameters);
+ /// The for the operation
+ /// A representing the running operation
+ Task ChangeSettings(DreamDaemonLaunchParameters launchParameters, CancellationToken cancellationToken);
///
/// Restarts DreamDaemon
diff --git a/src/Tgstation.Server.Host/Components/IInstanceManager.cs b/src/Tgstation.Server.Host/Components/IInstanceManager.cs
index d63384a3fd..356a2fd9c8 100644
--- a/src/Tgstation.Server.Host/Components/IInstanceManager.cs
+++ b/src/Tgstation.Server.Host/Components/IInstanceManager.cs
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Components
///
/// For managing s
///
- interface IInstanceManager
+ interface IInstanceManager : IInstanceShutdownMethod
{
///
/// Get the associated with given
diff --git a/src/Tgstation.Server.Host/Components/IInstanceShutdownMethod.cs b/src/Tgstation.Server.Host/Components/IInstanceShutdownMethod.cs
new file mode 100644
index 0000000000..14ced74d67
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/IInstanceShutdownMethod.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tgstation.Server.Host.Components
+{
+ interface IInstanceShutdownMethod
+ {
+ bool GracefulShutdown { get; set; }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/IInterop.cs b/src/Tgstation.Server.Host/Components/IInterop.cs
index 7c1d0e67ad..bc42312136 100644
--- a/src/Tgstation.Server.Host/Components/IInterop.cs
+++ b/src/Tgstation.Server.Host/Components/IInterop.cs
@@ -9,15 +9,15 @@ namespace Tgstation.Server.Host.Components
///
interface IInterop
{
- event EventHandler OnServerControl;
- event EventHandler OnChatMessage;
+ void SetServerControlHandler(Func serverControlHandler);
+ void SetChatMessageHandler(Func chatMessageHandler);
Version MinimumApiVersion { get; }
Version MaximumApiVersion { get; }
Task GetApiVersion(CancellationToken cancellationToken);
- void SetActivePort(ushort? port);
+ void SetRun(ushort? port, string accessToken);
Task ChatCommand(string command, string arguments, CancellationToken cancellationToken);
diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs
index 92947c72a9..ae48802658 100644
--- a/src/Tgstation.Server.Host/Components/InstanceManager.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs
@@ -14,6 +14,9 @@ namespace Tgstation.Server.Host.Components
///
sealed class InstanceManager : IInstanceManager, IHostedService
{
+ ///
+ public bool GracefulShutdown { get; set; }
+
///
/// The for the
///
diff --git a/src/Tgstation.Server.Host/Components/ServerControlEventArgs.cs b/src/Tgstation.Server.Host/Components/ServerControlEventArgs.cs
index a0c12a243f..ba9b7b2bef 100644
--- a/src/Tgstation.Server.Host/Components/ServerControlEventArgs.cs
+++ b/src/Tgstation.Server.Host/Components/ServerControlEventArgs.cs
@@ -10,16 +10,16 @@ namespace Tgstation.Server.Host.Components
///
/// If the event will result in a new run of the world
///
- bool ServerReboot { get; set; }
+ public bool ServerReboot { get; set; }
///
/// If the event will result in a restart of the process. If both this and are , the server is being terminated
///
- bool ProcessRestart { get; set; }
-
+ public bool ProcessRestart { get; set; }
+
///
/// If the action to be taken is graceful
///
- bool Graceful { get; set; }
+ public bool Graceful { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Security/CryptographySuite.cs b/src/Tgstation.Server.Host/Security/CryptographySuite.cs
index a3c5553030..b0f68e7a5c 100644
--- a/src/Tgstation.Server.Host/Security/CryptographySuite.cs
+++ b/src/Tgstation.Server.Host/Security/CryptographySuite.cs
@@ -56,5 +56,8 @@ namespace Tgstation.Server.Host.Security
}
return true;
}
+
+ ///
+ public string GetSecureString() => Convert.ToBase64String(GetSecureBytes(30));
}
}
diff --git a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs
index b19f805871..137cbf54ff 100644
--- a/src/Tgstation.Server.Host/Security/ICryptographySuite.cs
+++ b/src/Tgstation.Server.Host/Security/ICryptographySuite.cs
@@ -21,5 +21,11 @@ namespace Tgstation.Server.Host.Security
/// The password to check
/// if matches the hash, otherwise
bool CheckUserPassword(User user, string password);
+
+ ///
+ /// Generates a 40-length secure ascii
+ ///
+ /// A 40-length secure ascii
+ string GetSecureString();
}
}
diff --git a/src/Tgstation.Server.Host/Server.cs b/src/Tgstation.Server.Host/Server.cs
index 506424c49c..6d73783284 100644
--- a/src/Tgstation.Server.Host/Server.cs
+++ b/src/Tgstation.Server.Host/Server.cs
@@ -10,7 +10,7 @@ using Tgstation.Server.Host.Startup;
namespace Tgstation.Server.Host
{
///
- sealed class Server : IServer, IServerUpdateConsumer
+ sealed class Server : IServer, IServerControl
{
///
public string UpdatePath { get; private set; }
@@ -39,7 +39,7 @@ namespace Tgstation.Server.Host
using (cancellationTokenSource)
using (var webHost = webHostBuilder
.UseStartup()
- .ConfigureServices((serviceCollection) => serviceCollection.AddSingleton(this))
+ .ConfigureServices((serviceCollection) => serviceCollection.AddSingleton(this))
.Build()
)
await webHost.RunAsync(cancellationToken).ConfigureAwait(false);