2using System.Collections.Generic;
3using System.Globalization;
4using System.Net.Sockets;
7using System.Threading.Tasks;
9using Microsoft.Extensions.Logging;
117 readonly ILogger<SessionControllerFactory>
logger;
138 logger.LogTrace(
"Bind test: {port}", port);
142 const int MaxAttempts = 5;
143 for (var i = 0; i < MaxAttempts; ++i)
148 logger.LogDebug(
"Clearing the socket took {iterations} attempts :/", i + 1);
152 catch (SocketException ex) when (
platformIdentifier.
IsWindows && ex.SocketErrorCode == SocketError.AddressAlreadyInUse && i < (MaxAttempts - 1))
157 catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
200 ILogger<SessionControllerFactory>
logger,
211 this.chat =
chat ??
throw new ArgumentNullException(nameof(
chat));
219 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
221 this.instance =
instance ??
throw new ArgumentNullException(nameof(
instance));
225 #pragma warning disable CA1506
231 CancellationToken cancellationToken)
233 logger.LogTrace(
"Begin session launch...");
234 if (!launchParameters.
Port.HasValue)
235 throw new InvalidOperationException(
"Given port is null!");
244 logger.LogTrace(
"Boosting security level to minimum of Safe");
251 logger.LogTrace(
"Boosting security level to minimum of Trusted");
256 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Invalid DreamDaemonSecurity value: {0}", dmbProvider.
CompileJob.
MinimumSecurityLevel));
267 "Launching session with CompileJob {compileJobId}...",
275 await
PortBindTest(launchParameters.
Port.Value, engineType, cancellationToken);
277 string? outputFilePath =
null;
278 var preserveLogFile =
true;
280 var hasStandardOutput = engineLock.HasStandardOutput;
283 var now = DateTimeOffset.UtcNow;
289 $
"server-utc-{now.ToString("yyyy-MM-dd-HH-mm-ss
", CultureInfo.InvariantCulture)}{(apiValidate ? "-dmapi
" : String.Empty)}.log"));
291 logger.LogInformation(
"Logging server output to {path}...", outputFilePath);
293 else if (!hasStandardOutput)
296 preserveLogFile =
false;
302 logger.LogDebug(
"Session will have no DMAPI support!");
332 launchParameters.
Port.Value);
335 TimeSpan.FromMilliseconds(
355 CancellationToken.None),
360 return sessionController;
364 chatTrackingContext.Dispose();
370 await
using (process)
373 await process.Lifetime;
380 if (currentByondLock ==
null)
381 engineLock.Dispose();
385#pragma warning restore CA1506
388 public async ValueTask<ISessionController?>
Reattach(
390 CancellationToken cancellationToken)
392 ArgumentNullException.ThrowIfNull(reattachInformation);
394 logger.LogTrace(
"Begin session reattach...");
404 "Attaching to session PID: {pid}, CompileJob: {compileJobId}...",
414 if (engineLock.PromptsForNetworkAccess)
421 reattachInformation.
Dmb,
440 () => ValueTask.CompletedTask,
447 chatTrackingContext =
null;
453 chatTrackingContext?.Dispose();
460 await process.DisposeAsync();
467 engineLock?.Dispose();
487 string accessIdentifier,
490 CancellationToken cancellationToken)
495 new Dictionary<string, string>
502 !engineLock.HasStandardOutput || engineLock.PreferFileLogging
522 process.AdjustPriority(
false);
533 process.Id.ToString(CultureInfo.InvariantCulture),
542 await
using (process)
545 await process.Lifetime;
560 async ValueTask
LogDDOutput(
IProcess process,
string? outputFilePath,
bool cliSupported,
bool preserveFile, CancellationToken cancellationToken)
564 string? ddOutput =
null;
568 if (ddOutput ==
null)
575 ddOutput = Encoding.UTF8.GetString(dreamDaemonLogBytes);
582 logger.LogTrace(
"Deleting temporary log file {path}...", outputFilePath);
589 logger.LogWarning(ex,
"Failed to delete server log file {outputFilePath}!", outputFilePath);
594 "Server Output:{newLine}{output}",
600 logger.LogWarning(ex,
"Error reading server output!");
618 bool apiValidateOnly)
639 if (otherProcess ==
null)
647 if (otherUsername.Equals(ourUsername, StringComparison.Ordinal))
EngineType? Engine
The EngineType.
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. No-op for EngineType.OpenDream.
bool? LogOutput
If process output/error text should be logged.
uint? TopicRequestTimeout
The timeout for sending and receiving BYOND topics in milliseconds.
uint? StartupTimeout
The DreamDaemon startup timeout in seconds.
DreamDaemonSecurity? SecurityLevel
The DreamDaemonSecurity level of DreamDaemon. No-op for EngineType.OpenDream.
Constants used for communication with the DMAPI.
const string ParamServerPort
Identifies the Core.IServerPortProvider.HttpApiPort of the server.
const string ParamAccessIdentifier
Identifies the DMApiParameters.AccessIdentifier for the session.
const string ParamApiVersion
Identifies a DMAPI execution with the version as the value.
static readonly Version InteropVersion
The DMAPI InteropVersion being used.
readonly IEventConsumer eventConsumer
The IEventConsumer for the SessionControllerFactory.
readonly ITopicClientFactory topicClientFactory
The ITopicClientFactory for the SessionControllerFactory.
readonly SessionConfiguration sessionConfiguration
The SessionConfiguration for the SessionControllerFactory.
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.
async ValueTask CheckPagerIsNotRunning()
Make sure the BYOND pager is not running.
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the SessionControllerFactory.
async ValueTask LogDDOutput(IProcess process, string? outputFilePath, bool cliSupported, bool preserveFile, CancellationToken cancellationToken)
Attempts to log DreamDaemon output.
RuntimeInformation CreateRuntimeInformation(IDmbProvider dmbProvider, IChatTrackingContext chatTrackingContext, DreamDaemonSecurity securityLevel, DreamDaemonVisibility visibility, bool apiValidateOnly)
Create RuntimeInformation.
readonly ICryptographySuite cryptographySuite
The ICryptographySuite for the SessionControllerFactory.
async ValueTask< IProcess > CreateGameServerProcess(IDmbProvider dmbProvider, IEngineExecutableLock engineLock, DreamDaemonLaunchParameters launchParameters, string accessIdentifier, string? logFilePath, bool apiValidate, CancellationToken cancellationToken)
Creates the game server IProcess.
readonly IBridgeRegistrar bridgeRegistrar
The IBridgeRegistrar for the SessionControllerFactory.
async ValueTask PortBindTest(ushort port, EngineType engineType, CancellationToken cancellationToken)
Check if a given port can be bound to.
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.
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 ValueTask< ISessionController > LaunchNew(IDmbProvider dmbProvider, IEngineExecutableLock? currentByondLock, DreamDaemonLaunchParameters launchParameters, bool apiValidate, CancellationToken cancellationToken)
Create a ISessionController from a freshly launch DreamDaemon instance. A ValueTask<TResult> resultin...
SessionControllerFactory(IProcessExecutor processExecutor, IEngineManager engineManager, 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.
readonly IEngineManager engineManager
The IEngineManager for the SessionControllerFactory.
async ValueTask< ISessionController?> Reattach(ReattachInformation reattachInformation, CancellationToken cancellationToken)
Create a ISessionController from an existing DreamDaemon instance. A ValueTask<TResult> resulting in ...
readonly IAsyncDelayer asyncDelayer
The IAsyncDelayer 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(IPlatformIdentifier platformIdentifier, ushort port, bool includeIPv6, bool udp)
Attempt to exclusively bind to a given port .
Operation exceptions thrown from the context of a Models.Job.
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.
EngineVersion EngineVersion
The Api.Models.EngineVersion used to build the .dmb.
string Directory
The primary game directory with a trailing directory separator.
string DmbName
The file name of the .dmb.
Models.CompileJob CompileJob
The CompileJob of the .dmb.
Represents usage of the two primary BYOND server executables.
string ServerExePath
The full path to the game server executable.
string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary< string, string > parameters, DreamDaemonLaunchParameters launchParameters, string? logFilePath)
Return the command line arguments for launching with given launchParameters .
bool HasStandardOutput
If ServerExePath supports being run as a command-line application and outputs log information to be c...
For managing the engine installations.
ValueTask< IEngineExecutableLock > UseExecutables(EngineVersion? requiredVersion, string? trustDmbFullPath, CancellationToken cancellationToken)
Lock the current installation's location and return a IEngineExecutableLock.
Consumes EventTypes and takes the appropriate actions.
ValueTask 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.
ValueTask< byte[]> ReadAllBytes(string path, CancellationToken cancellationToken)
Returns all the contents of a file at path as a byte array.
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 .
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.
void AdjustPriority(bool higher)
Set's the owned global::System.Diagnostics.Process.PriorityClass to a non-normal value.
IProcess GetCurrentProcess()
Get a IProcess representing the running executable.
IProcess? GetProcess(int id)
Get a IProcess by id .
IProcess LaunchProcess(string fileName, string workingDirectory, string arguments, string? fileRedirect=null, bool readStandardHandles=false, bool noShellExecute=false)
Launch a IProcess.
IProcess? GetProcessByName(string name)
Get a IProcess with a given name .
Abstraction over a global::System.Diagnostics.Process.
string GetExecutingUsername()
Get the name of the account executing the IProcess.
Task< string?> GetCombinedOutput(CancellationToken cancellationToken)
Get the stderr and stdout output of the IProcess.
For waiting asynchronously.
Task Delay(TimeSpan timeSpan, CancellationToken cancellationToken)
Create a Task that completes after a given timeSpan .
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
DreamDaemonVisibility
The visibility setting for DreamDaemon.
DreamDaemonSecurity
DreamDaemon's security level.
EngineType
The type of engine the codebase is using.
EventType
Types of events. Mirror in tgs.dm. Prefer last listed name for script.