This commit is contained in:
Cyberboss
2018-07-04 17:02:29 -04:00
parent 72a7adc40c
commit 7842fcbbda
13 changed files with 51 additions and 117 deletions
+1 -2
View File
@@ -47,10 +47,9 @@ namespace Tgstation.Server.Host.Service
/// </summary>
public void OnExecute()
{
if((Install || Uninstall) && !IsAdministrator())
if ((Install || Uninstall) && !IsAdministrator())
{
//try to restart as admin
var currentProcess = Process.GetCurrentProcess();
var argList = Environment.GetCommandLineArgs().ToList();
//its windows, first arg is .exe name guaranteed
var exe = argList.First();
@@ -8,7 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Models;
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components
@@ -45,18 +45,14 @@ namespace Tgstation.Server.Host.Components
/// </summary>
readonly IConfiguration configuration;
/// <summary>
/// The <see cref="IDreamDaemonExecutor"/> for <see cref="DreamMaker"/>
/// The <see cref="ISessionControllerFactory"/> for <see cref="DreamMaker"/>
/// </summary>
readonly IDreamDaemonExecutor dreamDaemonExecutor;
readonly ISessionControllerFactory sessionControllerFactory;
/// <summary>
/// The <see cref="IByond"/> for <see cref="DreamMaker"/>
/// </summary>
readonly IByond byond;
/// <summary>
/// The <see cref="IInterop"/> for <see cref="DreamMaker"/>
/// </summary>
readonly IInterop interop;
/// <summary>
/// The <see cref="ICompileJobConsumer"/> for <see cref="DreamMaker"/>
/// </summary>
readonly ICompileJobConsumer compileJobConsumer;
@@ -76,13 +72,11 @@ namespace Tgstation.Server.Host.Components
/// <param name="compileJobConsumer">The value of <see cref="compileJobConsumer"/></param>
/// <param name="application">The value of <see cref="application"/></param>
///
public DreamMaker(IIOManager ioManager, IConfiguration configuration, IDreamDaemonExecutor dreamDaemonExecutor, IByond byond, IInterop interop, ICompileJobConsumer compileJobConsumer, IApplication application)
public DreamMaker(IIOManager ioManager, IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, ICompileJobConsumer compileJobConsumer, IApplication application)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
this.dreamDaemonExecutor = dreamDaemonExecutor ?? throw new ArgumentNullException(nameof(dreamDaemonExecutor));
this.byond = byond ?? throw new ArgumentNullException(nameof(byond));
this.interop = interop ?? throw new ArgumentNullException(nameof(interop));
this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory));
this.compileJobConsumer = compileJobConsumer ?? throw new ArgumentNullException(nameof(compileJobConsumer));
this.application = application ?? throw new ArgumentNullException(nameof(application));
}
@@ -91,10 +85,10 @@ namespace Tgstation.Server.Host.Components
/// Run a quick DD instance to test the DMAPI is installed on the target code
/// </summary>
/// <param name="dreamDaemonPath">The path to the DreamDaemon executable</param>
/// <param name="job">The <see cref="Host.Models.CompileJob"/> for the operation</param>
/// <param name="job">The <see cref="Models.CompileJob"/> for the operation</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if the DMAPI was successfully validated, <see langword="false"/> otherwise</returns>
async Task<bool> VerifyApi(string dreamDaemonPath, Host.Models.CompileJob job, CancellationToken cancellationToken)
async Task<bool> VerifyApi(string dreamDaemonPath, Models.CompileJob job, CancellationToken cancellationToken)
{
var launchParameters = new DreamDaemonLaunchParameters
{
@@ -2,11 +2,24 @@
namespace Tgstation.Server.Host.Components
{
/// <summary>
/// Represents usage of the two primary BYOND server executables
/// </summary>
public interface IByondExecutableLock : IDisposable
{
/// <summary>
/// The path to the DreamDaemon executable
/// </summary>
string DreamDaemonPath { get; set; }
/// <summary>
/// The path to the dm/DreamMaker executable
/// </summary>
string DreamMakerPath { get; set; }
/// <summary>
/// Call if, during a detach, this version should not be deleted
/// </summary>
void DoNotDeleteThisSession();
}
}
@@ -1,16 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Components
{
/// <summary>
/// Handles communication with the DMAPI
/// </summary>
interface IInterop
{
IInteropControl ReconnectToRun(string primaryAccessToken, string secondaryAccessToken, ushort primaryPort, ushort secondaryPort);
IInteropControl CreateRun(ushort primaryPort, ushort? secondaryPort, Func<ChatMessageEventArgs, CancellationToken, Task> chatMessageHandler);
}
}
@@ -1,30 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Components
{
/// <summary>
/// For monitoring DreamDaemon uptime
/// </summary>
interface IWatchdog
{
/// <summary>
/// The latest <see cref="Host.Models.CompileJob"/> used by the <see cref="IWatchdog"/>
/// </summary>
Host.Models.CompileJob CurrentCompileJob { get; }
/// <summary>
/// Start the <see cref="IWatchdog"/>
/// </summary>
/// <param name="launchParametersFactory">The <see cref="ILaunchParametersFactory"/> for the run</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task Start(ILaunchParametersFactory launchParametersFactory, CancellationToken cancellationToken);
/// <summary>
/// Stop the <see cref="IWatchdog"/>
/// </summary>
/// <returns>A <see cref="Task"/> representing the running operation</returns>
Task Stop();
}
}
@@ -1,20 +0,0 @@
using System;
namespace Tgstation.Server.Host.Components
{
/// <summary>
/// Represents a DreamDaemon control request or notification
/// </summary>
sealed class ServerControlEvent : EventArgs
{
/// <summary>
/// The <see cref="ServerControlEventType"/>
/// </summary>
public ServerControlEventType EventType { get; set; }
/// <summary>
/// If the message was sent from the primary server
/// </summary>
public bool FromPrimaryServer { get; set; }
}
}
@@ -1,25 +0,0 @@
namespace Tgstation.Server.Host.Components
{
/// <summary>
/// Indicates a server control event from a DreamDaemon instance
/// </summary>
enum ServerControlEventType
{
/// <summary>
/// The server is loaded
/// </summary>
ServerPrimed,
/// <summary>
/// The server called world/Reboot()
/// </summary>
ServerRebooting,
/// <summary>
/// The server requested that it's process be terminated
/// </summary>
RequestedProcessTermination,
/// <summary>
/// The server has stopped responding to heartbeats
/// </summary>
ServerUnresponsive,
}
}
@@ -33,5 +33,7 @@ namespace Tgstation.Server.Host.Components
/// <inheritdoc />
public void Dispose() { }
public void KeepAlive() => throw new NotSupportedException();
}
}
@@ -30,15 +30,15 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
/// <inheritdoc />
public ISession AttachToDreamDaemon(int processId) => new Session(Process.GetProcessById(processId));
public ISession AttachToDreamDaemon(int processId, IByondExecutableLock byondLock) => new Session(Process.GetProcessById(processId), byondLock);
/// <inheritdoc />
public ISession RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, string dreamDaemonPath, IDmbProvider dmbProvider, string parameters, bool useSecondaryPort, bool useSecondaryDirectory)
public ISession RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, IByondExecutableLock byondLock, IDmbProvider dmbProvider, string parameters, bool useSecondaryPort, bool useSecondaryDirectory)
{
if (launchParameters == null)
throw new ArgumentNullException(nameof(launchParameters));
if (dreamDaemonPath == null)
throw new ArgumentNullException(nameof(dreamDaemonPath));
if (byondLock == null)
throw new ArgumentNullException(nameof(byondLock));
if (dmbProvider == null)
throw new ArgumentNullException(nameof(dmbProvider));
if (parameters == null)
@@ -48,7 +48,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
try
{
proc.StartInfo.FileName = dreamDaemonPath;
proc.StartInfo.FileName = byondLock.DreamDaemonPath;
proc.StartInfo.WorkingDirectory = useSecondaryDirectory ? dmbProvider.SecondaryDirectory : dmbProvider.PrimaryDirectory;
proc.StartInfo.Arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}\"",
@@ -60,7 +60,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
proc.Start();
return new Session(proc);
return new Session(proc, byondLock);
}
catch
{
@@ -12,18 +12,19 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// </summary>
/// <param name="launchParameters">The <see cref="DreamDaemonLaunchParameters"/></param>
/// <param name="onSuccessfulStartup">The <see cref="TaskCompletionSource{TResult}"/> that is completed when dream daemon starts without crashing</param>
/// <param name="dreamDaemonPath">The path to the dreamdaemon executable</param>
/// <param name="byondLock">The <see cref="IByondExecutableLock"/> for the new <see cref="ISession"/></param>
/// <param name="dmbProvider">The <see cref="IDmbProvider"/> for the .dmb to run</param>
/// <param name="parameters">The value of the -params command line option</param>
/// <param name="useSecondaryPort">If the <see cref="DreamDaemonLaunchParameters.SecondaryPort"/> field of <paramref name="launchParameters"/> should be used</param>
/// <returns>A new <see cref="ISession"/></returns>
ISession RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, string dreamDaemonPath, IDmbProvider dmbProvider, string parameters, bool useSecondaryPort, bool useSecondaryDirectory);
ISession RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, IByondExecutableLock byondLock, IDmbProvider dmbProvider, string parameters, bool useSecondaryPort, bool useSecondaryDirectory);
/// <summary>
/// Attach to a running instance of DreamDaemon
/// </summary>
/// <param name="processId">The <see cref="ISession.ProcessId"/></param>
/// <param name="byondLock">The <see cref="IByondExecutableLock"/> for the new <see cref="ISession"/></param>
/// <returns>A new <see cref="ISession"/></returns>
ISession AttachToDreamDaemon(int processId);
ISession AttachToDreamDaemon(int processId, IByondExecutableLock byondLock);
}
}
@@ -20,6 +20,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The actual <see cref="Process"/>
/// </summary>
readonly Process process;
/// <summary>
/// The <see cref="IByondExecutableLock"/> for the <see cref="process"/>
/// </summary>
readonly IByondExecutableLock byondLock;
/// <summary>
/// The backing <see cref="TaskCompletionSource{TResult}"/> for <see cref="Lifetime"/>
/// </summary>
@@ -29,9 +34,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// Construct a <see cref="Session"/>
/// </summary>
/// <param name="process">The value of <see cref="process"/></param>
public Session(Process process)
/// <param name="byondLock">The value of <see cref="byondLock"/></param>
public Session(Process process, IByondExecutableLock byondLock)
{
this.process = process ?? throw new ArgumentNullException(nameof(process));
this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
LaunchResult = Task.Factory.StartNew(() =>
{
@@ -110,7 +110,10 @@ namespace Tgstation.Server.Host.Components.Watchdog
var byondLock = byond.UseExecutables(dmbProvider.CompileJob.ByondVersion);
try
{
var session = executor.RunDreamDaemon(launchParameters, byondLock, dmbProvider, /*TODO*/, !primaryPort, !primaryDirectory);
var parameters = String.Format(CultureInfo.InvariantCulture, "server_service_version={0}&tgs_json={1}", application.Version, interopJsonFile);
var session = executor.RunDreamDaemon(launchParameters, byondLock, dmbProvider, parameters, !primaryPort, !primaryDirectory);
try
{
return new SessionController(new ReattachInformation
@@ -1,4 +1,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
namespace Tgstation.Server.Host.Components.Watchdog
@@ -6,6 +8,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <inheritdoc />
sealed class Watchdog : IWatchdog
{
/// <inheritdoc />
public DreamDaemonLaunchParameters LaunchParameters
{
get => launchParameters;
@@ -74,5 +77,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
disposed = true;
}
}
/// <inheritdoc />
public Task<WatchdogLaunchResult> Launch(CancellationToken cancellationToken) => throw new NotImplementedException();
}
}