2using System.Collections.Generic;
3using System.Globalization;
4using System.Net.Sockets;
7using System.Threading.Tasks;
9using Byond.TopicSender;
11using Microsoft.Extensions.Logging;
119 readonly ILogger<SessionControllerFactory>
logger;
138 return securityLevel
switch
140 DreamDaemonSecurity.Safe =>
"safe",
141 DreamDaemonSecurity.Trusted =>
"trusted",
142 DreamDaemonSecurity.Ultrasafe =>
"ultrasafe",
143 _ =>
throw new ArgumentOutOfRangeException(nameof(securityLevel), securityLevel, String.Format(CultureInfo.InvariantCulture,
"Bad DreamDaemon security level: {0}", securityLevel)),
154 return visibility
switch
156 DreamDaemonVisibility.Public =>
"public",
157 DreamDaemonVisibility.Private =>
"private",
158 DreamDaemonVisibility.Invisible =>
"invisible",
159 _ =>
throw new ArgumentOutOfRangeException(nameof(visibility), visibility, String.Format(CultureInfo.InvariantCulture,
"Bad DreamDaemon visibility level: {0}", visibility)),
171 logger.LogTrace(
"Bind test: {port}", port);
174 catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
217 ILogger<SessionControllerFactory>
logger,
222 this.byond =
byond ??
throw new ArgumentNullException(nameof(
byond));
228 this.chat =
chat ??
throw new ArgumentNullException(nameof(
chat));
236 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
238 this.instance =
instance ??
throw new ArgumentNullException(nameof(
instance));
247 CancellationToken cancellationToken)
249 logger.LogTrace(
"Begin session launch...");
250 if (!launchParameters.
Port.HasValue)
251 throw new InvalidOperationException(
"Given port is null!");
259 logger.LogTrace(
"Boosting security level to minimum of Safe");
266 logger.LogTrace(
"Boosting security level to minimum of Trusted");
271 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Invalid DreamDaemonSecurity value: {0}", dmbProvider.
CompileJob.
MinimumSecurityLevel));
276 Version.Parse(dmbProvider.
CompileJob.ByondVersion),
282 "Launching session with CompileJob {compileJobId}...",
288 string outputFilePath =
null;
289 var preserveLogFile =
true;
292 var now = DateTimeOffset.UtcNow;
298 $
"dd-utc-{now.ToString("yyyy-MM-dd-HH-mm-ss
", CultureInfo.InvariantCulture)}{(apiValidate ? "-dmapi
" : String.Empty)}.log"));
300 logger.LogInformation(
"Logging DreamDaemon output to {path}...", outputFilePath);
302 else if (!byondLock.SupportsCli)
305 preserveLogFile =
false;
311 TimeSpan.FromMilliseconds(
315 logger.LogDebug(
"Session will have no DMAPI support!");
345 launchParameters.
Port.Value);
362 byondLock.SupportsCli,
364 CancellationToken.None),
369 return sessionController;
373 chatTrackingContext.Dispose();
379 await
using (process)
382 await process.Lifetime;
389 if (currentByondLock ==
null)
398 CancellationToken cancellationToken)
400 ArgumentNullException.ThrowIfNull(reattachInformation);
402 logger.LogTrace(
"Begin session reattach...");
405 Version.Parse(reattachInformation.
Dmb.
CompileJob.ByondVersion),
412 "Attaching to session PID: {pid}, CompileJob: {compileJobId}...",
422 if (!byondLock.SupportsCli)
429 reattachInformation.
Dmb,
447 () => Task.CompletedTask,
454 chatTrackingContext =
null;
460 chatTrackingContext.Dispose();
466 await process.DisposeAsync();
491 ITopicClient byondTopicSender,
494 string accessIdentifier,
497 CancellationToken cancellationToken)
501 var parameters = $
"{DMApiConstants.ParamApiVersion}={byondTopicSender.SanitizeString(DMApiConstants.InteropVersion.Semver().ToString())}&{byondTopicSender.SanitizeString(DMApiConstants.ParamServerPort)}={serverPortProvider.HttpApiPort}&{byondTopicSender.SanitizeString(DMApiConstants.ParamAccessIdentifier)}={byondTopicSender.SanitizeString(accessIdentifier)}";
504 parameters = $
"{parameters}&{launchParameters.AdditionalParameters}";
507 var arguments = String.Format(
508 CultureInfo.InvariantCulture,
509 "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6} -params \"{7}\"",
511 launchParameters.
Port.Value,
512 launchParameters.
AllowWebClient.Value ?
"-webclient " : String.Empty,
516 ? $
" -logself -log {logFilePath}"
536 process.AdjustPriority(
true);
539 process.AdjustPriority(
false);
550 process.Id.ToString(CultureInfo.InvariantCulture),
559 await
using (process)
562 await process.Lifetime;
577 async Task
LogDDOutput(
IProcess process,
string outputFilePath,
bool cliSupported,
bool preserveFile, CancellationToken cancellationToken)
581 string ddOutput =
null;
585 if (ddOutput ==
null)
592 ddOutput = Encoding.UTF8.GetString(dreamDaemonLogBytes);
599 logger.LogTrace(
"Deleting temporary log file {path}...", outputFilePath);
604 logger.LogWarning(ex,
"Failed to delete DreamDaemon log file {outputFilePath}!", outputFilePath);
609 "DreamDaemon Output:{newLine}{output}",
615 logger.LogWarning(ex,
"Error reading DreamDaemon output!");
631 bool apiValidateOnly)
637 launchParameters?.SecurityLevel,
638 launchParameters?.Visibility,
653 if (otherProcess ==
null)
659 var otherUserName = await otherUsernameTask;
661 if (otherUserName.Equals(ourUserName, StringComparison.Ordinal))
virtual ? long Id
The ID of the entity.
Metadata about a server instance.
virtual ? Version DMApiVersion
The DMAPI Version.
DreamDaemonSecurity? MinimumSecurityLevel
The minimum DreamDaemonSecurity required to run the CompileJob's output.
Launch settings for DreamDaemon.
ushort? Port
The port DreamDaemon uses. This should be publically accessible.
DreamDaemonVisibility? Visibility
The DreamDaemonVisibility level of DreamDaemon.
bool? LogOutput
If process output/error text should be logged.
uint? TopicRequestTimeout
The timeout for sending and receiving BYOND topics in milliseconds.
bool? AllowWebClient
If the BYOND web client can be used to connect to the game server.
uint? StartupTimeout
The DreamDaemon startup timeout in seconds.
bool? StartProfiler
If -profile is passed in on the DreamDaemon command line.
DreamDaemonSecurity? SecurityLevel
The DreamDaemonSecurity level of DreamDaemon.
string? AdditionalParameters
Parameters string for DreamDaemon.
readonly IEventConsumer eventConsumer
The IEventConsumer for the SessionControllerFactory.
readonly ITopicClientFactory topicClientFactory
The ITopicClientFactory for the SessionControllerFactory.
readonly SessionConfiguration sessionConfiguration
The SessionConfiguration for the SessionControllerFactory.
async Task< ISessionController > LaunchNew(IDmbProvider dmbProvider, IByondExecutableLock currentByondLock, DreamDaemonLaunchParameters launchParameters, bool apiValidate, CancellationToken cancellationToken)
Create a ISessionController from a freshly launch DreamDaemon instance. A Task<TResult> resulting in ...
readonly IServerPortProvider serverPortProvider
The IServerPortProvider for the SessionControllerFactory.
readonly ILoggerFactory loggerFactory
The ILoggerFactory for the SessionControllerFactory.
readonly IProcessExecutor processExecutor
The IProcessExecutor for the SessionControllerFactory.
readonly IIOManager gameIOManager
The IIOManager for the Game directory.
RuntimeInformation CreateRuntimeInformation(IDmbProvider dmbProvider, IChatTrackingContext chatTrackingContext, DreamDaemonLaunchParameters launchParameters, bool apiValidateOnly)
Create RuntimeInformation.
SessionControllerFactory(IProcessExecutor processExecutor, IByondManager byond, ITopicClientFactory topicClientFactory, ICryptographySuite cryptographySuite, IAssemblyInformationProvider assemblyInformationProvider, IIOManager gameIOManager, IIOManager diagnosticsIOManager, IChatManager chat, INetworkPromptReaper networkPromptReaper, IPlatformIdentifier platformIdentifier, IBridgeRegistrar bridgeRegistrar, IServerPortProvider serverPortProvider, IEventConsumer eventConsumer, IAsyncDelayer asyncDelayer, ILoggerFactory loggerFactory, ILogger< SessionControllerFactory > logger, SessionConfiguration sessionConfiguration, Api.Models.Instance instance)
Initializes a new instance of the SessionControllerFactory class.
static string SecurityWord(DreamDaemonSecurity securityLevel)
Change a given securityLevel into the appropriate DreamDaemon command line word.
async Task CheckPagerIsNotRunning(CancellationToken cancellationToken)
Make sure the BYOND pager is not running.
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the SessionControllerFactory.
async Task LogDDOutput(IProcess process, string outputFilePath, bool cliSupported, bool preserveFile, CancellationToken cancellationToken)
Attempts to log DreamDaemon output.
readonly ICryptographySuite cryptographySuite
The ICryptographySuite for the SessionControllerFactory.
readonly IBridgeRegistrar bridgeRegistrar
The IBridgeRegistrar for the SessionControllerFactory.
async Task< IProcess > CreateDreamDaemonProcess(IDmbProvider dmbProvider, ITopicClient byondTopicSender, IByondExecutableLock byondLock, DreamDaemonLaunchParameters launchParameters, string accessIdentifier, string logFilePath, bool apiValidate, CancellationToken cancellationToken)
Creates the DreamDaemon IProcess.
const string DreamDaemonLogsPath
Path in Diagnostics folder to DreamDaemon logs.
readonly Api.Models.Instance instance
The Api.Models.Instance for the SessionControllerFactory.
readonly INetworkPromptReaper networkPromptReaper
The INetworkPromptReaper for the SessionControllerFactory.
static string VisibilityWord(DreamDaemonVisibility visibility)
Change a given visibility into the appropriate DreamDaemon command line word.
readonly ILogger< SessionControllerFactory > logger
The ILogger for the SessionControllerFactory.
readonly IChatManager chat
The IChatManager for the SessionControllerFactory.
readonly IAssemblyInformationProvider assemblyInformationProvider
The IAssemblyInformationProvider for the SessionControllerFactory.
async Task< ISessionController > Reattach(ReattachInformation reattachInformation, CancellationToken cancellationToken)
Create a ISessionController from an existing DreamDaemon instance. A Task<TResult> resulting in a new...
void PortBindTest(ushort port)
Check if a given port can be bound to.
readonly IAsyncDelayer asyncDelayer
The IAsyncDelayer for the SessionControllerFactory.
readonly IByondManager byond
The IByondManager for the SessionControllerFactory.
readonly IIOManager diagnosticsIOManager
The IIOManager for the Diagnostics directory.
Configuration options for the game sessions.
bool HighPriorityLiveDreamDaemon
If the public DreamDaemon instances are set to be above normal priority processes.
bool LowPriorityDeploymentProcesses
If the deployment DreamMaker and DreamDaemon instances are set to be below normal priority processes.
Extension methods for the Socket class.
static void BindTest(ushort port, bool includeIPv6)
Attempt to exclusively bind to a given port .
Operation exceptions thrown from the context of a Models.Job.
Represents usage of the two primary BYOND server executables.
bool SupportsCli
If DreamDaemonPath supports being run as a command-line application.
string DreamDaemonPath
The full path to the DreamDaemon executable.
For managing the BYOND installation.
Task< IByondExecutableLock > UseExecutables(Version requiredVersion, string trustDmbFullPath, CancellationToken cancellationToken)
Lock the current installation's location and return a IByondExecutableLock.
For managing connected chat services.
IChatTrackingContext CreateTrackingContext()
Start tracking Commands.CustomCommands and ChannelRepresentations.
Represents a tracking of dynamic chat json files.
Provides absolute paths to the latest compiled .dmbs.
string Directory
The primary game directory with a trailing directory separator.
string DmbName
The file name of the .dmb.
CompileJob CompileJob
The CompileJob of the .dmb.
Consumes EventTypes and takes the appropriate actions.
Task HandleEvent(EventType eventType, IEnumerable< string > parameters, bool deploymentPipeline, CancellationToken cancellationToken)
Handle a given eventType .
Registers IBridgeHandlers.
Factory for ISessionControllers.
Factory for ITopicClients.
ITopicClient CreateTopicClient(TimeSpan timeout)
Create a ITopicClient.
Provides access to the server's HttpApiPort.
ushort HttpApiPort
The port the server listens on.
Interface for using filesystems.
string ResolvePath()
Retrieve the full path of the current working directory.
string ConcatPath(params string[] paths)
Combines an array of strings into a path.
Task CreateDirectory(string path, CancellationToken cancellationToken)
Create a directory at path .
Task DeleteFile(string path, CancellationToken cancellationToken)
Deletes a file at path .
Task< byte[]> ReadAllBytes(string path, CancellationToken cancellationToken)
Returns all the contents of a file at path as a byte array.
Contains various cryptographic functions.
string GetSecureString()
Generates a 40-length secure ascii string.
On Windows, DreamDaemon will show an unskippable prompt when using /world/proc/OpenPort()....
void RegisterProcess(IProcess process)
Register a given process for network prompt reaping.
Task< IProcess > LaunchProcess(string fileName, string workingDirectory, string arguments=null, string fileRedirect=null, bool readStandardHandles=false, bool noShellExecute=false)
Launch a IProcess.
IProcess GetProcessByName(string name)
Get a IProcess with a given name .
IProcess GetProcess(int id)
Get a IProcess by id .
IProcess GetCurrentProcess()
Get a IProcess representing the running executable.
Abstraction over a global::System.Diagnostics.Process.
Task< string > GetCombinedOutput(CancellationToken cancellationToken)
Get the stderr and stdout output of the IProcess.
Task< string > GetExecutingUsername(CancellationToken cancellationToken)
Get the name of the account executing the IProcess.
For waiting asynchronously.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
DreamDaemonVisibility
The visibility setting for DreamDaemon.
DreamDaemonSecurity
DreamDaemon's security level.
EventType
Types of events. Mirror in tgs.dm.