diff --git a/src/DMAPI/tgs/v4/api.dm b/src/DMAPI/tgs/v4/api.dm
index cde747ba1f..1736130b67 100644
--- a/src/DMAPI/tgs/v4/api.dm
+++ b/src/DMAPI/tgs/v4/api.dm
@@ -10,8 +10,7 @@
#define TGS4_TOPIC_EVENT "tgs_event"
#define TGS4_TOPIC_INTEROP_RESPONSE "tgs_interop"
-#define TGS4_COMM_ONLINE "tgs_on"
-#define TGS4_COMM_IDENTIFY "tgs_ident"
+#define TGS4_COMM_NEW_PORT "tgs_new_port"
#define TGS4_COMM_VALIDATE "tgs_validate"
#define TGS4_COMM_SERVER_PRIMED "tgs_prime"
#define TGS4_COMM_WORLD_REBOOT "tgs_reboot"
@@ -21,8 +20,7 @@
#define TGS4_PARAMETER_COMMAND "tgs_com"
#define TGS4_PARAMETER_DATA "tgs_data"
-#define TGS4_PARAMETER_NEW_PORT "new_port"
-#define TGS4_PARAMETER_NEW_REBOOT_MODE "new_rmode"
+#define TGS4_PORT_CRITFAIL_MESSAGE " Must exit to let watchdog reboot..."
#define EXPORT_TIMEOUT_DS 200
@@ -111,6 +109,7 @@
/datum/tgs_api/v4/OnInitializationComplete()
Export(TGS4_COMM_SERVER_PRIMED)
+
var/tgs4_secret_sleep_offline_sauce = 24051994
var/old_sleep_offline = world.sleep_offline
world.sleep_offline = tgs4_secret_sleep_offline_sauce
@@ -156,7 +155,22 @@
if(TGS4_TOPIC_INTEROP_RESPONSE)
last_interop_response = json_decode(params[TGS4_PARAMETER_DATA])
return
-
+ if(TGS4_TOPIC_CHANGE_PORT)
+ var/new_port = text2num(params[TGS4_PARAMETER_DATA])
+ if (!(new_port > 0))
+ return "Invalid port: [new_port]"
+
+ //the topic still completes, miraculously
+ //I honestly didn't believe byond could do it
+ event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port)
+ if(!world.OpenPort(new_port))
+ return "Port change failed!"
+ if(TGS4_TOPIC_CHANGE_REBOOT_MODE)
+ var/new_reboot_mode = text2num(params[TGS4_PARAMETER_DATA])
+ event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode)
+ reboot_mode = new_reboot_mode
+ return
+
return "Unknown command: [command]"
/datum/tgs_api/v4/proc/Export(command, list/data)
@@ -164,6 +178,29 @@
data = list()
data[TGS4_PARAMETER_COMMAND] = command
var/json = json_encode(data)
+
+ //we need some port open at this point to facilitate return communication
+ if(!world.port)
+ if(!world.OpenPort(0)) //open any port
+ TGS_ERROR_LOG("Unable to open random port to retrieve new port![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+
+ //request a new port
+ export_lock = FALSE
+ var/list/new_port_json = Export(TGS4_COMM_NEW_PORT, list("current_port" = "[world.port]")) //stringify this on purpose
+
+ if(!new_port_json)
+ TGS_ERROR_LOG("No new port response from server![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+
+ var/new_port = new_port_json["port"]
+ if(!isnum(new_port) || new_port <= 0)
+ TGS_ERROR_LOG("Malformed new port json ([json_encode(new_port_json)])![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
+
+ if(new_port != world.port && !world.OpenPort(new_port))
+ TGS_ERROR_LOG("Unable to open port [new_port]![TGS4_PORT_CRITFAIL_MESSAGE]")
+ del(world)
while(export_lock)
sleep(1)
@@ -189,7 +226,18 @@
if(!result)
return
- //TODO: Port handling
+ //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter
+
+ var/port = json[TGS4_PARAMETER_DATA]
+ if(!isnum(port))
+ return //this is valid, server may just want use to reboot
+
+ if(port == 0)
+ //to byond 0 means any port and "none" means close vOv
+ port = "none"
+
+ if(!world.OpenPort(port))
+ TGS_ERROR_LOG("Unable to set port to [port]!")
/datum/tgs_api/v4/InstanceName()
return instance_name
diff --git a/src/Tgstation.Server.Host/Components/Compiler/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Compiler/DmbFactory.cs
index 2092ed275c..045e495fa0 100644
--- a/src/Tgstation.Server.Host/Components/Compiler/DmbFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Compiler/DmbFactory.cs
@@ -212,9 +212,15 @@ namespace Tgstation.Server.Host.Components.Compiler
lock (this)
{
if (!jobLockCounts.TryGetValue(compileJob.Id, out int value))
+ {
+ value = 1;
jobLockCounts.Add(compileJob.Id, 1);
+ }
else
jobLockCounts[compileJob.Id] = ++value;
+
+ logger.LogTrace("Compile job {0} lock count now: {1}", compileJob.Id, value);
+
providerSubmitted = true;
return newProvider;
}
diff --git a/src/Tgstation.Server.Host/Components/Interop/Constants.cs b/src/Tgstation.Server.Host/Components/Interop/Constants.cs
index 00b516bd94..55b7ff5b73 100644
--- a/src/Tgstation.Server.Host/Components/Interop/Constants.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/Constants.cs
@@ -18,8 +18,7 @@
public const string DMTopicEvent = "tgs_event";
public const string DMTopicInteropResponse = "tgs_interop";
- public const string DMCommandOnline = "tgs_on";
- public const string DMCommandIdentify = "tgs_ident";
+ public const string DMCommandNewPort = "tgs_new_port";
public const string DMCommandApiValidate = "tgs_validate";
public const string DMCommandServerPrimed = "tgs_prime";
public const string DMCommandWorldReboot = "tgs_reboot";
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs
index 6a703f5fc9..3f2e245eba 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs
@@ -19,6 +19,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
bool IsPrimary { get; }
+ ///
+ /// If the DreamDaemon instance sent a
+ ///
+ bool TerminationWasRequested { get; }
+
///
/// If the DMAPI was validated. This field may only be access once completes
///
@@ -34,16 +39,16 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
ushort? Port { get; }
+ ///
+ /// If the port should be rotated off when the world reboots
+ ///
+ bool ClosePortOnReboot { get; set; }
+
///
/// The current
///
RebootState RebootState { get; }
- ///
- /// If the port should close when /world/Reboot() is called. Defaults to
- ///
- bool ClosePortOnReboot { get; set; }
-
///
/// A that completes when the server calls /world/Reboot()
///
@@ -63,13 +68,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// A resulting in the result of /world/Topic()
Task SendCommand(string command, CancellationToken cancellationToken);
- ///
- /// Closes the world's port
- ///
- /// The for the operation
- /// A resulting in if the operation succeeded, otherwise
- Task ClosePort(CancellationToken cancellationToken);
-
///
/// Causes the world to start listening on a
///
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
index 6a6448678b..e38b92b9bb 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
@@ -28,9 +28,6 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
}
- ///
- public bool ClosePortOnReboot { get; set; }
-
///
public bool ApiValidated
{
@@ -58,7 +55,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
get
{
CheckDisposed();
- if (portClosed)
+ if (portClosedForReboot)
return null;
return reattachInformation.Port;
}
@@ -74,6 +71,12 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
}
+ ///
+ public bool ClosePortOnReboot { get; set; }
+
+ ///
+ public bool TerminationWasRequested { get; private set; }
+
///
public Task LaunchResult { get; }
@@ -124,13 +127,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
readonly ILogger logger;
///
- /// The waits on when DreamDaemon currently has it's ports closed
+ /// The waits on when DreamDaemon currently has it's ports closed
///
TaskCompletionSource portAssignmentTcs;
///
/// The port to assign DreamDaemon when it queries for it
///
- ushort nextPort;
+ ushort? nextPort;
///
/// The that completes when DD tells us about a reboot
@@ -140,7 +143,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
/// If we know DreamDaemon currently has it's port closed
///
- bool portClosed;
+ bool portClosedForReboot;
+
///
/// If the has been disposed
///
@@ -181,7 +185,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
interopContext.RegisterHandler(this);
- portClosed = false;
+ portClosedForReboot = false;
disposed = false;
apiValidated = false;
released = false;
@@ -265,6 +269,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
var query = command.Parameters;
object content;
+ Action postRespond = null;
if (query.TryGetValue(Constants.DMParameterCommand, out var method))
{
content = new object();
@@ -273,20 +278,39 @@ namespace Tgstation.Server.Host.Components.Watchdog
case Constants.DMCommandServerPrimed:
//currently unused, maybe in the future
break;
- case Constants.DMCommandIdentify:
+ case Constants.DMCommandEndProcess:
+ TerminationWasRequested = true;
+ process.Terminate();
+ return;
+ case Constants.DMCommandNewPort:
lock (this)
- if (portClosed)
- content = new Dictionary { { Constants.DMParameterData, nextPort } };
- break;
- case Constants.DMCommandOnline:
- lock (this)
- if (portClosed)
- {
- reattachInformation.Port = nextPort;
- portAssignmentTcs.TrySetResult(true);
- portAssignmentTcs = null;
- portClosed = false;
+ {
+ if (!query.TryGetValue(Constants.DMParameterData, out var stringPort) || !UInt16.TryParse(stringPort, out var currentPort)) {
+ /////UHHHH
+ logger.LogWarning("DreamDaemon sent new port command without providing it's own!");
+ break;
}
+
+ if (!nextPort.HasValue)
+ //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
+ reattachInformation.Port = currentPort;
+ else
+ {
+ //nextPort is ready, tell DD to switch to that
+ //if it fails it'll kill itself
+ content = new Dictionary { { Constants.DMParameterData, nextPort.Value } };
+ reattachInformation.Port = nextPort.Value;
+ nextPort = null;
+
+ //we'll also get here from SetPort so complete that task
+ var tmpTcs = portAssignmentTcs;
+ portAssignmentTcs = null;
+ if (tmpTcs != null)
+ postRespond = () => tmpTcs.SetResult(true);
+ }
+
+ portClosedForReboot = false;
+ }
break;
case Constants.DMCommandApiValidate:
apiValidated = true;
@@ -295,13 +319,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
if (ClosePortOnReboot)
{
content = new Dictionary { { Constants.DMParameterData, 0 } };
- portClosed = true;
+ portClosedForReboot = true;
}
- else
- ClosePortOnReboot = true;
var oldTcs = rebootTcs;
rebootTcs = new TaskCompletionSource