diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index f92298da10d..5306221a60d 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -125,15 +125,22 @@ IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateD var setupWizardHostBuilder = CreateDefaultBuilder() .UseSetupApplication(assemblyInformationProvider, IOManager); - IPostSetupServices postSetupServices; + IPostSetupServices postSetupServices; using (var setupHost = setupWizardHostBuilder.Build()) { - postSetupServices = setupHost.Services.GetRequiredService>(); + ILogger logger = setupHost.Services.GetRequiredService>(); + postSetupServices = setupHost.Services.GetRequiredService(); await setupHost.RunAsync(cancellationToken); if (postSetupServices.GeneralConfiguration.SetupWizardMode == SetupWizardMode.Only) { - postSetupServices.Logger.LogInformation("Shutting down due to only running setup wizard."); + logger.LogInformation("Shutting down due to only running setup wizard."); + return null; + } + + if (postSetupServices.ReloadRequired) + { + logger.LogInformation("TGS must restart to reload the updated configuration."); return null; } } diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs index 21264d9277e..7f3dba95654 100644 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices.cs @@ -42,5 +42,10 @@ public interface IPostSetupServices /// The . /// IPlatformIdentifier PlatformIdentifier { get; } + + /// + /// If an application reload to get updated configuration values is required. + /// + bool ReloadRequired { get; set; } } } diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs deleted file mode 100644 index f36d9526e78..00000000000 --- a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Logging; - -namespace Tgstation.Server.Host.Setup -{ - /// - /// with a . - /// - /// The category for . - interface IPostSetupServices : IPostSetupServices - { - /// - /// The . - /// - ILogger Logger { get; } - } -} diff --git a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs index c1ace340ec5..9180c22c7a9 100644 --- a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs @@ -1,6 +1,5 @@ using System; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Tgstation.Server.Host.Configuration; @@ -9,14 +8,11 @@ namespace Tgstation.Server.Host.Setup { /// - sealed class PostSetupServices : IPostSetupServices + sealed class PostSetupServices : IPostSetupServices { /// public IPlatformIdentifier PlatformIdentifier { get; } - /// - public ILogger Logger { get; } - /// public GeneralConfiguration GeneralConfiguration => generalConfigurationOptions.Value; @@ -35,6 +31,9 @@ sealed class PostSetupServices : IPostSetupServices /// public ElasticsearchConfiguration ElasticsearchConfiguration => elasticsearchConfigurationOptions.Value; + /// + public bool ReloadRequired { get; set; } + /// /// Backing for . /// @@ -66,10 +65,9 @@ sealed class PostSetupServices : IPostSetupServices readonly IOptions internalConfigurationOptions; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The value of . - /// The used to create . /// The containing the value of . /// The containing the value of . /// The containing the value of . @@ -78,7 +76,6 @@ sealed class PostSetupServices : IPostSetupServices /// The containing the value of . public PostSetupServices( IPlatformIdentifier platformIdentifier, - ILoggerFactory loggerFactory, IOptions generalConfigurationOptions, IOptions databaseConfigurationOptions, IOptions securityConfigurationOptions, @@ -87,9 +84,6 @@ public PostSetupServices( IOptions internalConfigurationOptions) { PlatformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); - ArgumentNullException.ThrowIfNull(loggerFactory); - - Logger = loggerFactory.CreateLogger(); this.generalConfigurationOptions = generalConfigurationOptions ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); this.databaseConfigurationOptions = databaseConfigurationOptions ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions)); this.securityConfigurationOptions = securityConfigurationOptions ?? throw new ArgumentNullException(nameof(securityConfigurationOptions)); diff --git a/src/Tgstation.Server.Host/Setup/SetupApplication.cs b/src/Tgstation.Server.Host/Setup/SetupApplication.cs index 56c590ce7d0..744aabd8c0a 100644 --- a/src/Tgstation.Server.Host/Setup/SetupApplication.cs +++ b/src/Tgstation.Server.Host/Setup/SetupApplication.cs @@ -72,7 +72,7 @@ public void ConfigureServices(IServiceCollection services, IAssemblyInformationP /// The to configure. protected virtual void ConfigureHostedService(IServiceCollection services) { - services.AddSingleton(typeof(IPostSetupServices<>), typeof(PostSetupServices<>)); + services.AddSingleton(); services.AddSingleton(); } } diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 04cc54a3bfd..36d0bf31116 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -76,6 +76,11 @@ sealed class SetupWizard : BackgroundService /// readonly IHostApplicationLifetime applicationLifetime; + /// + /// The for the . + /// + readonly IPostSetupServices postSetupServices; + /// /// The for the . /// @@ -97,6 +102,7 @@ sealed class SetupWizard : BackgroundService /// The value of . /// The value of . /// The value of . + /// The value of . /// The containing the value of . /// The containing the value of . public SetupWizard( @@ -108,6 +114,7 @@ public SetupWizard( IPlatformIdentifier platformIdentifier, IAsyncDelayer asyncDelayer, IHostApplicationLifetime applicationLifetime, + IPostSetupServices postSetupServices, IOptions generalConfigurationOptions, IOptions internalConfigurationOptions) { @@ -119,6 +126,7 @@ public SetupWizard( this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.applicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime)); + this.postSetupServices = postSetupServices ?? throw new ArgumentNullException(nameof(postSetupServices)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); internalConfiguration = internalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(internalConfigurationOptions)); @@ -1014,6 +1022,8 @@ await ioManager.WriteAllBytes( userConfigFileName, configBytes, cancellationToken); + + postSetupServices.ReloadRequired = true; } catch (Exception e) when (e is not OperationCanceledException) { diff --git a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs index 823036a10b3..1aa35762774 100644 --- a/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs +++ b/tests/Tgstation.Server.Host.Tests/Setup/TestSetupWizard.cs @@ -27,25 +27,27 @@ public sealed class TestSetupWizard [TestMethod] public void TestConstructionThrows() { - Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(null, null, null, null, null, null, null, null, null, null, null)); var mockIOManager = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, null, null, null, null, null, null, null, null, null, null)); var mockConsole = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, null, null, null, null, null, null, null, null, null)); var mockHostingEnvironment = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, null, null, null, null, null, null, null, null)); var mockAssemblyInfoProvider = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, null, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, null, null, null, null, null, null, null)); var mockDBConnectionFactory = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, null, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, null, null, null, null, null, null)); var mockPlatformIdentifier = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, null, null, null, null, null)); var mockAsyncDelayer = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, null, null, null, null)); var mockLifetime = new Mock(); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, null, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, null, null, null)); + var mockServices = new Mock(); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockServices.Object, null, null)); var mockGeneralConfigurationOptions = Options.Create(new GeneralConfiguration()); - Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockGeneralConfigurationOptions, null)); + Assert.ThrowsException(() => new SetupWizard(mockIOManager.Object, mockConsole.Object, mockHostingEnvironment.Object, mockAssemblyInfoProvider.Object, mockDBConnectionFactory.Object, mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, mockServices.Object, mockGeneralConfigurationOptions, null)); } [TestMethod] @@ -61,6 +63,7 @@ public async Task TestWithUserStupidity() var mockInternalConfigurationOptions = new Mock>(); var mockPlatformIdentifier = new Mock(); var mockAsyncDelayer = new Mock(); + var mockServices = new Mock(); var testGeneralConfig = new GeneralConfiguration { @@ -83,6 +86,7 @@ public async Task TestWithUserStupidity() mockPlatformIdentifier.Object, mockAsyncDelayer.Object, mockLifetime.Object, + mockServices.Object, mockGeneralConfigurationOptions.Object, mockInternalConfigurationOptions.Object); diff --git a/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs b/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs index c8c83fc5942..9a96a8332ff 100644 --- a/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs +++ b/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs @@ -15,8 +15,10 @@ namespace Tgstation.Server.Host.Tests [TestClass] public sealed class TestServerFactory { + static readonly string[] cliArgs = ["General:SetupWizardMode=Never"]; + [TestMethod] - public void TestContructor() + public void TestConstructor() { Assert.ThrowsException(() => new ServerFactory(null, null)); IAssemblyInformationProvider assemblyInformationProvider = Mock.Of(); @@ -31,7 +33,7 @@ public async Task TestWorksWithoutUpdatePath() var factory = Application.CreateDefaultServerFactory(); await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, null, default).AsTask()); - var result = await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, null, default); + var result = await factory.CreateServer(cliArgs, null, default); Assert.IsNotNull(result); } @@ -43,7 +45,7 @@ public async Task TestWorksWithUpdatePath() await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, null, default).AsTask()); await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, Path, default).AsTask()); - var result = await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, Path, default); + var result = await factory.CreateServer(cliArgs, Path, default); Assert.IsNotNull(result); } }