Finish IServerPortProvider stuff

This commit is contained in:
Jordan Brown
2020-04-21 11:04:20 -04:00
parent beed88f8d0
commit 618ad7bb38
8 changed files with 123 additions and 6 deletions
@@ -35,6 +35,6 @@ namespace Tgstation.Server.Api.Models.Internal
/// <summary>
/// The DMAPI <see cref="Version"/>.
/// </summary>
public Version DMApiVersion { get; set;
public Version DMApiVersion { get; set; }
}
}
@@ -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!");
@@ -112,6 +112,11 @@ namespace Tgstation.Server.Host.Components
/// </summary>
readonly IRepositoryFactory repositoryFactory;
/// <summary>
/// The <see cref="IServerPortProvider"/> for the <see cref="InstanceFactory"/>.
/// </summary>
readonly IServerPortProvider serverPortProvider;
/// <summary>
/// Construct an <see cref="InstanceFactory"/>
/// </summary>
@@ -133,6 +138,7 @@ namespace Tgstation.Server.Host.Components
/// <param name="gitHubClientFactory">The value of <see cref="gitHubClientFactory"/></param>
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/></param>
/// <param name="repositoryFactory">The value of <see cref="repositoryFactory"/>.</param>
/// <param name="serverPortProvider">The value of <see cref="serverPortProvider"/>.</param>
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));
}
/// <inheritdoc />
@@ -215,6 +223,7 @@ namespace Tgstation.Server.Host.Components
networkPromptReaper,
platformIdentifier,
bridgeRegistrar,
serverPortProvider,
loggerFactory,
metadata.CloneMetadata());
@@ -63,16 +63,17 @@ namespace Tgstation.Server.Host.Components.Interop.Runtime
/// <param name="channelsJson">The value of <see cref="RuntimeFileList.ChatChannelsJson"/>.</param>
/// <param name="commandsJson">The value of <see cref="RuntimeFileList.ChatCommandsJson"/>.</param>
/// <param name="securityLevel">The value of <see cref="SecurityLevel"/>.</param>
/// <param name="serverPort">The value of <see cref="ServerPort"/>.</param>
public RuntimeInformation(
IApplication application,
ICryptographySuite cryptographySuite,
IServerPortProvider portProvider,
IEnumerable<RuntimeTestMerge> 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;
}
}
}
@@ -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
/// </summary>
readonly IBridgeRegistrar bridgeRegistrar;
/// <summary>
/// The <see cref="IServerPortProvider"/> for the <see cref="SessionControllerFactory"/>.
/// </summary>
readonly IServerPortProvider serverPortProvider;
/// <summary>
/// The <see cref="ILoggerFactory"/> for the <see cref="SessionControllerFactory"/>
/// </summary>
@@ -120,6 +124,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="networkPromptReaper">The value of <see cref="networkPromptReaper"/></param>
/// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/></param>
/// <param name="bridgeRegistrar">The value of <see cref="bridgeRegistrar"/>.</param>
/// <param name="serverPortProvider">The value of <see cref="serverPortProvider"/>.</param>
/// <param name="loggerFactory">The value of <see cref="loggerFactory"/></param>
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");
@@ -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<ISynchronousIOManager, SynchronousIOManager>();
services.AddSingleton<IGitHubClientFactory, GitHubClientFactory>();
services.AddSingleton<IProcessExecutor, ProcessExecutor>();
services.AddSingleton<IServerPortProvider, ServerPortProivder>();
services.AddSingleton<IByondTopicSender>(new ByondTopicSender
{
ReceiveTimeout = generalConfiguration.ByondTopicTimeout,
@@ -373,6 +375,7 @@ namespace Tgstation.Server.Host.Core
IApplicationBuilder applicationBuilder,
IServerControl serverControl,
ITokenFactory tokenFactory,
IServerPortProvider serverPortProvider,
IOptions<ControlPanelConfiguration> controlPanelConfigurationOptions,
IOptions<GeneralConfiguration> generalConfigurationOptions,
ILogger<Application> 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<IServerAddressesFeature>();
serverPortProvider.Configure(addressFeature);
var controlPanelConfiguration = controlPanelConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(controlPanelConfigurationOptions));
var generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Hosting.Server.Features;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Core
{
/// <summary>
/// Provides access to the server's <see cref="HttpApiPort"/>.
/// </summary>
interface IServerPortProvider
{
/// <summary>
/// A <see cref="Task{TResult}"/> resulting in the port the server listens on.
/// </summary>
Task<ushort> HttpApiPort { get; }
/// <summary>
/// Configures the <see cref="ServerPortProivder"/>.
/// </summary>
/// <param name="addressFeature">The <see cref="IServerAddressesFeature"/> to use.</param>
void Configure(IServerAddressesFeature addressFeature);
}
}
@@ -0,0 +1,65 @@
using Microsoft.AspNetCore.Hosting.Server.Features;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Tgstation.Server.Host.Core
{
/// <inheritdoc />
sealed class ServerPortProivder : IServerPortProvider
{
/// <inheritdoc />
public Task<ushort> HttpApiPort => taskCompletionSource.Task;
/// <summary>
/// Backing <see cref="TaskCompletionSource{TResult}"/> field for <see cref="HttpApiPort"/>/
/// </summary>
readonly TaskCompletionSource<ushort> taskCompletionSource;
/// <summary>
/// In
/// </summary>
public ServerPortProivder()
{
taskCompletionSource = new TaskCompletionSource<ushort>();
}
/// <inheritdoc />
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);
}
/// <summary>
/// Convert a given <paramref name="address"/> to its port.
/// </summary>
/// <param name="address">The address <see cref="string"/>.</param>
/// <returns>The parsed port.</returns>
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;
}
}
}