Remove Executor and Session

This commit is contained in:
Cyberboss
2018-08-10 10:51:58 -04:00
parent fb8aa23960
commit fbbe03f1d2
10 changed files with 90 additions and 256 deletions
@@ -52,11 +52,6 @@ namespace Tgstation.Server.Host.Components
/// </summary>
readonly ICryptographySuite cryptographySuite;
/// <summary>
/// The <see cref="IExecutor"/> for the <see cref="InstanceFactory"/>
/// </summary>
readonly IExecutor executor;
/// <summary>
/// The <see cref="ISynchronousIOManager"/> for the <see cref="InstanceFactory"/>
/// </summary>
@@ -92,13 +87,12 @@ namespace Tgstation.Server.Host.Components
/// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param>
/// <param name="serverUpdater">The value of <see cref="serverUpdater"/></param>
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
/// <param name="executor">The value of <see cref="executor"/></param>
/// <param name="synchronousIOManager">The value of <see cref="synchronousIOManager"/></param>
/// <param name="symlinkFactory">The value of <see cref="symlinkFactory"/></param>
/// <param name="byondInstaller">The value of <see cref="byondInstaller"/></param>
/// <param name="providerFactory">The value of <see cref="providerFactory"/></param>
/// <param name="processExecutor">The value of <see cref="processExecutor"/></param>
public InstanceFactory(IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILoggerFactory loggerFactory, IByondTopicSender byondTopicSender, IServerControl serverUpdater, ICryptographySuite cryptographySuite, IExecutor executor, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IByondInstaller byondInstaller, IProviderFactory providerFactory, IProcessExecutor processExecutor)
public InstanceFactory(IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILoggerFactory loggerFactory, IByondTopicSender byondTopicSender, IServerControl serverUpdater, ICryptographySuite cryptographySuite, ISynchronousIOManager synchronousIOManager, ISymlinkFactory symlinkFactory, IByondInstaller byondInstaller, IProviderFactory providerFactory, IProcessExecutor processExecutor)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
@@ -106,8 +100,7 @@ namespace Tgstation.Server.Host.Components
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater));
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite ));
this.executor = executor ?? throw new ArgumentNullException(nameof(executor));
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
this.synchronousIOManager = synchronousIOManager ?? throw new ArgumentNullException(nameof(synchronousIOManager));
this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory));
this.byondInstaller = byondInstaller ?? throw new ArgumentNullException(nameof(byondInstaller));
@@ -144,7 +137,7 @@ namespace Tgstation.Server.Host.Components
var chat = chatFactory.CreateChat(metadata.ChatSettings);
try
{
var sessionControllerFactory = new SessionControllerFactory(executor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, loggerFactory, metadata.CloneMetadata());
var sessionControllerFactory = new SessionControllerFactory(processExecutor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, loggerFactory, metadata.CloneMetadata());
var reattachInfoHandler = new ReattachInfoHandler(databaseContextFactory, dmbFactory, metadata.CloneMetadata());
var watchdogFactory = new WatchdogFactory(chat, sessionControllerFactory, serverUpdater, loggerFactory, reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, metadata.CloneMetadata());
var watchdog = watchdogFactory.CreateWatchdog(dmbFactory, metadata.DreamDaemonSettings);
@@ -1,87 +0,0 @@
using Microsoft.Extensions.Logging;
using System;
using System.Globalization;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components.Watchdog
{
/// <inheritdoc />
sealed class Executor : IExecutor
{
/// <summary>
/// The <see cref="IProcessExecutor"/> for the <see cref="Executor"/>
/// </summary>
readonly IProcessExecutor processExecutor;
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="Executor"/>
/// </summary>
readonly ILogger<Executor> logger;
/// <summary>
/// Change a given <paramref name="securityLevel"/> into the appropriate DreamDaemon command line word
/// </summary>
/// <param name="securityLevel">The <see cref="DreamDaemonSecurity"/> level to change</param>
/// <returns>A <see cref="string"/> representation of the command line parameter</returns>
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));
}
}
/// <summary>
/// Construct an <see cref="Executor"/>
/// </summary>
/// <param name="processExecutor">The value of <see cref="processExecutor"/></param>
/// <param name="logger">The value of <see cref="logger"/></param>
public Executor(IProcessExecutor processExecutor, ILogger<Executor> logger)
{
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <inheritdoc />
public ISession AttachToDreamDaemon(int processId, IByondExecutableLock byondLock) => new Session(processExecutor.GetProcess(processId), byondLock);
/// <inheritdoc />
public ISession RunDreamDaemon(DreamDaemonLaunchParameters launchParameters, IByondExecutableLock byondLock, IDmbProvider dmbProvider, string parameters, bool useSecondaryPort, bool useSecondaryDirectory)
{
if (launchParameters == null)
throw new ArgumentNullException(nameof(launchParameters));
if (byondLock == null)
throw new ArgumentNullException(nameof(byondLock));
if (dmbProvider == null)
throw new ArgumentNullException(nameof(dmbProvider));
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));
var fileName = byondLock.DreamDaemonPath;
var workingDirectory = useSecondaryDirectory ? dmbProvider.SecondaryDirectory : dmbProvider.PrimaryDirectory;
var arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}\"",
dmbProvider.DmbName,
useSecondaryPort ? launchParameters.SecondaryPort : launchParameters.PrimaryPort,
launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty,
SecurityWord(launchParameters.SecurityLevel.Value),
parameters);
logger.LogTrace("Running DreamDaemon in {0}: {1} {2}", workingDirectory, fileName, arguments);
var proc = processExecutor.LaunchProcess(fileName, workingDirectory, arguments);
return new Session(proc, byondLock);
}
}
}
@@ -1,31 +0,0 @@
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Byond;
namespace Tgstation.Server.Host.Components.Watchdog
{
/// <summary>
/// For creating <see cref="ISession"/>s
/// </summary>
interface IExecutor
{
/// <summary>
/// Run a dream daemon instance
/// </summary>
/// <param name="launchParameters">The <see cref="DreamDaemonLaunchParameters"/></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>
/// <param name="useSecondaryDirectory">If the <see cref="IDmbProvider.SecondaryDirectory"/> field of <paramref name="dmbProvider"/> should be used</param>
/// <returns>A new <see cref="ISession"/></returns>
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, IByondExecutableLock byondLock);
}
}
@@ -1,11 +0,0 @@
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components.Watchdog
{
/// <summary>
/// Represents a dream daemon process
/// </summary>
interface ISession : ISessionBase, IProcess
{
}
}
@@ -1,13 +0,0 @@
using System.Threading.Tasks;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components.Watchdog
{
interface ISessionBase : IProcessBase
{
/// <summary>
/// A <see cref="Task"/> that completes when DreamDaemon starts pumping the windows message queue after loading a .dmb or when it crashes
/// </summary>
Task<LaunchResult> LaunchResult { get; }
}
}
@@ -1,20 +1,26 @@
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components.Watchdog
{
/// <summary>
/// Handles communication with a <see cref="ISession"/>
/// Handles communication with a DreamDaemon <see cref="IProcess"/>
/// </summary>
interface ISessionController : ISessionBase
interface ISessionController : IProcessBase
{
/// <summary>
/// A <see cref="Task"/> that completes when DreamDaemon starts pumping the windows message queue after loading a .dmb or when it crashes
/// </summary>
Task<LaunchResult> LaunchResult { get; }
/// <summary>
/// If the <see cref="IDmbProvider.PrimaryDirectory"/> of <see cref="Dmb"/> is being used
/// </summary>
bool IsPrimary { get; }
/// <summary>
/// If the DMAPI was validated. This field may only be access once <see cref="ISessionBase.Lifetime"/> completes
/// If the DMAPI was validated. This field may only be access once <see cref="IProcessBase.Lifetime"/> completes
/// </summary>
bool ApiValidated { get; }
@@ -44,7 +50,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
Task OnReboot { get; }
/// <summary>
/// Releases the <see cref="ISession"/> without terminating it. Also calls <see cref="System.IDisposable.Dispose"/>
/// Releases the <see cref="IProcess"/> without terminating it. Also calls <see cref="System.IDisposable.Dispose"/>
/// </summary>
/// <returns><see cref="ReattachInformation"/> which can be used to create a new <see cref="ISessionController"/> similar to this one</returns>
ReattachInformation Release();
@@ -1,75 +0,0 @@
using System;
using System.Threading.Tasks;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components.Watchdog
{
/// <inheritdoc />
sealed class Session : ISession
{
/// <inheritdoc />
public int Id => process.Id;
/// <inheritdoc />
public Task Startup => process.Startup;
/// <inheritdoc />
public Task<LaunchResult> LaunchResult { get; }
/// <inheritdoc />
public Task<int> Lifetime => process.Lifetime;
/// <summary>
/// The actual <see cref="IProcess"/>
/// </summary>
readonly IProcess process;
/// <summary>
/// The <see cref="IByondExecutableLock"/> for the <see cref="process"/>
/// </summary>
readonly IByondExecutableLock byondLock;
/// <summary>
/// Construct a <see cref="Session"/>
/// </summary>
/// <param name="process">The value of <see cref="process"/></param>
/// <param name="byondLock">The value of <see cref="byondLock"/></param>
public Session(IProcess process, IByondExecutableLock byondLock)
{
this.process = process ?? throw new ArgumentNullException(nameof(process));
this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
async Task<LaunchResult> GetLaunchResult()
{
var startTime = DateTimeOffset.Now;
await process.Startup.ConfigureAwait(false);
var result = new LaunchResult
{
ExitCode = process.Lifetime.IsCompleted ? (int?)await process.Lifetime.ConfigureAwait(false) : null,
StartupTime = DateTimeOffset.Now - startTime
};
return result;
};
LaunchResult = GetLaunchResult();
}
/// <inheritdoc />
public void Dispose()
{
process.Dispose();
byondLock.Dispose();
}
/// <inheritdoc />
public void Terminate() => process.Terminate();
/// <inheritdoc />
public string GetErrorOutput() => process.GetErrorOutput();
/// <inheritdoc />
public string GetStandardOutput() => process.GetStandardOutput();
/// <inheritdoc />
public string GetCombinedOutput() => process.GetCombinedOutput();
}
}
@@ -8,7 +8,9 @@ using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components.Watchdog
{
@@ -72,10 +74,10 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
/// <inheritdoc />
public Task<LaunchResult> LaunchResult => session.LaunchResult;
public Task<LaunchResult> LaunchResult { get; }
/// <inheritdoc />
public Task<int> Lifetime => session.Lifetime;
public Task<int> Lifetime => process.Lifetime;
/// <inheritdoc />
public Task OnReboot => rebootTcs.Task;
@@ -96,9 +98,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
readonly IInteropContext interopContext;
/// <summary>
/// The <see cref="ISession"/> for the <see cref="SessionController"/>
/// The <see cref="IProcess"/> for the <see cref="SessionController"/>
/// </summary>
readonly ISession session;
readonly IProcess process;
/// <summary>
/// The <see cref="IByondExecutableLock"/> for the <see cref="SessionController"/>
/// </summary>
readonly IByondExecutableLock byondLock;
/// <summary>
/// The <see cref="IJsonTrackingContext"/> for the <see cref="SessionController"/>
@@ -144,7 +151,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
bool apiValidated;
/// <summary>
/// If <see cref="session"/> should be kept alive instead
/// If <see cref="process"/> should be kept alive instead
/// </summary>
bool released;
@@ -152,18 +159,20 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// Construct a <see cref="SessionController"/>
/// </summary>
/// <param name="reattachInformation">The value of <see cref="reattachInformation"/></param>
/// <param name="session">The value of <see cref="session"/></param>
/// <param name="process">The value of <see cref="process"/></param>
/// <param name="byondLock">The value of <see cref="byondLock"/></param>
/// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param>
/// <param name="interopContext">The value of <see cref="interopContext"/></param>
/// <param name="chat">The value of <see cref="chat"/></param>
/// <param name="chatJsonTrackingContext">The value of <see cref="chatJsonTrackingContext"/></param>
/// <param name="logger">The value of <see cref="logger"/></param>
public SessionController(ReattachInformation reattachInformation, ISession session, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, IInteropContext interopContext, IChat chat, ILogger<SessionController> logger)
public SessionController(ReattachInformation reattachInformation, IProcess process, IByondExecutableLock byondLock, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, IInteropContext interopContext, IChat chat, ILogger<SessionController> logger)
{
this.chatJsonTrackingContext = chatJsonTrackingContext; //null valid
this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
this.session = session ?? throw new ArgumentNullException(nameof(session));
this.process = process ?? throw new ArgumentNullException(nameof(process));
this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
this.interopContext = interopContext ?? throw new ArgumentNullException(nameof(interopContext));
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -176,6 +185,19 @@ namespace Tgstation.Server.Host.Components.Watchdog
released = false;
rebootTcs = new TaskCompletionSource<object>();
async Task<LaunchResult> GetLaunchResult()
{
var startTime = DateTimeOffset.Now;
await process.Startup.ConfigureAwait(false);
var result = new LaunchResult
{
ExitCode = process.Lifetime.IsCompleted ? (int?)await process.Lifetime.ConfigureAwait(false) : null,
StartupTime = DateTimeOffset.Now - startTime
};
return result;
};
LaunchResult = GetLaunchResult();
}
/// <summary>
@@ -201,8 +223,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (disposing)
{
if (!released)
session.Terminate();
session.Dispose();
{
process.Terminate();
byondLock.Dispose();
}
process.Dispose();
interopContext.Dispose();
Dmb?.Dispose(); //will be null when released
chatJsonTrackingContext.Dispose();
@@ -213,8 +238,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (logger != null)
logger.LogError("Being disposed via finalizer!");
if (!released)
if (session != null)
session.Terminate();
if (process != null)
process.Terminate();
else if (logger != null)
logger.LogCritical("Unable to terminate active DreamDaemon session due to finalizer ordering!");
}
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Host.Components.Byond;
using Tgstation.Server.Host.Components.Chat;
@@ -21,9 +22,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
sealed class SessionControllerFactory : ISessionControllerFactory
{
/// <summary>
/// The <see cref="IExecutor"/> for the <see cref="SessionControllerFactory"/>
/// The <see cref="IProcessExecutor"/> for the <see cref="SessionControllerFactory"/>
/// </summary>
readonly IExecutor executor;
readonly IProcessExecutor processExecutor;
/// <summary>
/// The <see cref="IByondManager"/> for the <see cref="SessionControllerFactory"/>
@@ -65,10 +66,30 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// </summary>
readonly Api.Models.Instance instance;
/// <summary>
/// Change a given <paramref name="securityLevel"/> into the appropriate DreamDaemon command line word
/// </summary>
/// <param name="securityLevel">The <see cref="DreamDaemonSecurity"/> level to change</param>
/// <returns>A <see cref="string"/> representation of the command line parameter</returns>
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));
}
}
/// <summary>
/// Construct a <see cref="SessionControllerFactory"/>
/// </summary>
/// <param name="executor">The value of <see cref="executor"/></param>
/// <param name="processExecutor">The value of <see cref="processExecutor"/></param>
/// <param name="byond">The value of <see cref="byond"/></param>
/// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param>
/// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param>
@@ -77,9 +98,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="ioManager">The value of <see cref="ioManager"/></param>
/// <param name="chat">The value of <see cref="chat"/></param>
/// <param name="loggerFactory">The value of <see cref="loggerFactory"/></param>
public SessionControllerFactory(IExecutor executor, IByondManager byond, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, ILoggerFactory loggerFactory, Api.Models.Instance instance)
public SessionControllerFactory(IProcessExecutor processExecutor, IByondManager byond, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, ILoggerFactory loggerFactory, Api.Models.Instance instance)
{
this.executor = executor ?? throw new ArgumentNullException(nameof(executor));
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
this.byond = byond ?? throw new ArgumentNullException(nameof(byond));
this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite));
@@ -150,7 +171,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
var context = new InteropContext(ioManager, loggerFactory.CreateLogger<InteropContext>(), basePath, interopInfo.ServerCommandsJson);
try
{
var session = executor.RunDreamDaemon(launchParameters, byondLock, dmbProvider, parameters, !primaryPort, !primaryDirectory);
var arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} {2}-close -{3} -verbose -public -params \"{4}\"",
dmbProvider.DmbName,
primaryPort ? launchParameters.PrimaryPort : launchParameters.SecondaryPort,
launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty,
SecurityWord(launchParameters.SecurityLevel.Value),
parameters);
var process = processExecutor.LaunchProcess(byondLock.DreamDaemonPath, basePath, arguments);
try
{
return new SessionController(new ReattachInformation
@@ -159,15 +187,15 @@ namespace Tgstation.Server.Host.Components.Watchdog
Dmb = dmbProvider,
IsPrimary = primaryDirectory,
Port = portToUse.Value,
ProcessId = session.Id,
ProcessId = process.Id,
ChatChannelsJson = interopInfo.ChatChannelsJson,
ChatCommandsJson = interopInfo.ChatCommandsJson,
ServerCommandsJson = interopInfo.ServerCommandsJson,
}, session, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger<SessionController>());
}, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger<SessionController>());
}
catch
{
session.Dispose();
process.Dispose();
throw;
}
}
@@ -207,14 +235,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
var context = new InteropContext(ioManager, loggerFactory.CreateLogger<InteropContext>(), basePath, reattachInformation.ServerCommandsJson);
try
{
var session = executor.AttachToDreamDaemon(reattachInformation.ProcessId, byondLock);
var process = processExecutor.GetProcess(reattachInformation.ProcessId);
try
{
return new SessionController(reattachInformation, session, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger<SessionController>());
return new SessionController(reattachInformation, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger<SessionController>());
}
catch
{
session.Dispose();
process.Dispose();
throw;
}
}
@@ -199,7 +199,6 @@ namespace Tgstation.Server.Host.Core
}
services.AddSingleton<IProcessExecutor, ProcessExecutor>();
services.AddSingleton<IExecutor, Executor>();
services.AddSingleton<IProviderFactory, ProviderFactory>();
services.AddSingleton<IByondTopicSender>(new ByondTopicSender
{