diff --git a/build/Version.props b/build/Version.props
index fe83ec82ae..75afbdc50b 100644
--- a/build/Version.props
+++ b/build/Version.props
@@ -3,7 +3,7 @@
- 5.5.0
+ 5.6.0
4.4.0
9.8.1
10.2.0
diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs b/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs
index 7b83fd5f8d..e6f83363a9 100644
--- a/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/ByondExecutableLock.cs
@@ -20,6 +20,9 @@ namespace Tgstation.Server.Host.Components.Byond
///
public string DreamMakerPath { get; }
+ ///
+ public bool SupportsCli { get; }
+
///
/// The for the .
///
@@ -44,13 +47,15 @@ namespace Tgstation.Server.Host.Components.Byond
/// The value of .
/// The value of .
/// The value of .
+ /// The value of .
public ByondExecutableLock(
IIOManager ioManager,
SemaphoreSlim trustedFileSemaphore,
Version version,
string dreamDaemonPath,
string dreamMakerPath,
- string trustedFilePath)
+ string trustedFilePath,
+ bool supportsCli)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.trustedFileSemaphore = trustedFileSemaphore ?? throw new ArgumentNullException(nameof(trustedFileSemaphore));
@@ -58,6 +63,8 @@ namespace Tgstation.Server.Host.Components.Byond
DreamDaemonPath = dreamDaemonPath ?? throw new ArgumentNullException(nameof(dreamDaemonPath));
DreamMakerPath = dreamMakerPath ?? throw new ArgumentNullException(nameof(dreamMakerPath));
this.trustedFilePath = trustedFilePath ?? throw new ArgumentNullException(nameof(trustedFilePath));
+
+ SupportsCli = supportsCli;
}
// at one point in design, byond versions were to delete themselves if they weren't the active version
diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs
index cbe76ef1b4..67e80cda1f 100644
--- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs
@@ -18,9 +18,6 @@ namespace Tgstation.Server.Host.Components.Byond
///
const string CacheDirectoryName = "cache";
- ///
- public abstract string DreamDaemonName { get; }
-
///
public abstract string DreamMakerName { get; }
@@ -53,6 +50,9 @@ namespace Tgstation.Server.Host.Components.Byond
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
+ ///
+ public abstract string GetDreamDaemonName(Version version, out bool supportsCli);
+
///
public async Task CleanCache(CancellationToken cancellationToken)
{
@@ -77,7 +77,10 @@ namespace Tgstation.Server.Host.Components.Byond
}
///
- public abstract Task InstallByond(string path, Version version, CancellationToken cancellationToken);
+ public abstract Task InstallByond(Version version, string path, CancellationToken cancellationToken);
+
+ ///
+ public abstract Task UpgradeInstallation(Version version, string path, CancellationToken cancellationToken);
///
public Task DownloadVersion(Version version, CancellationToken cancellationToken)
diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs
index 0476292a5f..7aa63f18d2 100644
--- a/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/ByondManager.cs
@@ -166,7 +166,7 @@ namespace Tgstation.Server.Host.Components.Byond
ioManager.ResolvePath(
ioManager.ConcatPath(
binPathForVersion,
- byondInstaller.DreamDaemonName)),
+ byondInstaller.GetDreamDaemonName(versionToUse, out var supportsCli))),
ioManager.ResolvePath(
ioManager.ConcatPath(
binPathForVersion,
@@ -175,7 +175,8 @@ namespace Tgstation.Server.Host.Components.Byond
ioManager.ConcatPath(
byondInstaller.PathToUserByondFolder,
CfgDirectoryName,
- TrustedDmbFileName)));
+ TrustedDmbFileName)),
+ supportsCli);
}
///
@@ -211,6 +212,8 @@ namespace Tgstation.Server.Host.Components.Byond
await ioManager.CreateDirectory(byondDirectory, cancellationToken);
var directories = await ioManager.GetDirectories(byondDirectory, cancellationToken);
+ var installedVersionPaths = new Dictionary();
+
async Task ReadVersion(string path)
{
var versionFile = ioManager.ConcatPath(path, VersionFileName);
@@ -231,6 +234,7 @@ namespace Tgstation.Server.Host.Components.Byond
{
logger.LogDebug("Adding detected BYOND version {0}...", key);
installedVersions.Add(key, Task.CompletedTask);
+ installedVersionPaths.Add(ioManager.ResolvePath(key), version);
return;
}
}
@@ -238,7 +242,10 @@ namespace Tgstation.Server.Host.Components.Byond
await ioManager.DeleteDirectory(path, cancellationToken);
}
- await Task.WhenAll(directories.Select(x => ReadVersion(x)));
+ await Task.WhenAll(directories.Select(ReadVersion));
+
+ logger.LogTrace("Upgrading BYOND installations...");
+ await Task.WhenAll(installedVersionPaths.Select(kvp => byondInstaller.UpgradeInstallation(kvp.Value, kvp.Key, cancellationToken)));
var activeVersionBytes = await activeVersionBytesTask;
if (activeVersionBytes != null)
@@ -339,7 +346,7 @@ namespace Tgstation.Server.Host.Components.Byond
await ioManager.ZipToDirectory(extractPath, versionZipStream, cancellationToken);
}
- await byondInstaller.InstallByond(extractPath, version, cancellationToken);
+ await byondInstaller.InstallByond(version, extractPath, cancellationToken);
// make sure to do this last because this is what tells us we have a valid version in the future
await ioManager.WriteAllBytes(
diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs b/src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs
index 200aca5a71..ef90080042 100644
--- a/src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/IByondExecutableLock.cs
@@ -24,6 +24,11 @@ namespace Tgstation.Server.Host.Components.Byond
///
string DreamMakerPath { get; }
+ ///
+ /// If supports being run as a command-line application.
+ ///
+ bool SupportsCli { get; }
+
///
/// Call if, during a detach, this version should not be deleted.
///
diff --git a/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs
index ad1edcc08f..cc49610e64 100644
--- a/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/IByondInstaller.cs
@@ -10,11 +10,6 @@ namespace Tgstation.Server.Host.Components.Byond
///
interface IByondInstaller
{
- ///
- /// Get the file name of the DreamDaemon executable.
- ///
- string DreamDaemonName { get; }
-
///
/// Get the file name of the DreamMaker executable.
///
@@ -25,6 +20,14 @@ namespace Tgstation.Server.Host.Components.Byond
///
string PathToUserByondFolder { get; }
+ ///
+ /// Get the file name of the DreamDaemon executable.
+ ///
+ /// The of BYOND to select the executable name for.
+ /// Whether or not the returned path supports being run as a command-line application.
+ /// The file name of the DreamDaemon executable.
+ string GetDreamDaemonName(Version version, out bool supportsCli);
+
///
/// Download a given BYOND .
///
@@ -36,11 +39,20 @@ namespace Tgstation.Server.Host.Components.Byond
///
/// Does actions necessary to get an extracted BYOND installation working.
///
- /// The path to the BYOND installation.
/// The of BYOND being installed.
+ /// The path to the BYOND installation.
/// The for the operation.
/// A representing the running operation.
- Task InstallByond(string path, Version version, CancellationToken cancellationToken);
+ Task InstallByond(Version version, string path, CancellationToken cancellationToken);
+
+ ///
+ /// Does actions necessary to get upgrade a BYOND version installed by a previous version of TGS.
+ ///
+ /// The of BYOND being installed.
+ /// The path to the BYOND installation.
+ /// The for the operation.
+ /// A representing the running operation.
+ Task UpgradeInstallation(Version version, string path, CancellationToken cancellationToken);
///
/// Attempts to cleans the BYOND cache folder for the system.
diff --git a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs
index 00fd577788..876ed37aa7 100644
--- a/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/PosixByondInstaller.cs
@@ -30,9 +30,6 @@ namespace Tgstation.Server.Host.Components.Byond
///
const string ShellScriptExtension = ".sh";
- ///
- public override string DreamDaemonName => DreamDaemonExecutableName + ShellScriptExtension;
-
///
public override string DreamMakerName => DreamMakerExecutableName + ShellScriptExtension;
@@ -66,13 +63,23 @@ namespace Tgstation.Server.Host.Components.Byond
}
///
- public override Task InstallByond(string path, Version version, CancellationToken cancellationToken)
+ public override string GetDreamDaemonName(Version version, out bool supportsCli)
{
- if (path == null)
- throw new ArgumentNullException(nameof(path));
if (version == null)
throw new ArgumentNullException(nameof(version));
+ supportsCli = true;
+ return DreamDaemonExecutableName + ShellScriptExtension;
+ }
+
+ ///
+ public override Task InstallByond(Version version, string path, CancellationToken cancellationToken)
+ {
+ if (version == null)
+ throw new ArgumentNullException(nameof(version));
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+
// write the scripts for running the ting
// need to add $ORIGIN to LD_LIBRARY_PATH
const string StandardScript = "#!/bin/sh\nexport LD_LIBRARY_PATH=\"\\$ORIGIN:$LD_LIBRARY_PATH\"\nBASEDIR=$(dirname \"$0\")\nexec \"$BASEDIR/{0}\" \"$@\"\n";
@@ -89,12 +96,29 @@ namespace Tgstation.Server.Host.Components.Byond
var basePath = IOManager.ConcatPath(path, ByondManager.BinPath);
- var task = Task.WhenAll(WriteAndMakeExecutable(IOManager.ConcatPath(basePath, DreamDaemonName), dreamDaemonScript), WriteAndMakeExecutable(IOManager.ConcatPath(basePath, DreamMakerName), dreamMakerScript));
+ var task = Task.WhenAll(
+ WriteAndMakeExecutable(
+ IOManager.ConcatPath(basePath, GetDreamDaemonName(version, out var _)),
+ dreamDaemonScript),
+ WriteAndMakeExecutable(
+ IOManager.ConcatPath(basePath, DreamMakerName),
+ dreamMakerScript));
postWriteHandler.HandleWrite(IOManager.ConcatPath(basePath, DreamDaemonExecutableName));
postWriteHandler.HandleWrite(IOManager.ConcatPath(basePath, DreamMakerExecutableName));
return task;
}
+
+ ///
+ public override Task UpgradeInstallation(Version version, string path, CancellationToken cancellationToken)
+ {
+ if (version == null)
+ throw new ArgumentNullException(nameof(version));
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+
+ return Task.CompletedTask;
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
index 678e12347f..03d6b9389f 100644
--- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
@@ -41,8 +41,10 @@ namespace Tgstation.Server.Host.Components.Byond
///
const string ByondDXDir = "byond/directx";
- ///
- public override string DreamDaemonName => "dreamdaemon.exe";
+ ///
+ /// The file TGS uses to determine if dd.exe has been firewalled.
+ ///
+ const string TgsFirewalledDDFile = "TGSFirewalledDD";
///
public override string DreamMakerName => "dm.exe";
@@ -96,7 +98,17 @@ namespace Tgstation.Server.Host.Components.Byond
public void Dispose() => semaphore.Dispose();
///
- public override Task InstallByond(string path, Version version, CancellationToken cancellationToken)
+ public override string GetDreamDaemonName(Version version, out bool supportsCli)
+ {
+ if (version == null)
+ throw new ArgumentNullException(nameof(version));
+
+ supportsCli = version.Major >= 515 && version.Minor >= 1598;
+ return supportsCli ? "dd.exe" : "dreamdaemon.exe";
+ }
+
+ ///
+ public override Task InstallByond(Version version, string path, CancellationToken cancellationToken)
{
var tasks = new List
{
@@ -105,11 +117,33 @@ namespace Tgstation.Server.Host.Components.Byond
};
if (!generalConfiguration.SkipAddingByondFirewallException)
- tasks.Add(AddDreamDaemonToFirewall(path, cancellationToken));
+ tasks.Add(AddDreamDaemonToFirewall(version, path, cancellationToken));
return Task.WhenAll(tasks);
}
+ ///
+ public override async Task UpgradeInstallation(Version version, string path, CancellationToken cancellationToken)
+ {
+ if (version == null)
+ throw new ArgumentNullException(nameof(version));
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+
+ if (generalConfiguration.SkipAddingByondFirewallException)
+ return;
+
+ GetDreamDaemonName(version, out var usesDDExe);
+ if (!usesDDExe)
+ return;
+
+ if (await IOManager.FileExists(IOManager.ConcatPath(path, TgsFirewalledDDFile), cancellationToken))
+ return;
+
+ Logger.LogInformation("BYOND Version {version} needs dd.exe added to firewall", version);
+ await AddDreamDaemonToFirewall(version, path, cancellationToken);
+ }
+
///
/// Creates the BYOND cfg file that prevents the trusted mode dialog from appearing when launching DreamDaemon.
///
@@ -177,17 +211,21 @@ namespace Tgstation.Server.Host.Components.Byond
///
/// Attempt to add the DreamDaemon executable as an exception to the Windows firewall.
///
+ /// The BYOND .
/// The path to the BYOND installation.
/// The for the operation.
/// A representing the running operation.
- async Task AddDreamDaemonToFirewall(string path, CancellationToken cancellationToken)
+ async Task AddDreamDaemonToFirewall(Version version, string path, CancellationToken cancellationToken)
{
+ var dreamDaemonName = GetDreamDaemonName(version, out var supportsCli);
+
var dreamDaemonPath = IOManager.ResolvePath(
IOManager.ConcatPath(
path,
ByondManager.BinPath,
- DreamDaemonName));
+ dreamDaemonName));
+ Logger.LogInformation("Adding Windows Firewall exception for {path}...", dreamDaemonPath);
try
{
using var netshProcess = processExecutor.LaunchProcess(
@@ -210,6 +248,12 @@ namespace Tgstation.Server.Host.Components.Byond
if (exitCode != 0)
throw new JobException(ErrorCode.ByondDreamDaemonFirewallFail, new JobException($"Invalid exit code: {exitCode}"));
+
+ if (supportsCli)
+ await IOManager.WriteAllBytes(
+ IOManager.ConcatPath(path, TgsFirewalledDDFile),
+ Array.Empty(),
+ cancellationToken);
}
catch (Exception ex)
{
diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
index 019e188cfa..c57099f5a8 100644
--- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
@@ -679,7 +679,7 @@ namespace Tgstation.Server.Host.Components.Chat
message.User.Channel.IsAdminChannel = mappingChannelRepresentation.IsAdminChannel;
}
- var splits = new List(message.Content.Trim().Split(' '));
+ var splits = new List(message.Content.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries));
var address = splits[0];
if (address.Length > 1 && (address.Last() == ':' || address.Last() == ','))
address = address[0..^1];
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
index 9117f5eb5d..e938adeb17 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
@@ -282,23 +282,22 @@ namespace Tgstation.Server.Host.Components.Session
Guid? logFileGuid = null;
var arguments = String.Format(
CultureInfo.InvariantCulture,
- "{0} -port {1} -ports 1-65535 {2}-close -verbose -logself -{3} -{4}{5}{6} -params \"{7}\"",
+ "{0} -port {1} -ports 1-65535 {2}-close -verbose -{3} -{4}{5}{6} -params \"{7}\"",
dmbProvider.DmbName,
launchParameters.Port.Value,
launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty,
SecurityWord(launchParameters.SecurityLevel.Value),
VisibilityWord(launchParameters.Visibility.Value),
- platformIdentifier.IsWindows
- ? $" -log {logFileGuid = Guid.NewGuid()}"
- : String.Empty, // Just use stdout on linux
+ !byondLock.SupportsCli
+ ? $" -logself -log {logFileGuid = Guid.NewGuid()}"
+ : !platformIdentifier.IsWindows // Just use stdout on if CLI is supported
+ ? " -logself"
+ : String.Empty, // Windows doesn't output anything to dd.exe if -logself is set?
launchParameters.StartProfiler.Value
? " -profile"
: String.Empty,
parameters);
- // See https://github.com/tgstation/tgstation-server/issues/719
- var noShellExecute = !platformIdentifier.IsWindows;
-
if (!apiValidate && dmbProvider.CompileJob.DMApiVersion == null)
logger.LogDebug("Session will have no DMAPI support!");
@@ -307,14 +306,15 @@ namespace Tgstation.Server.Host.Components.Session
byondLock.DreamDaemonPath,
dmbProvider.Directory,
arguments,
- noShellExecute,
- noShellExecute,
- noShellExecute: noShellExecute);
+ byondLock.SupportsCli,
+ byondLock.SupportsCli,
+ byondLock.SupportsCli);
+ var cliSupported = byondLock.SupportsCli;
async Task GetDDOutput()
{
// DCT x2: None available
- if (!platformIdentifier.IsWindows)
+ if (cliSupported)
return await process.GetCombinedOutput(default);
var logFilePath = ioManager.ConcatPath(dmbProvider.Directory, logFileGuid.ToString());
diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs
index 7ef2eeed3f..4a7225df13 100644
--- a/src/Tgstation.Server.Host/System/Process.cs
+++ b/src/Tgstation.Server.Host/System/Process.cs
@@ -112,7 +112,7 @@ namespace Tgstation.Server.Host.System
}
catch (Exception ex)
{
- logger.LogDebug(ex, "Error on WaitForInputIdle()!");
+ logger.LogTrace(ex, "WaitForInputIdle() failed, this is normal.");
}
},
default, // DCT: None available
diff --git a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs
index de7d2fc05c..558ccf0faf 100644
--- a/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs
+++ b/tests/Tgstation.Server.Host.Tests/Components/Byond/TestPosixByondInstaller.cs
@@ -65,9 +65,9 @@ namespace Tgstation.Server.Host.Components.Byond.Tests
const string FakePath = "fake";
await Assert.ThrowsExceptionAsync(() => installer.InstallByond(null, null, default));
- await Assert.ThrowsExceptionAsync(() => installer.InstallByond(FakePath, null, default));
+ await Assert.ThrowsExceptionAsync(() => installer.InstallByond(new Version(123,252345), null, default));
- await installer.InstallByond(FakePath, new Version(511, 1385), default);
+ await installer.InstallByond(new Version(511, 1385), FakePath, default);
mockPostWriteHandler.Verify(x => x.HandleWrite(It.IsAny()), Times.Exactly(4));
}
diff --git a/tests/Tgstation.Server.Tests/Instance/ByondTest.cs b/tests/Tgstation.Server.Tests/Instance/ByondTest.cs
index 92dca4144d..f2e69aeee4 100644
--- a/tests/Tgstation.Server.Tests/Instance/ByondTest.cs
+++ b/tests/Tgstation.Server.Tests/Instance/ByondTest.cs
@@ -1,5 +1,4 @@
-using Castle.Core.Logging;
-using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
@@ -103,6 +102,8 @@ namespace Tgstation.Server.Tests.Instance
new DefaultIOManager(new AssemblyInformationProvider()),
Mock.Of>());
+ using var windowsByondInstaller = byondInstaller as WindowsByondInstaller;
+
// get the bytes for stable
using var stableBytesMs = await byondInstaller.DownloadVersion(TestVersion, cancellationToken);