2using System.Collections.Generic;
3using System.Diagnostics;
5using System.Net.Http.Headers;
9using System.Threading.Tasks;
11using Microsoft.Extensions.Logging;
78 string compilerExePath,
79 Task installationTask,
81 : base(installationIOManager)
85 ServerExePath = serverExePath ??
throw new ArgumentNullException(nameof(serverExePath));
86 CompilerExePath = compilerExePath ??
throw new ArgumentNullException(nameof(compilerExePath));
87 InstallationTask = installationTask ??
throw new ArgumentNullException(nameof(installationTask));
88 Version = version ??
throw new ArgumentNullException(nameof(version));
91 throw new ArgumentException($
"Invalid EngineType: {version.Engine.Value}", nameof(version));
97 IReadOnlyDictionary<string, string> parameters,
101 ArgumentNullException.ThrowIfNull(dmbProvider);
102 ArgumentNullException.ThrowIfNull(parameters);
103 ArgumentNullException.ThrowIfNull(launchParameters);
106 throw new ArgumentException($
"parameters must have \"{DMApiConstants.ParamAccessIdentifier}\" set!", nameof(parameters));
110 var
arguments = $
"--cvar {(logFilePath != null ? $"log.path=\
"{InstallationIOManager.GetDirectoryName(logFilePath)}\" --cvar log.format=\"{InstallationIOManager.GetFileName(logFilePath)}\"" :
"log.enabled=false")} --cvar watchdog.token={accessIdentifier} --cvar log.runtimelog=
false --cvar net.port={launchParameters.Port!.Value} --cvar opendream.topic_port={launchParameters.OpenDreamTopicPort!.Value} --cvar opendream.world_params=\
"{parametersString}\" --cvar opendream.json_path=\"./{dmbProvider.DmbName}\"";
117 if (String.IsNullOrWhiteSpace(additionalArguments))
118 additionalArguments = String.Empty;
120 additionalArguments = $
"{additionalArguments.Trim()} ";
122 return $
"--suppress-unimplemented --notices-enabled {additionalArguments}\"{dmePath ?? throw new ArgumentNullException(nameof(dmePath))}\"";
129 string accessIdentifier,
131 CancellationToken cancellationToken)
133 ArgumentNullException.ThrowIfNull(logger);
135 const int MaximumTerminationSeconds = 5;
137 logger.LogTrace(
"Attempting Robust.Server graceful exit (Timeout: {seconds}s)...", MaximumTerminationSeconds);
138 var timeout = asyncDelayer.Delay(TimeSpan.FromSeconds(MaximumTerminationSeconds), cancellationToken).AsTask();
140 if (lifetime.IsCompleted)
141 logger.LogTrace(
"Robust.Server already exited");
143 var stopwatch = Stopwatch.StartNew();
146 using var httpClient = httpClientFactory.CreateClient();
147 using var request =
new HttpRequestMessage();
148 request.Headers.Add(
"WatchdogToken", accessIdentifier);
149 request.RequestUri =
new Uri($
"http://localhost:{port}/shutdown");
150 request.Content =
new StringContent(
151 "{\"Reason\":\"TGS session termination\"}",
153 new MediaTypeHeaderValue(MediaTypeNames.Application.Json));
154 request.Method = HttpMethod.Post;
156 var responseTask = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
159 await Task.WhenAny(timeout, lifetime, responseTask);
160 if (responseTask.IsCompleted)
162 using var response = await responseTask;
163 if (response.IsSuccessStatusCode)
165 logger.LogDebug(
"Robust.Server responded to the shutdown command successfully ({requestMs}ms). Waiting for exit...", stopwatch.ElapsedMilliseconds);
166 await Task.WhenAny(timeout, lifetime);
170 if (!lifetime.IsCompleted)
171 logger.LogWarning(
"Robust.Server graceful exit timed out!");
173 catch (
Exception ex) when (ex is not OperationCanceledException)
175 logger.LogDebug(ex,
"Unable to send graceful exit request to Robust.Server watchdog API!");
178 if (lifetime.IsCompleted)
180 logger.LogTrace(
"Robust.Server exited without termination");
186 logger.LogTrace(
"Robust.Server graceful shutdown attempt took {totalMs}ms", stopwatch.ElapsedMilliseconds);
189 await base.StopServerProcess(logger, process, accessIdentifier, port, cancellationToken);
Information about an engine installation.
EngineType? Engine
The EngineType.
Launch settings for DreamDaemon.
static string EncodeParameters(IReadOnlyDictionary< string, string > parameters, DreamDaemonLaunchParameters launchParameters)
Encode given parameters for passing as world.params on the command line.
Implementation of IEngineInstallation for EngineType.OpenDream.
override string CompilerExePath
The full path to the dm/DreamMaker executable.
readonly IAbstractHttpClientFactory httpClientFactory
The IAbstractHttpClientFactory for the OpenDreamInstallation.
OpenDreamInstallation(IIOManager installationIOManager, IAsyncDelayer asyncDelayer, IAbstractHttpClientFactory httpClientFactory, string serverExePath, string compilerExePath, Task installationTask, EngineVersion version)
Initializes a new instance of the OpenDreamInstallation class.
readonly IAsyncDelayer asyncDelayer
The IAsyncDelayer for the OpenDreamInstallation.
override bool PromptsForNetworkAccess
If ServerExePath may create network prompts.
override async ValueTask StopServerProcess(ILogger logger, IProcess process, string accessIdentifier, ushort port, CancellationToken cancellationToken)
Kills a given engine server process .A ValueTask representing the running operation.
override string FormatCompilerArguments(string dmePath, string? additionalArguments)
Return the command line arguments for compiling a given dmePath if compilation is necessary....
override string FormatServerArguments(IDmbProvider dmbProvider, IReadOnlyDictionary< string, string > parameters, DreamDaemonLaunchParameters launchParameters, string? logFilePath)
Return the command line arguments for launching with given launchParameters .The formatted arguments ...
override bool HasStandardOutput
If ServerExePath supports being run as a command-line application and outputs log information to be c...
override EngineVersion Version
The EngineVersion of the IEngineInstallation.
override string ServerExePath
The full path to the game server executable.
override bool PreferFileLogging
If HasStandardOutput is set, this indicates that the engine server has good file logging that should ...
override bool UseDotnetDump
If dotnet-dump should be used to create process dumps for this installation.
override Task InstallationTask
The Task that completes when the BYOND version finished installing.
Constants used for communication with the DMAPI.
const string ParamAccessIdentifier
Identifies the DMApiParameters.AccessIdentifier for the session.
Provides absolute paths to the latest compiled .dmbs.
Interface for using filesystems.
Task< int?> Lifetime
The Task<TResult> resulting in the exit code of the process or null if the process was detached.
Abstraction over a global::System.Diagnostics.Process.
For waiting asynchronously.
EngineType
The type of engine the codebase is using.