diff --git a/build/Version.props b/build/Version.props
index ef659a9af2..b169916252 100644
--- a/build/Version.props
+++ b/build/Version.props
@@ -2,10 +2,10 @@
- 4.2.0
+ 4.2.1
6.2.0
6.1.0
- 5.1.0
+ 5.1.1
0.4.0
1.1.0
diff --git a/build/prep_deployment.ps1 b/build/prep_deployment.ps1
index 2f50c5b2b7..358b72d8c6 100644
--- a/build/prep_deployment.ps1
+++ b/build/prep_deployment.ps1
@@ -1,5 +1,7 @@
$bf = $env:APPVEYOR_BUILD_FOLDER
-[XML]$versionXML = Get-Content "$bf/build/Version.props"
+$propsPath = "$bf/build/Version.props"
+
+[XML]$versionXML = Get-Content $propsPath
$env:TGSVersion = $versionXML.Project.PropertyGroup.TgsCoreVersion
$env:APIVersion = $versionXML.Project.PropertyGroup.TgsApiVersion
$env:DMVersion = $versionXML.Project.PropertyGroup.TgsDmapiVersion
@@ -11,7 +13,7 @@ if (($env:CONFIGURATION -match "Release") -And ($env:APPVEYOR_REPO_BRANCH -match
$env:TGSDeploy = "Do it."
Write-Host "Generating release notes..."
- dotnet run -p "$bf/tools/ReleaseNotes" $env:TGSVersion
+ dotnet run -p "$bf/tools/ReleaseNotes" $env:TGSVersion $propsPath
$env:TGSDraftNotes = !($?)
$releaseNotesPath = "$bf/release_notes.md"
Write-Host "Reading release notes from $releaseNotesPath..."
diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm
index 9f84fdd3cb..e164a4ec96 100644
--- a/src/DMAPI/tgs.dm
+++ b/src/DMAPI/tgs.dm
@@ -1,6 +1,6 @@
//tgstation-server DMAPI
-#define TGS_DMAPI_VERSION "5.1.0"
+#define TGS_DMAPI_VERSION "5.1.1"
//All functions and datums outside this document are subject to change with any version and should not be relied on
diff --git a/src/DMAPI/tgs/core/datum.dm b/src/DMAPI/tgs/core/datum.dm
index 3abf5f284f..ccc75fe344 100644
--- a/src/DMAPI/tgs/core/datum.dm
+++ b/src/DMAPI/tgs/core/datum.dm
@@ -6,7 +6,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version)
. = ..()
- src.event_handler = version
+ src.event_handler = event_handler
src.version = version
/datum/tgs_api/latest
diff --git a/src/DMAPI/tgs/v5/_defines.dm b/src/DMAPI/tgs/v5/_defines.dm
index 4abd059677..2baf3e12d7 100644
--- a/src/DMAPI/tgs/v5/_defines.dm
+++ b/src/DMAPI/tgs/v5/_defines.dm
@@ -60,10 +60,10 @@
#define DMAPI5_TOPIC_COMMAND_CHANGE_PORT 2
#define DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE 3
#define DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED 4
-#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 4
-#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 5
-#define DMAPI5_TOPIC_COMMAND_HEARTBEAT 6
-#define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 7
+#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 5
+#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 6
+#define DMAPI5_TOPIC_COMMAND_HEARTBEAT 7
+#define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 8
#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
diff --git a/src/DMAPI/tgs/v5/api.dm b/src/DMAPI/tgs/v5/api.dm
index f0c38a7c24..eedefb2877 100644
--- a/src/DMAPI/tgs/v5/api.dm
+++ b/src/DMAPI/tgs/v5/api.dm
@@ -16,7 +16,7 @@
var/list/chat_channels
/datum/tgs_api/v5/ApiVersion()
- return new /datum/tgs_version("5.1.0")
+ return new /datum/tgs_version("5.1.1")
/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level)
server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
diff --git a/src/Tgstation.Server.Api/Models/ErrorCode.cs b/src/Tgstation.Server.Api/Models/ErrorCode.cs
index 19c999d4f2..9de878067c 100644
--- a/src/Tgstation.Server.Api/Models/ErrorCode.cs
+++ b/src/Tgstation.Server.Api/Models/ErrorCode.cs
@@ -415,7 +415,7 @@ namespace Tgstation.Server.Api.Models
///
/// Attempted to start the watchdog with a corrupted .
///
- [Description("Cannot launch with active compile job as it is corrupted!")]
+ [Description("Cannot launch active compile job as it is missing or corrupted!")]
WatchdogCompileJobCorrupted,
///
diff --git a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
index c57ae5c352..eb249c99c7 100644
--- a/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/WindowsByondInstaller.cs
@@ -119,7 +119,10 @@ namespace Tgstation.Server.Host.Components.Byond
IProcess directXInstaller;
try
{
- directXInstaller = processExecutor.LaunchProcess(IOManager.ConcatPath(rbdx, "DXSETUP.exe"), rbdx, "/silent", noShellExecute: true);
+ directXInstaller = processExecutor.LaunchProcess(
+ IOManager.ConcatPath(rbdx, "DXSETUP.exe"),
+ rbdx, "/silent",
+ noShellExecute: true);
}
catch (Exception e)
{
diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
index 2782f9aba1..94e01c8af5 100644
--- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
@@ -646,7 +646,8 @@ namespace Tgstation.Server.Host.Components.Chat
public async Task StopAsync(CancellationToken cancellationToken)
{
handlerCts.Cancel();
- await chatHandler.ConfigureAwait(false);
+ if (chatHandler != null)
+ await chatHandler.ConfigureAwait(false);
await Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Disconnect(cancellationToken))).ConfigureAwait(false);
}
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs
index fd368e5ef3..62a03990dd 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs
@@ -118,7 +118,7 @@ namespace Tgstation.Server.Host.Components.Deployment
if (!jobLockCounts.TryGetValue(job.Id, out var currentVal) || currentVal == 1)
{
jobLockCounts.Remove(job.Id);
- logger.LogDebug("Cleaning compile job {0} => {1}", job.Id, job.DirectoryName);
+ logger.LogDebug("Cleaning lock-free compile job {0} => {1}", job.Id, job.DirectoryName);
cleanupTask = HandleCleanup();
}
else
@@ -247,7 +247,7 @@ namespace Tgstation.Server.Host.Components.Deployment
///
#pragma warning disable CA1506 // TODO: Decomplexify
- public async Task CleanUnusedCompileJobs(CompileJob exceptThisOne, CancellationToken cancellationToken)
+ public async Task CleanUnusedCompileJobs(CancellationToken cancellationToken)
{
List jobIdsToSkip;
@@ -260,12 +260,18 @@ namespace Tgstation.Server.Host.Components.Deployment
// find the uids of locked directories
await databaseContextFactory.UseContext(async db =>
{
- jobUidsToNotErase = await db.CompileJobs.Where(x => x.Job.Instance.Id == instance.Id && jobIdsToSkip.Contains(x.Id)).Select(x => x.DirectoryName.Value.ToString().ToUpperInvariant()).ToListAsync(cancellationToken).ConfigureAwait(false);
+ jobUidsToNotErase = (await db.CompileJobs.Where(
+ x => x.Job.Instance.Id == instance.Id && jobIdsToSkip.Contains(x.Id))
+ .Select(x => x.DirectoryName.Value)
+ .ToListAsync(cancellationToken)
+ .ConfigureAwait(false))
+ .Select(x => x.ToString())
+ .ToList();
}).ConfigureAwait(false);
- // add the other exemption
- if (exceptThisOne != null)
- jobUidsToNotErase.Add(exceptThisOne.DirectoryName.Value.ToString().ToUpperInvariant());
+ jobUidsToNotErase.Add(WindowsSwappableDmbProvider.LiveGameDirectory);
+
+ logger.LogTrace("We will not clean the following directories: {0}", String.Join(", ", jobUidsToNotErase));
// cleanup
var gameDirectory = ioManager.ResolvePath();
@@ -275,8 +281,9 @@ namespace Tgstation.Server.Host.Components.Deployment
var tasks = directories.Select(async x =>
{
var nameOnly = ioManager.GetFileName(x);
- if (jobUidsToNotErase.Contains(nameOnly.ToUpperInvariant()))
+ if (jobUidsToNotErase.Contains(nameOnly))
return;
+ logger.LogDebug("Cleaning unused game folder: {0}...", nameOnly);
try
{
++deleting;
@@ -292,10 +299,7 @@ namespace Tgstation.Server.Host.Components.Deployment
}
}).ToList();
if (deleting > 0)
- {
- logger.LogDebug("Cleaning unused game folders: {0}...", String.Join(", ", directories));
- await Task.WhenAll().ConfigureAwait(false);
- }
+ await Task.WhenAll(tasks).ConfigureAwait(false);
}
#pragma warning restore CA1506
}
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
index 8cceeb1dd4..3c2b21bb43 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
@@ -244,6 +244,7 @@ namespace Tgstation.Server.Host.Components.Deployment
ADirectoryName)),
$"-clean {job.DmeName}.{DmeExtension}",
true,
+ true,
true);
int exitCode;
using (cancellationToken.Register(() => dm.Terminate()))
@@ -381,7 +382,7 @@ namespace Tgstation.Server.Host.Components.Deployment
await chatManager.SendUpdateMessage(
String.Format(
CultureInfo.InvariantCulture,
- "*Deployment Triggered*{0}Revision: {1}{2}{3}{0} BYOND Version: {4}.{5}",
+ "*Deployment Triggered*{0}Revision: {1}{2}{3}{0}BYOND Version: {4}.{5}",
Environment.NewLine,
commitInsert,
testmergeInsert,
diff --git a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs
index 266f3b41e8..4f5059c2be 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/IDmbFactory.cs
@@ -37,11 +37,10 @@ namespace Tgstation.Server.Host.Components.Deployment
Task FromCompileJob(CompileJob compileJob, CancellationToken cancellationToken);
///
- /// Deletes all compile jobs that are inactive in the Game folder
+ /// Deletes all compile jobs that are inactive in the Game folder.
///
- /// An optional compile job to not delete
/// The for the operation
/// A representing the running operation
- Task CleanUnusedCompileJobs(CompileJob exceptThisOne, CancellationToken cancellationToken);
+ Task CleanUnusedCompileJobs(CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Deployment/WindowsSwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/WindowsSwappableDmbProvider.cs
index add8f65690..597333c54c 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/WindowsSwappableDmbProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/WindowsSwappableDmbProvider.cs
@@ -14,7 +14,7 @@ namespace Tgstation.Server.Host.Components.Deployment
///
/// The directory where the is symlinked to.
///
- const string LiveGameDirectory = "Live";
+ public const string LiveGameDirectory = "Live";
///
public string DmbName => baseProvider.DmbName;
diff --git a/src/Tgstation.Server.Host/Components/EventConsumer.cs b/src/Tgstation.Server.Host/Components/EventConsumer.cs
index e204cbcf8f..1cebdd1d2b 100644
--- a/src/Tgstation.Server.Host/Components/EventConsumer.cs
+++ b/src/Tgstation.Server.Host/Components/EventConsumer.cs
@@ -30,14 +30,13 @@ namespace Tgstation.Server.Host.Components
}
///
- public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
+ public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
{
if (watchdog == null)
throw new InvalidOperationException("EventConsumer used without watchdog set!");
- if (!await configuration.HandleEvent(eventType, parameters, cancellationToken).ConfigureAwait(false))
- return false;
- return await watchdog.HandleEvent(eventType, parameters, cancellationToken).ConfigureAwait(false);
+ await configuration.HandleEvent(eventType, parameters, cancellationToken).ConfigureAwait(false);
+ await watchdog.HandleEvent(eventType, parameters, cancellationToken).ConfigureAwait(false);
}
///
diff --git a/src/Tgstation.Server.Host/Components/IEventConsumer.cs b/src/Tgstation.Server.Host/Components/IEventConsumer.cs
index aa30d18827..f4dd616bd8 100644
--- a/src/Tgstation.Server.Host/Components/IEventConsumer.cs
+++ b/src/Tgstation.Server.Host/Components/IEventConsumer.cs
@@ -15,7 +15,7 @@ namespace Tgstation.Server.Host.Components
/// The
/// The parameters for
/// The for the operation
- /// A resulting in if more should run, otherwise
- Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken);
+ /// A representing the running operation.
+ Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs
index 0e23c4cca1..87814d36c6 100644
--- a/src/Tgstation.Server.Host/Components/Instance.cs
+++ b/src/Tgstation.Server.Host/Components/Instance.cs
@@ -15,7 +15,6 @@ using Tgstation.Server.Host.Components.Repository;
using Tgstation.Server.Host.Components.Watchdog;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
-using Tgstation.Server.Host.Extensions;
using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Models;
@@ -623,12 +622,7 @@ namespace Tgstation.Server.Host.Components
// dependent on so many things, its just safer this way
await Watchdog.StartAsync(cancellationToken).ConfigureAwait(false);
- CompileJob latestCompileJob = null;
- await databaseContextFactory.UseContext(async db =>
- {
- latestCompileJob = await db.MostRecentCompletedCompileJobOrDefault(metadata, cancellationToken).ConfigureAwait(false);
- }).ConfigureAwait(false);
- await dmbFactory.CleanUnusedCompileJobs(latestCompileJob, cancellationToken).ConfigureAwait(false);
+ await dmbFactory.CleanUnusedCompileJobs(cancellationToken).ConfigureAwait(false);
}
///
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index d9991f0044..7b841e1270 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -235,6 +235,7 @@ namespace Tgstation.Server.Host.Components
bridgeRegistrar,
serverPortProvider,
loggerFactory,
+ loggerFactory.CreateLogger(),
metadata.CloneMetadata());
var dmbFactory = new DmbFactory(databaseContextFactory, gameIoManager, loggerFactory.CreateLogger(), metadata.CloneMetadata());
diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs
index f14967cf94..f7f4820dc7 100644
--- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs
@@ -33,7 +33,7 @@ namespace Tgstation.Server.Host.Components.Interop
///
/// The DMAPI being used.
///
- public static readonly Version Version = new Version(5, 1, 0);
+ public static readonly Version Version = new Version(5, 1, 1);
///
/// for use when communicating with the DMAPI.
diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
index 43bf3baa27..4a6aef276e 100644
--- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
@@ -163,8 +163,8 @@ namespace Tgstation.Server.Host.Components.Repository
if (remote.EndsWith(item, StringComparison.OrdinalIgnoreCase))
remote = remote.Substring(0, remote.LastIndexOf(item, StringComparison.OrdinalIgnoreCase));
var splits = remote.Split('/');
- name = splits[splits.Length - 1];
- owner = splits[splits.Length - 2].Split('.')[0];
+ name = splits.Last();
+ owner = splits[^2].Split('.').First();
logger.LogTrace("GetRepositoryOwnerName({0}) => {1} / {2}", remote, owner, name);
}
@@ -622,18 +622,14 @@ namespace Tgstation.Server.Host.Components.Repository
cancellationToken.ThrowIfCancellationRequested();
try
{
- if (!await eventConsumer.HandleEvent(
+ await eventConsumer.HandleEvent(
EventType.RepoPreSynchronize,
new List
{
ioMananger.ResolvePath()
},
cancellationToken)
- .ConfigureAwait(false))
- {
- logger.LogDebug("Aborted synchronize due to event handler response!");
- return false;
- }
+ .ConfigureAwait(false);
}
finally
{
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs
index 51f33bf3df..0e8e1736bf 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs
@@ -522,7 +522,6 @@ namespace Tgstation.Server.Host.Components.Session
var json = JsonConvert.SerializeObject(parameters, DMApiConstants.SerializerSettings);
logger.LogTrace("Topic request: {0}", json);
- Exception caughtException;
try
{
var commandString = String.Format(CultureInfo.InvariantCulture,
@@ -558,19 +557,20 @@ namespace Tgstation.Server.Host.Components.Session
return new CombinedTopicResponse(topicResponse, interopResponse);
}
- catch (OperationCanceledException e)
+ catch (OperationCanceledException)
{
+ logger.LogTrace(
+ "Topic request {0}!",
+ cancellationToken.IsCancellationRequested
+ ? "aborted"
+ : "timed out");
cancellationToken.ThrowIfCancellationRequested();
- caughtException = e;
}
catch (Exception e)
{
- caughtException = e;
+ logger.LogWarning("Send command exception:{0}{1}", Environment.NewLine, e);
}
- if (caughtException == null)
- logger.LogWarning("Send command exception:{0}{1}", Environment.NewLine, caughtException.Message);
-
return null;
}
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
index aef22ee773..92a76a973b 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionControllerFactory.cs
@@ -15,6 +15,7 @@ using Tgstation.Server.Host.Components.Interop;
using Tgstation.Server.Host.Components.Interop.Bridge;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.IO;
+using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
@@ -83,6 +84,11 @@ namespace Tgstation.Server.Host.Components.Session
///
readonly ILoggerFactory loggerFactory;
+ ///
+ /// The for the
+ ///
+ readonly ILogger logger;
+
///
/// The for the
///
@@ -120,6 +126,7 @@ namespace Tgstation.Server.Host.Components.Session
/// The value of .
/// The value of .
/// The value of
+ /// The value of .
public SessionControllerFactory(
IProcessExecutor processExecutor,
IByondManager byond,
@@ -133,6 +140,7 @@ namespace Tgstation.Server.Host.Components.Session
IBridgeRegistrar bridgeRegistrar,
IServerPortProvider serverPortProvider,
ILoggerFactory loggerFactory,
+ ILogger logger,
Api.Models.Instance instance)
{
this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor));
@@ -148,6 +156,7 @@ namespace Tgstation.Server.Host.Components.Session
this.bridgeRegistrar = bridgeRegistrar ?? throw new ArgumentNullException(nameof(bridgeRegistrar));
this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider));
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
///
@@ -192,6 +201,8 @@ namespace Tgstation.Server.Host.Components.Session
if (launchParameters.SecurityLevel == DreamDaemonSecurity.Trusted)
await byondLock.TrustDmbPath(ioManager.ConcatPath(basePath, dmbProvider.DmbName), cancellationToken).ConfigureAwait(false);
+ CheckPagerIsNotRunning();
+
var accessIdentifier = cryptographySuite.GetSecureString();
// set command line options
@@ -213,7 +224,24 @@ namespace Tgstation.Server.Host.Components.Session
var noShellExecute = !platformIdentifier.IsWindows;
// launch dd
- var process = processExecutor.LaunchProcess(byondLock.DreamDaemonPath, basePath, arguments, noShellExecute: noShellExecute);
+ var process = processExecutor.LaunchProcess(
+ byondLock.DreamDaemonPath,
+ basePath,
+ arguments,
+ noShellExecute,
+ noShellExecute,
+ noShellExecute: noShellExecute);
+
+ if (noShellExecute)
+ {
+ // Log DD output
+ _ = process.Lifetime.ContinueWith(
+ x => logger.LogTrace(
+ "DreamDaemon Output:{0}{1}",
+ Environment.NewLine, process.GetCombinedOutput()),
+ TaskScheduler.Current);
+ }
+
try
{
networkPromptReaper.RegisterProcess(process);
@@ -371,5 +399,14 @@ namespace Tgstation.Server.Host.Components.Session
securityLevel,
apiValidateOnly);
}
+
+ ///
+ /// Make sure the BYOND pager is not running.
+ ///
+ void CheckPagerIsNotRunning()
+ {
+ if (platformIdentifier.IsWindows && processExecutor.IsProcessWithNameRunning("byond"))
+ throw new JobException("Cannot start DreamDaemon headless with the BYOND pager running!");
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
index c2ce055042..17ebbe5a5e 100644
--- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
+++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
@@ -11,6 +11,7 @@ using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.IO;
+using Tgstation.Server.Host.Jobs;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
@@ -442,12 +443,12 @@ namespace Tgstation.Server.Host.Components.StaticFiles
public Task StopAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
///
- public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
+ public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
{
await EnsureDirectories(cancellationToken).ConfigureAwait(false);
if (!EventTypeScriptFileNameMap.TryGetValue(eventType, out var scriptName))
- return true;
+ return;
// always execute in serial
using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
@@ -456,17 +457,22 @@ namespace Tgstation.Server.Host.Components.StaticFiles
var resolvedScriptsDir = ioManager.ResolvePath(EventScriptsSubdirectory);
foreach (var I in files.Select(x => ioManager.GetFileName(x)).Where(x => x.StartsWith(scriptName, StringComparison.Ordinal)))
- using (var script = processExecutor.LaunchProcess(ioManager.ConcatPath(resolvedScriptsDir, I), resolvedScriptsDir, String.Join(' ', parameters), noShellExecute: true))
+ using (var script = processExecutor.LaunchProcess(
+ ioManager.ConcatPath(resolvedScriptsDir, I),
+ resolvedScriptsDir,
+ String.Join(' ', parameters),
+ true,
+ true,
+ true))
using (cancellationToken.Register(() => script.Terminate()))
{
var exitCode = await script.Lifetime.ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
+ var scriptOutput = script.GetCombinedOutput();
if (exitCode != 0)
- return false;
+ throw new JobException($"Script {I} exited with code {exitCode}:{Environment.NewLine}{scriptOutput}");
}
}
-
- return true;
}
///
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index abbbb4598d..3f026305ce 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -727,19 +727,15 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
///
- public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
+ public async Task HandleEvent(EventType eventType, IEnumerable parameters, CancellationToken cancellationToken)
{
- if (!Running)
- return true;
-
- var notification = new EventNotification(eventType, parameters);
-
var activeServer = GetActiveController();
// Server may have ended
if (activeServer == null)
- return true;
+ return;
+ var notification = new EventNotification(eventType, parameters);
var result = await activeServer.SendCommand(
new TopicParameters(notification),
cancellationToken)
@@ -762,8 +758,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
.Select(nullableChannelId => nullableChannelId.Value),
cancellationToken)))
.ConfigureAwait(false);
-
- return true;
}
///
diff --git a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs
index 68fae14333..9699c86a16 100644
--- a/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs
+++ b/src/Tgstation.Server.Host/Database/Design/DesignTimeDbContextFactoryHelpers.cs
@@ -1,8 +1,5 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Options;
using Tgstation.Server.Host.Configuration;
-using Tgstation.Server.Host.IO;
-using Tgstation.Server.Host.System;
namespace Tgstation.Server.Host.Database.Design
{
@@ -11,31 +8,21 @@ namespace Tgstation.Server.Host.Database.Design
///
static class DesignTimeDbContextFactoryHelpers
{
- ///
- /// Path to the json file to use for migrations configuration
- ///
- const string RootJson = "appsettings.json";
-
- ///
- /// Path to the development json file to use for migrations configuration
- ///
- const string DevJson = "appsettings.Development.json";
-
///
/// Get the for the
///
+ /// The .
+ /// The .
/// The for the
- public static IOptions GetDbContextOptions()
+ public static IOptions GetDbContextOptions(DatabaseType databaseType, string connectionString)
{
- var builder = new ConfigurationBuilder();
- var assemblyInfoProvider = new AssemblyInformationProvider();
- var ioManager = new DefaultIOManager();
- builder.SetBasePath(ioManager.GetDirectoryName(assemblyInfoProvider.Path));
- builder.AddJsonFile(RootJson);
- builder.AddJsonFile(DevJson);
- var configuration = builder.Build();
- var dbConfig = configuration.GetSection(DatabaseConfiguration.Section).Get();
- dbConfig.DesignTime = true;
+ var dbConfig = new DatabaseConfiguration
+ {
+ DesignTime = true,
+ DatabaseType = databaseType,
+ ConnectionString = connectionString
+ };
+
return Options.Create(dbConfig);
}
}
diff --git a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs
index 4ac39129ac..6496f55009 100644
--- a/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs
+++ b/src/Tgstation.Server.Host/Database/Design/MySqlDesignTimeDbContextFactory.cs
@@ -2,6 +2,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Logging;
+using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
@@ -17,7 +18,9 @@ namespace Tgstation.Server.Host.Database.Design
using var loggerFactory = new LoggerFactory();
return new MySqlDatabaseContext(
new DbContextOptions(),
- DesignTimeDbContextFactoryHelpers.GetDbContextOptions(),
+ DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
+ DatabaseType.MariaDB,
+ "Server=127.0.0.1;User Id=root;Password=fake;Database=TGS_Design"),
new DatabaseSeeder(
new CryptographySuite(
new PasswordHasher()),
diff --git a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs
index dc56d54d4b..483fc08b2b 100644
--- a/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs
+++ b/src/Tgstation.Server.Host/Database/Design/SqlServerDesignTimeDbContextFactory.cs
@@ -2,6 +2,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Logging;
+using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
@@ -17,7 +18,9 @@ namespace Tgstation.Server.Host.Database.Design
using var loggerFactory = new LoggerFactory();
return new SqlServerDatabaseContext(
new DbContextOptions(),
- DesignTimeDbContextFactoryHelpers.GetDbContextOptions(),
+ DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
+ DatabaseType.SqlServer,
+ "Data Source=fake;Initial Catalog=TGS_Design;Integrated Security=True;Application Name=tgstation-server"),
new DatabaseSeeder(
new CryptographySuite(
new PasswordHasher()),
diff --git a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs
index 65789a71c6..09e506711f 100644
--- a/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs
+++ b/src/Tgstation.Server.Host/Database/Design/SqliteDesignTimeDbContextFactory.cs
@@ -2,6 +2,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Logging;
+using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
using Tgstation.Server.Host.System;
@@ -17,7 +18,9 @@ namespace Tgstation.Server.Host.Database.Design
using var loggerFactory = new LoggerFactory();
return new SqliteDatabaseContext(
new DbContextOptions(),
- DesignTimeDbContextFactoryHelpers.GetDbContextOptions(),
+ DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
+ DatabaseType.Sqlite,
+ "Data Source=tgs_design.sqlite3;Mode=ReadWriteCreate"),
new DatabaseSeeder(
new CryptographySuite(
new PasswordHasher()),
diff --git a/src/Tgstation.Server.Host/System/IProcessExecutor.cs b/src/Tgstation.Server.Host/System/IProcessExecutor.cs
index 3d9a001b9e..6b732915dd 100644
--- a/src/Tgstation.Server.Host/System/IProcessExecutor.cs
+++ b/src/Tgstation.Server.Host/System/IProcessExecutor.cs
@@ -23,5 +23,12 @@
/// The
/// The represented by on success, on failure
IProcess GetProcess(int id);
+
+ ///
+ /// Check if a with a given is running.
+ ///
+ /// The name of the process without the extension.
+ /// if the process is running, otherwise.
+ bool IsProcessWithNameRunning(string name);
}
}
diff --git a/src/Tgstation.Server.Host/System/Process.cs b/src/Tgstation.Server.Host/System/Process.cs
index 07b8d5fbe3..a722179341 100644
--- a/src/Tgstation.Server.Host/System/Process.cs
+++ b/src/Tgstation.Server.Host/System/Process.cs
@@ -117,7 +117,7 @@ namespace Tgstation.Server.Host.System
{
if (outputStringBuilder == null)
throw new InvalidOperationException("Output reading was not enabled!");
- return errorStringBuilder.ToString().TrimStart(Environment.NewLine.ToCharArray());
+ return outputStringBuilder.ToString().TrimStart(Environment.NewLine.ToCharArray());
}
///
diff --git a/src/Tgstation.Server.Host/System/ProcessExecutor.cs b/src/Tgstation.Server.Host/System/ProcessExecutor.cs
index 9e66aedf85..772c754131 100644
--- a/src/Tgstation.Server.Host/System/ProcessExecutor.cs
+++ b/src/Tgstation.Server.Host/System/ProcessExecutor.cs
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using System;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -102,9 +103,30 @@ namespace Tgstation.Server.Host.System
}
///
- public IProcess LaunchProcess(string fileName, string workingDirectory, string arguments, bool readOutput, bool readError, bool noShellExecute)
+ public IProcess LaunchProcess(
+ string fileName,
+ string workingDirectory,
+ string arguments,
+ bool readOutput,
+ bool readError,
+ bool noShellExecute)
{
- logger.LogDebug("Launching process in {0}: {1} {2}", workingDirectory, fileName, arguments);
+ if (fileName == null)
+ throw new ArgumentNullException(nameof(fileName));
+ if (workingDirectory == null)
+ throw new ArgumentNullException(nameof(workingDirectory));
+ if (arguments == null)
+ throw new ArgumentNullException(nameof(arguments));
+
+ if (!noShellExecute && (readOutput || readError))
+ throw new InvalidOperationException("Requesting output/error reading requires noShellExecute to be true!");
+
+ logger.LogDebug(
+ "{0}aunching process in {1}: {2} {3}",
+ noShellExecute ? "L" : "Shell l",
+ workingDirectory,
+ fileName,
+ arguments);
var handle = new global::System.Diagnostics.Process();
try
{
@@ -112,9 +134,12 @@ namespace Tgstation.Server.Host.System
handle.StartInfo.Arguments = arguments;
handle.StartInfo.WorkingDirectory = workingDirectory;
- handle.StartInfo.UseShellExecute = !(noShellExecute || readOutput || readError);
+ handle.StartInfo.UseShellExecute = !noShellExecute;
StringBuilder outputStringBuilder = null, errorStringBuilder = null, combinedStringBuilder = null;
+
+ TaskCompletionSource