mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-26 06:27:19 +01:00
More OpenDream Integration
- Make use of `world.opendream_topic_port` in DMAPI if present. Send in initial bridge request. - Implement compiler and server arguments for `OpenDreamInstallation`. - Deprecate bridge port update requests. - Prevent symlink swapping if not running a BYOND engine.
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@
|
||||
<TgsApiLibraryVersion>12.0.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>13.0.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>6.6.0</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.6.1</TgsInteropVersion>
|
||||
<TgsInteropVersion>5.7.0</TgsInteropVersion>
|
||||
<TgsHostWatchdogVersion>1.4.0</TgsHostWatchdogVersion>
|
||||
<TgsContainerScriptVersion>1.2.1</TgsContainerScriptVersion>
|
||||
<TgsMigratorVersion>2.0.0</TgsMigratorVersion>
|
||||
|
||||
@@ -1 +1 @@
|
||||
"5.6.1"
|
||||
"5.7.0"
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#define DMAPI5_TOPIC_REQUEST_LIMIT 65528
|
||||
#define DMAPI5_TOPIC_RESPONSE_LIMIT 65529
|
||||
|
||||
#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0
|
||||
#define DMAPI5_BRIDGE_COMMAND_STARTUP 1
|
||||
#define DMAPI5_BRIDGE_COMMAND_PRIME 2
|
||||
#define DMAPI5_BRIDGE_COMMAND_REBOOT 3
|
||||
@@ -18,6 +17,7 @@
|
||||
|
||||
#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
|
||||
#define DMAPI5_PARAMETER_CUSTOM_COMMANDS "customCommands"
|
||||
#define DMAPI5_PARAMETER_TOPIC_PORT "topicPort"
|
||||
|
||||
#define DMAPI5_CHUNK "chunk"
|
||||
#define DMAPI5_CHUNK_PAYLOAD "payload"
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
var/datum/tgs_version/api_version = ApiVersion()
|
||||
version = null
|
||||
var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands()))
|
||||
var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort()))
|
||||
if(!istype(bridge_response))
|
||||
TGS_ERROR_LOG("Failed initial bridge request!")
|
||||
return FALSE
|
||||
@@ -100,6 +100,13 @@
|
||||
initialized = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/tgs_api/v5/proc/GetTopicPort()
|
||||
#if defined(OPENDREAM) && defined(OPENDREAM_TOPIC_PORT_EXISTS)
|
||||
return "[world.opendream_topic_port]"
|
||||
#else
|
||||
return null
|
||||
#endif
|
||||
|
||||
/datum/tgs_api/v5/proc/RequireInitialBridgeResponse()
|
||||
TGS_DEBUG_LOG("RequireInitialBridgeResponse()")
|
||||
var/logged = FALSE
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
|
||||
var/list/reattach_response = TopicResponse(error_message)
|
||||
reattach_response[DMAPI5_PARAMETER_CUSTOM_COMMANDS] = ListCustomCommands()
|
||||
reattach_response[DMAPI5_PARAMETER_TOPIC_PORT] = GetTopicPort()
|
||||
return reattach_response
|
||||
|
||||
if(DMAPI5_TOPIC_COMMAND_SEND_CHUNK)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#undef DMAPI5_TOPIC_REQUEST_LIMIT
|
||||
#undef DMAPI5_TOPIC_RESPONSE_LIMIT
|
||||
|
||||
#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE
|
||||
#undef DMAPI5_BRIDGE_COMMAND_STARTUP
|
||||
#undef DMAPI5_BRIDGE_COMMAND_PRIME
|
||||
#undef DMAPI5_BRIDGE_COMMAND_REBOOT
|
||||
@@ -18,6 +17,7 @@
|
||||
|
||||
#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
|
||||
#undef DMAPI5_PARAMETER_CUSTOM_COMMANDS
|
||||
#undef DMAPI5_PARAMETER_TOPIC_PORT
|
||||
|
||||
#undef DMAPI5_CHUNK
|
||||
#undef DMAPI5_CHUNK_PAYLOAD
|
||||
|
||||
@@ -9,21 +9,21 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
public class DreamDaemonLaunchParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// If the BYOND web client can be used to connect to the game server.
|
||||
/// If the BYOND web client can be used to connect to the game server. No-op for <see cref="EngineType.OpenDream"/>.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[ResponseOptions]
|
||||
public bool? AllowWebClient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If -profile is passed in on the DreamDaemon command line.
|
||||
/// If -profile is passed in on the DreamDaemon command line. No-op for <see cref="EngineType.OpenDream"/>.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[ResponseOptions]
|
||||
public bool? StartProfiler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DreamDaemonVisibility"/> level of DreamDaemon.
|
||||
/// The <see cref="DreamDaemonVisibility"/> level of DreamDaemon. No-op for <see cref="EngineType.OpenDream"/>.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[ResponseOptions]
|
||||
@@ -31,7 +31,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
public DreamDaemonVisibility? Visibility { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DreamDaemonSecurity"/> level of DreamDaemon.
|
||||
/// The <see cref="DreamDaemonSecurity"/> level of DreamDaemon. No-op for <see cref="EngineType.OpenDream"/>.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[ResponseOptions]
|
||||
@@ -92,7 +92,7 @@ namespace Tgstation.Server.Api.Models.Internal
|
||||
public bool? LogOutput { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If DreamDaemon supports it, the value added as the -map-threads parameter. 0 uses the default BYOND value.
|
||||
/// If DreamDaemon supports it, the value added as the -map-threads parameter. 0 uses the default BYOND value. No-op for <see cref="EngineType.OpenDream"/>.
|
||||
/// </summary>
|
||||
[Required]
|
||||
[ResponseOptions]
|
||||
|
||||
@@ -6,19 +6,16 @@ using Tgstation.Server.Host.IO;
|
||||
namespace Tgstation.Server.Host.Components.Deployment
|
||||
{
|
||||
/// <inheritdoc />
|
||||
sealed class DmbProvider : IDmbProvider
|
||||
sealed class DmbProvider : DmbProviderBase, IDmbProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string DmbName => String.Concat(CompileJob.DmeName, DreamMaker.DmbExtension);
|
||||
public override string Directory => ioManager.ResolvePath(CompileJob.DirectoryName.ToString() + directoryAppend);
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Directory => ioManager.ResolvePath(CompileJob.DirectoryName.ToString() + directoryAppend);
|
||||
public override Models.CompileJob CompileJob { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Models.CompileJob CompileJob { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ByondVersion ByondVersion { get; }
|
||||
public override ByondVersion ByondVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IIOManager"/> for the <see cref="DmbProvider"/>.
|
||||
@@ -53,9 +50,9 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() => onDispose?.Invoke();
|
||||
public override void Dispose() => onDispose?.Invoke();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void KeepAlive() => onDispose = null;
|
||||
public override void KeepAlive() => onDispose = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Deployment
|
||||
{
|
||||
/// <inheritdoc />
|
||||
abstract class DmbProviderBase : IDmbProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string DmbName => String.Concat(
|
||||
CompileJob.DmeName,
|
||||
ByondVersion.Engine.Value switch
|
||||
{
|
||||
EngineType.Byond => ".dmb",
|
||||
EngineType.OpenDream => ".json",
|
||||
_ => throw new InvalidOperationException($"Invalid EngineType: {ByondVersion.Engine.Value}"),
|
||||
});
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string Directory { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract Models.CompileJob CompileJob { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract ByondVersion ByondVersion { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract void Dispose();
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract void KeepAlive();
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,6 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
/// <inheritdoc />
|
||||
sealed class DreamMaker : IDreamMaker
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension for .dmbs.
|
||||
/// </summary>
|
||||
public const string DmbExtension = ".dmb";
|
||||
|
||||
/// <summary>
|
||||
/// Extension for .dmes.
|
||||
/// </summary>
|
||||
@@ -805,7 +800,6 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
ApiValidationStatus validationStatus;
|
||||
using (var provider = new TemporaryDmbProvider(
|
||||
ioManager.ResolvePath(job.DirectoryName.ToString()),
|
||||
String.Concat(job.DmeName, DmbExtension),
|
||||
job,
|
||||
byondLock.Version))
|
||||
await using (var controller = await sessionControllerFactory.LaunchNew(provider, byondLock, launchParameters, true, cancellationToken))
|
||||
|
||||
@@ -7,41 +7,36 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
/// <summary>
|
||||
/// Temporary <see cref="IDmbProvider"/>.
|
||||
/// </summary>
|
||||
sealed class TemporaryDmbProvider : IDmbProvider
|
||||
sealed class TemporaryDmbProvider : DmbProviderBase
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string DmbName { get; }
|
||||
public override string Directory { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Directory { get; }
|
||||
public override Models.CompileJob CompileJob { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Models.CompileJob CompileJob { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ByondVersion ByondVersion { get; }
|
||||
public override ByondVersion ByondVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TemporaryDmbProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="directory">The value of <see cref="Directory"/>.</param>
|
||||
/// <param name="dmb">The value of <see cref="DmbName"/>.</param>
|
||||
/// <param name="compileJob">The value of <see cref="CompileJob"/>.</param>
|
||||
/// <param name="byondVersion">The value of <see cref="ByondVersion"/>.</param>
|
||||
public TemporaryDmbProvider(string directory, string dmb, Models.CompileJob compileJob, ByondVersion byondVersion)
|
||||
public TemporaryDmbProvider(string directory, Models.CompileJob compileJob, ByondVersion byondVersion)
|
||||
{
|
||||
DmbName = dmb ?? throw new ArgumentNullException(nameof(dmb));
|
||||
Directory = directory ?? throw new ArgumentNullException(nameof(directory));
|
||||
CompileJob = compileJob ?? throw new ArgumentNullException(nameof(compileJob));
|
||||
ByondVersion = byondVersion ?? throw new ArgumentNullException(nameof(byondVersion));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void KeepAlive() => throw new NotSupportedException();
|
||||
public override void KeepAlive() => throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
@@ -34,21 +36,23 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OpenDreamInstallation"/> class.
|
||||
/// </summary>
|
||||
/// <param name="serverExePath">The value of <see cref="ServerExePath"/>.</param>
|
||||
/// <param name="compilerExePath">The value of <see cref="CompilerExePath"/>.</param>
|
||||
/// <param name="installationTask">The value of <see cref="InstallationTask"/>.</param>
|
||||
/// <param name="version">The value of <see cref="Version"/>.</param>
|
||||
public OpenDreamInstallation(
|
||||
string serverExePath,
|
||||
string compilerExePath,
|
||||
Task installationTask,
|
||||
ByondVersion version)
|
||||
{
|
||||
ServerExePath = serverExePath ?? throw new ArgumentNullException(nameof(serverExePath));
|
||||
CompilerExePath = compilerExePath ?? throw new ArgumentNullException(nameof(compilerExePath));
|
||||
InstallationTask = installationTask ?? throw new ArgumentNullException(nameof(installationTask));
|
||||
ArgumentNullException.ThrowIfNull(version);
|
||||
|
||||
if (version.Engine.Value != EngineType.OpenDream)
|
||||
throw new ArgumentException($"Invalid EngineType: {version.Engine.Value}", nameof(version));
|
||||
|
||||
Version = version ?? throw new ArgumentNullException(nameof(version));
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -58,14 +62,33 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
ArgumentNullException.ThrowIfNull(parameters);
|
||||
ArgumentNullException.ThrowIfNull(launchParameters);
|
||||
|
||||
throw new NotImplementedException();
|
||||
var parametersString = String.Join(';', parameters.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
||||
|
||||
if (!String.IsNullOrEmpty(launchParameters.AdditionalParameters))
|
||||
{
|
||||
// TGS and BYOND expect url encoded params, OD takes unencoded
|
||||
var unencodedAdditionalParams = String.Join(
|
||||
';',
|
||||
launchParameters
|
||||
.AdditionalParameters
|
||||
.Split('&')
|
||||
.Select(
|
||||
singleParam => String.Join(
|
||||
'=',
|
||||
singleParam
|
||||
.Split('=')
|
||||
.Select(
|
||||
encodedParam => HttpUtility.UrlDecode(encodedParam)))));
|
||||
|
||||
parametersString = $"{parametersString};{unencodedAdditionalParams}";
|
||||
}
|
||||
|
||||
var arguments = $"--cvar net.port={launchParameters.Port.Value} --cvar opendream.topic_port=0 --cvar opendream.world_params=\"{parametersString}\" \"{dmbProvider.DmbName}\"";
|
||||
return arguments;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string FormatCompilerArguments(string dmePath)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dmePath);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
=> $"--suppress-unimplemented --verbose --notices-enabled {dmePath ?? throw new ArgumentNullException(nameof(dmePath))}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,15 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// </summary>
|
||||
sealed class OpenDreamInstaller : EngineInstallerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the subdirectory used to store the server and compiler binaries.
|
||||
/// </summary>
|
||||
const string InstallationBinDirectory = "bin";
|
||||
|
||||
/// <summary>
|
||||
/// The name of the subdirectory used for the <see cref="RepositoryEngineInstallationData"/>'s copy.
|
||||
/// </summary>
|
||||
private const string InstallationRepositorySubDirectory = "SourceRepo";
|
||||
const string InstallationSourceSubDirectory = "TgsSourceSubdir";
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override EngineType TargetEngineType => EngineType.OpenDream;
|
||||
@@ -82,7 +87,21 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public override IEngineInstallation CreateInstallation(ByondVersion version, Task installationTask)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
return new OpenDreamInstallation(installationTask, version);
|
||||
var binPathForVersion = IOManager.ConcatPath(version.ToString(), InstallationBinDirectory);
|
||||
|
||||
var exeExtension = platformIdentifier.IsWindows
|
||||
? ".exe"
|
||||
: String.Empty;
|
||||
|
||||
return new OpenDreamInstallation(
|
||||
IOManager.ConcatPath(
|
||||
binPathForVersion,
|
||||
$"OpenDreamServer{exeExtension}"),
|
||||
IOManager.ConcatPath(
|
||||
binPathForVersion,
|
||||
$"DMCompiler{exeExtension}"),
|
||||
installationTask,
|
||||
version);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -135,7 +154,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
version.SourceCommittish = repo.Head;
|
||||
|
||||
return new RepositoryEngineInstallationData(IOManager, repo, InstallationRepositorySubDirectory);
|
||||
return new RepositoryEngineInstallationData(IOManager, repo, InstallationSourceSubDirectory);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -149,6 +168,40 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(installPath);
|
||||
var sourcePath = IOManager.ConcatPath(installPath, InstallationSourceSubDirectory);
|
||||
|
||||
if (!await IOManager.DirectoryExists(sourcePath, cancellationToken))
|
||||
{
|
||||
// a zip install that didn't come from us?
|
||||
// we want to use the bin dir, so put everything where we expect
|
||||
Logger.LogDebug("Correcting extraction location...");
|
||||
var dirsTask = IOManager.GetDirectories(installPath, cancellationToken);
|
||||
var filesTask = IOManager.GetFiles(installPath, cancellationToken);
|
||||
var dirCreateTask = IOManager.CreateDirectory(sourcePath, cancellationToken);
|
||||
|
||||
await Task.WhenAll(dirsTask, filesTask, dirCreateTask);
|
||||
|
||||
var dirsMoveTasks = dirsTask
|
||||
.Result
|
||||
.Select(
|
||||
dirPath => IOManager.MoveDirectory(
|
||||
dirPath,
|
||||
IOManager.ConcatPath(
|
||||
sourcePath,
|
||||
IOManager.GetFileName(sourcePath)),
|
||||
cancellationToken));
|
||||
var filesMoveTask = filesTask
|
||||
.Result
|
||||
.Select(
|
||||
filePath => IOManager.MoveFile(
|
||||
filePath,
|
||||
IOManager.ConcatPath(
|
||||
sourcePath,
|
||||
IOManager.GetFileName(sourcePath)),
|
||||
cancellationToken));
|
||||
|
||||
await Task.WhenAll(dirsMoveTasks.Concat(filesMoveTask));
|
||||
}
|
||||
|
||||
var dotnetPaths = DotnetHelper.GetPotentialDotnetPaths(platformIdentifier.IsWindows)
|
||||
.ToList();
|
||||
@@ -165,11 +218,9 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
var dotnetPath = dotnetPaths[selectedPathIndex];
|
||||
|
||||
var repositoryPath = IOManager.ConcatPath(installPath, InstallationRepositorySubDirectory);
|
||||
|
||||
await using (var buildProcess = processExecutor.LaunchProcess(
|
||||
dotnetPath,
|
||||
repositoryPath,
|
||||
sourcePath,
|
||||
"build -c Release",
|
||||
null,
|
||||
true,
|
||||
@@ -180,18 +231,17 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
throw new JobException("OpenDream build failed!");
|
||||
}
|
||||
|
||||
const string BinDirectory = "bin";
|
||||
await IOManager.MoveDirectory(
|
||||
IOManager.ConcatPath(
|
||||
repositoryPath,
|
||||
BinDirectory,
|
||||
sourcePath,
|
||||
InstallationBinDirectory,
|
||||
"Content.Server"),
|
||||
IOManager.ConcatPath(
|
||||
installPath,
|
||||
BinDirectory),
|
||||
InstallationBinDirectory),
|
||||
cancellationToken);
|
||||
|
||||
await IOManager.DeleteDirectory(repositoryPath, cancellationToken);
|
||||
await IOManager.DeleteDirectory(sourcePath, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/// <summary>
|
||||
/// DreamDaemon notifying us of its current port and requesting a change if necessary.
|
||||
/// </summary>
|
||||
PortUpdate,
|
||||
DeprecatedPortUpdate,
|
||||
|
||||
/// <summary>
|
||||
/// DreamDaemon notifying it is starting.
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.Components.Interop.Bridge
|
||||
public BridgeCommandType? CommandType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current port for <see cref="BridgeCommandType.PortUpdate"/> requests.
|
||||
/// The current port for <see cref="BridgeCommandType.DeprecatedPortUpdate"/> requests.
|
||||
/// </summary>
|
||||
public ushort? CurrentPort { get; set; }
|
||||
|
||||
@@ -45,5 +45,10 @@ namespace Tgstation.Server.Host.Components.Interop.Bridge
|
||||
/// The <see cref="ChunkData"/> for <see cref="BridgeCommandType.Chunk"/> requests.
|
||||
/// </summary>
|
||||
public ChunkData Chunk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The port that should be used to send world topics, if not the default.
|
||||
/// </summary>
|
||||
public ushort? TopicPort { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
using Tgstation.Server.Host.Components.Interop.Topic;
|
||||
using Tgstation.Server.Host.Models;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Session
|
||||
@@ -37,7 +37,12 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <summary>
|
||||
/// Gets the <see cref="CompileJob"/> associated with the <see cref="ISessionController"/>.
|
||||
/// </summary>
|
||||
CompileJob CompileJob { get; }
|
||||
Models.CompileJob CompileJob { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Api.Models.Internal.ByondVersion"/> associated with the <see cref="ISessionController"/>.
|
||||
/// </summary>
|
||||
ByondVersion ByondVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Session.ReattachInformation"/> associated with the <see cref="ISessionController"/>.
|
||||
@@ -98,14 +103,6 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="TopicResponse"/> of /world/Topic().</returns>
|
||||
ValueTask<TopicResponse> SendCommand(TopicParameters parameters, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Causes the world to start listening on a <paramref name="newPort"/>.
|
||||
/// </summary>
|
||||
/// <param name="newPort">The port to change to.</param>
|
||||
/// <param name="cancellatonToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if the operation succeeded, <see langword="false"/> otherwise.</returns>
|
||||
Task<bool> SetPort(ushort newPort, CancellationToken cancellatonToken);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to change the current <see cref="RebootState"/> to <paramref name="newRebootState"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,6 +14,7 @@ using Newtonsoft.Json;
|
||||
using Serilog.Context;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Common.Extensions;
|
||||
using Tgstation.Server.Host.Components.Chat;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
@@ -51,6 +52,9 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <inheritdoc />
|
||||
public Models.CompileJob CompileJob => ReattachInformation.Dmb.CompileJob;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ByondVersion ByondVersion => ReattachInformation.Dmb.ByondVersion;
|
||||
|
||||
/// <inheritdoc />
|
||||
public RebootState RebootState => ReattachInformation.RebootState;
|
||||
|
||||
@@ -167,11 +171,6 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// </summary>
|
||||
readonly object synchronizationLock;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TaskCompletionSource{TResult}"/> <see cref="SetPort(ushort, CancellationToken)"/> waits on when DreamDaemon currently has it's ports closed.
|
||||
/// </summary>
|
||||
TaskCompletionSource<bool> portAssignmentTcs;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TaskCompletionSource"/> that completes when DD sends a valid startup bridge request.
|
||||
/// </summary>
|
||||
@@ -197,11 +196,6 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// </summary>
|
||||
volatile uint rebootBridgeRequestsProcessing;
|
||||
|
||||
/// <summary>
|
||||
/// The port to assign DreamDaemon when it queries for it.
|
||||
/// </summary>
|
||||
ushort? nextPort;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ApiValidationStatus"/> for the <see cref="SessionController"/>.
|
||||
/// </summary>
|
||||
@@ -484,40 +478,6 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
return fullResponse;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<bool> SetPort(ushort port, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
if (port == 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(port), port, "port must not be zero!");
|
||||
|
||||
async Task<bool> ImmediateTopicPortChange()
|
||||
{
|
||||
var commandResult = await SendCommand(
|
||||
new TopicParameters(port),
|
||||
cancellationToken);
|
||||
|
||||
if (commandResult?.ErrorMessage != null)
|
||||
return false;
|
||||
|
||||
ReattachInformation.Port = port;
|
||||
return true;
|
||||
}
|
||||
|
||||
lock (synchronizationLock)
|
||||
if (portClosedForReboot)
|
||||
{
|
||||
if (portAssignmentTcs != null)
|
||||
throw new InvalidOperationException("A port change operation is already in progress!");
|
||||
nextPort = port;
|
||||
portAssignmentTcs = new TaskCompletionSource<bool>();
|
||||
return portAssignmentTcs.Task;
|
||||
}
|
||||
else
|
||||
return ImmediateTopicPortChange();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<bool> SetRebootState(RebootState newRebootState, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -702,37 +662,8 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
TerminationWasRequested = true;
|
||||
process.Terminate();
|
||||
break;
|
||||
case BridgeCommandType.PortUpdate:
|
||||
lock (synchronizationLock)
|
||||
{
|
||||
if (!parameters.CurrentPort.HasValue)
|
||||
{
|
||||
/////UHHHH
|
||||
Logger.LogWarning("DreamDaemon sent new port command without providing it's own!");
|
||||
return BridgeError("Missing stringified port as data parameter!");
|
||||
}
|
||||
|
||||
var currentPort = parameters.CurrentPort.Value;
|
||||
if (!nextPort.HasValue)
|
||||
ReattachInformation.Port = parameters.CurrentPort.Value; // not ready yet, so what we'll do is accept the random port DD opened on for now and change it later when we decide to
|
||||
else
|
||||
{
|
||||
// nextPort is ready, tell DD to switch to that
|
||||
// if it fails it'll kill itself
|
||||
response.NewPort = nextPort.Value;
|
||||
ReattachInformation.Port = nextPort.Value;
|
||||
nextPort = null;
|
||||
|
||||
// we'll also get here from SetPort so complete that task
|
||||
var tmpTcs = portAssignmentTcs;
|
||||
portAssignmentTcs = null;
|
||||
tmpTcs.SetResult(true);
|
||||
}
|
||||
|
||||
portClosedForReboot = false;
|
||||
}
|
||||
|
||||
break;
|
||||
case BridgeCommandType.DeprecatedPortUpdate:
|
||||
return BridgeError("Port switching is no longer supported!");
|
||||
case BridgeCommandType.Startup:
|
||||
apiValidationStatus = ApiValidationStatus.BadValidationRequest;
|
||||
if (parameters.Version == null)
|
||||
@@ -774,6 +705,13 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
ReattachInformation.RuntimeInformation.ServerPort,
|
||||
ReattachInformation.RuntimeInformation.ApiValidateOnly);
|
||||
|
||||
if (parameters.TopicPort.HasValue)
|
||||
{
|
||||
var newTopicPort = parameters.TopicPort.Value;
|
||||
Logger.LogInformation("Server is requesting use of port {topicPort} for topic communications", newTopicPort);
|
||||
ReattachInformation.Port = newTopicPort;
|
||||
}
|
||||
|
||||
// Load custom commands
|
||||
chatTrackingContext.CustomCommands = parameters.CustomCommands;
|
||||
Interlocked.Exchange(ref startupTcs, new TaskCompletionSource()).SetResult();
|
||||
@@ -816,7 +754,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
/// <returns>A new errored <see cref="BridgeResponse"/>.</returns>
|
||||
BridgeResponse BridgeError(string message)
|
||||
{
|
||||
Logger.LogWarning("Bridge request chunking error: {message}", message);
|
||||
Logger.LogWarning("Bridge request error: {message}", message);
|
||||
return new BridgeResponse
|
||||
{
|
||||
ErrorMessage = message,
|
||||
|
||||
@@ -255,6 +255,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
await CheckLaunchResult(Server, "Server", cancellationToken);
|
||||
|
||||
Server.EnableCustomChatCommands();
|
||||
|
||||
// persist again, because the DMAPI can say we need a different topic port (Original OD behavior)
|
||||
// kinda hacky imo, but at least we can safely forget about this
|
||||
if (!reattachInProgress)
|
||||
await SessionPersistor.Save(Server.ReattachInformation, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Internal;
|
||||
using Tgstation.Server.Host.Components.Chat;
|
||||
using Tgstation.Server.Host.Components.Deployment;
|
||||
@@ -245,6 +246,16 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
canSeamlesslySwap = false;
|
||||
}
|
||||
|
||||
if (Server.ByondVersion.Engine.Value != EngineType.Byond
|
||||
|| compileJobProvider.ByondVersion.Engine.Value != EngineType.Byond)
|
||||
{
|
||||
Logger.LogDebug(
|
||||
"Not swapping to new compile job {newCompileJobId} as it or the current compile job ({oldCompileJobId}) is not using the BYOND engine. Queueing graceful restart instead...",
|
||||
compileJobProvider.CompileJob.Id,
|
||||
Server.CompileJob.Id);
|
||||
canSeamlesslySwap = false;
|
||||
}
|
||||
|
||||
if (!canSeamlesslySwap)
|
||||
{
|
||||
compileJobProvider.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user