diff --git a/src/Tgstation.Server.Api/Models/Internal/CompileJob.cs b/src/Tgstation.Server.Api/Models/Internal/CompileJob.cs
index 97d9aaaf5c..7e33d1178c 100644
--- a/src/Tgstation.Server.Api/Models/Internal/CompileJob.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/CompileJob.cs
@@ -35,6 +35,6 @@ namespace Tgstation.Server.Api.Models.Internal
///
/// The DMAPI .
///
- public Version DMApiVersion { get; set;
+ public Version DMApiVersion { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
index 6156844e19..37cfe70a11 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
@@ -216,6 +216,8 @@ namespace Tgstation.Server.Host.Components.Deployment
default:
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Session controller returned unexpected ApiValidationStatus: {0}", validationStatus));
}
+
+ job.DMApiVersion = controller.DMApiVersion;
}
throw new JobException("DMAPI validation timed out!");
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index ed3ceffea5..78366142ee 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -112,6 +112,11 @@ namespace Tgstation.Server.Host.Components
///
readonly IRepositoryFactory repositoryFactory;
+ ///
+ /// The for the .
+ ///
+ readonly IServerPortProvider serverPortProvider;
+
///
/// Construct an
///
@@ -133,6 +138,7 @@ namespace Tgstation.Server.Host.Components
/// The value of
/// The value of
/// The value of .
+ /// The value of .
public InstanceFactory(
IIOManager ioManager,
IDatabaseContextFactory databaseContextFactory,
@@ -151,7 +157,8 @@ namespace Tgstation.Server.Host.Components
INetworkPromptReaper networkPromptReaper,
IGitHubClientFactory gitHubClientFactory,
IPlatformIdentifier platformIdentifier,
- IRepositoryFactory repositoryFactory)
+ IRepositoryFactory repositoryFactory,
+ IServerPortProvider serverPortProvider)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
@@ -171,6 +178,7 @@ namespace Tgstation.Server.Host.Components
this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory));
this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
this.repositoryFactory = repositoryFactory ?? throw new ArgumentNullException(nameof(repositoryFactory));
+ this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider));
}
///
@@ -215,6 +223,7 @@ namespace Tgstation.Server.Host.Components
networkPromptReaper,
platformIdentifier,
bridgeRegistrar,
+ serverPortProvider,
loggerFactory,
metadata.CloneMetadata());
diff --git a/src/Tgstation.Server.Host/Components/Interop/Runtime/RuntimeInformation.cs b/src/Tgstation.Server.Host/Components/Interop/Runtime/RuntimeInformation.cs
index d5be4fddac..8b44d0f157 100644
--- a/src/Tgstation.Server.Host/Components/Interop/Runtime/RuntimeInformation.cs
+++ b/src/Tgstation.Server.Host/Components/Interop/Runtime/RuntimeInformation.cs
@@ -63,16 +63,17 @@ namespace Tgstation.Server.Host.Components.Interop.Runtime
/// The value of .
/// The value of .
/// The value of .
+ /// The value of .
public RuntimeInformation(
IApplication application,
ICryptographySuite cryptographySuite,
- IServerPortProvider portProvider,
IEnumerable testMerges,
Api.Models.Instance instance,
Api.Models.Internal.RevisionInformation revision,
string channelsJson,
string commandsJson,
- DreamDaemonSecurity securityLevel)
+ DreamDaemonSecurity securityLevel,
+ ushort serverPort)
{
ServerVersion = application?.Version ?? throw new ArgumentNullException(nameof(application));
AccessIdentifier = cryptographySuite?.GetSecureString() ?? throw new ArgumentNullException(nameof(cryptographySuite));
@@ -82,6 +83,7 @@ namespace Tgstation.Server.Host.Components.Interop.Runtime
ChatChannelsJson = channelsJson ?? throw new ArgumentNullException(nameof(channelsJson));
ChatChannelsJson = commandsJson ?? throw new ArgumentNullException(nameof(commandsJson));
SecurityLevel = securityLevel;
+ ServerPort = serverPort;
}
}
}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
index cbd5dc65f4..3d5e444d34 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
@@ -1,7 +1,6 @@
using Byond.TopicSender;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using System;
using System.Globalization;
using System.Linq;
@@ -76,6 +75,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
readonly IBridgeRegistrar bridgeRegistrar;
+ ///
+ /// The for the .
+ ///
+ readonly IServerPortProvider serverPortProvider;
+
///
/// The for the
///
@@ -120,6 +124,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The value of
/// The value of
/// The value of .
+ /// The value of .
/// The value of
public SessionControllerFactory(
IProcessExecutor processExecutor,
@@ -132,6 +137,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
INetworkPromptReaper networkPromptReaper,
IPlatformIdentifier platformIdentifier,
IBridgeRegistrar bridgeRegistrar,
+ IServerPortProvider serverPortProvider,
ILoggerFactory loggerFactory,
Api.Models.Instance instance)
{
@@ -146,6 +152,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
this.networkPromptReaper = networkPromptReaper ?? throw new ArgumentNullException(nameof(networkPromptReaper));
this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
this.bridgeRegistrar = bridgeRegistrar ?? throw new ArgumentNullException(nameof(bridgeRegistrar));
+ this.serverPortProvider = serverPortProvider ?? throw new ArgumentNullException(nameof(serverPortProvider));
this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
@@ -212,7 +219,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
revisionInfo,
JsonFile("chat_channels"),
JsonFile("chat_commands"),
- securityLevelToUse);
+ securityLevelToUse,
+ await serverPortProvider.HttpApiPort.ConfigureAwait(false));
var interopJsonFile = JsonFile("interop");
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index 55021ccf9f..cc11929724 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
@@ -340,6 +341,7 @@ namespace Tgstation.Server.Host.Core
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton(new ByondTopicSender
{
ReceiveTimeout = generalConfiguration.ByondTopicTimeout,
@@ -373,6 +375,7 @@ namespace Tgstation.Server.Host.Core
IApplicationBuilder applicationBuilder,
IServerControl serverControl,
ITokenFactory tokenFactory,
+ IServerPortProvider serverPortProvider,
IOptions controlPanelConfigurationOptions,
IOptions generalConfigurationOptions,
ILogger logger)
@@ -384,6 +387,12 @@ namespace Tgstation.Server.Host.Core
this.tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory));
+ if (serverPortProvider == null)
+ throw new ArgumentNullException(nameof(serverPortProvider));
+
+ var addressFeature = applicationBuilder?.ServerFeatures.Get();
+ serverPortProvider.Configure(addressFeature);
+
var controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions));
var generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
diff --git a/src/Tgstation.Server.Host/Core/IServerPortProvider.cs b/src/Tgstation.Server.Host/Core/IServerPortProvider.cs
new file mode 100644
index 0000000000..c1f98d4ab8
--- /dev/null
+++ b/src/Tgstation.Server.Host/Core/IServerPortProvider.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using System.Threading.Tasks;
+
+namespace Tgstation.Server.Host.Core
+{
+ ///
+ /// Provides access to the server's .
+ ///
+ interface IServerPortProvider
+ {
+ ///
+ /// A resulting in the port the server listens on.
+ ///
+ Task HttpApiPort { get; }
+
+ ///
+ /// Configures the .
+ ///
+ /// The to use.
+ void Configure(IServerAddressesFeature addressFeature);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Core/ServerPortProivder.cs b/src/Tgstation.Server.Host/Core/ServerPortProivder.cs
new file mode 100644
index 0000000000..cbc90ebc03
--- /dev/null
+++ b/src/Tgstation.Server.Host/Core/ServerPortProivder.cs
@@ -0,0 +1,65 @@
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Tgstation.Server.Host.Core
+{
+ ///
+ sealed class ServerPortProivder : IServerPortProvider
+ {
+ ///
+ public Task HttpApiPort => taskCompletionSource.Task;
+
+ ///
+ /// Backing field for /
+ ///
+ readonly TaskCompletionSource taskCompletionSource;
+
+ ///
+ /// In
+ ///
+ public ServerPortProivder()
+ {
+ taskCompletionSource = new TaskCompletionSource();
+ }
+
+ ///
+ public void Configure(IServerAddressesFeature addressFeature)
+ {
+ if (addressFeature == null)
+ throw new ArgumentNullException(nameof(addressFeature));
+
+ var enumerator = addressFeature.Addresses.Select(GetPortFromAddress);
+ var newPort = enumerator.FirstOrDefault(x => x.HasValue);
+
+ if(!newPort.HasValue)
+ throw new InvalidOperationException("At least one plain HTTP endpoint must be configured. Neded for BYOND -> Server communications!");
+
+ if (!addressFeature.Addresses.Select(GetPortFromAddress).All(x => !x.HasValue || x == newPort))
+ throw new InvalidOperationException("All configured HTTP server addresses must use the same port!");
+
+ // Will fail if set twice
+ taskCompletionSource.SetResult(newPort.Value);
+ }
+
+ ///
+ /// Convert a given to its port.
+ ///
+ /// The address .
+ /// The parsed port.
+ static ushort? GetPortFromAddress(string address)
+ {
+ var splits = address.Split(":", StringSplitOptions.RemoveEmptyEntries);
+ if (splits.First().Equals("https", StringComparison.OrdinalIgnoreCase))
+ return null;
+
+ var portString = splits.Last();
+ portString = portString.TrimEnd('/');
+ if (UInt16.TryParse(portString, out var result))
+ return result;
+
+ return null;
+ }
+ }
+}