diff --git a/build/Version.props b/build/Version.props index 79bcb4fb8f..e6845264db 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ 4.5.4 - 2.1.0 + 2.1.1 7.4.0 8.4.0 5.2.7 diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 02e413701a..911f95dc23 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -239,6 +239,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers protected override async Task Connect(CancellationToken cancellationToken) { disconnecting = false; + cancellationToken.ThrowIfCancellationRequested(); try { client.Connect(address, port); diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs index 4ece931574..9f3100ffa3 100644 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs +++ b/src/Tgstation.Server.Host/Components/Interop/DMApiConstants.cs @@ -1,8 +1,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; -using System.Reflection; using Tgstation.Server.Host.Components.Interop.Converters; +using Tgstation.Server.Host.Properties; namespace Tgstation.Server.Host.Components.Interop { @@ -34,11 +34,7 @@ namespace Tgstation.Server.Host.Components.Interop /// /// The DMAPI being used. /// - public static readonly Version Version = Version.Parse( - Assembly - .GetExecutingAssembly() - .GetCustomAttribute() - .RawDMApiVersion); + public static readonly Version Version = Version.Parse(MasterVersionsAttribute.Instance.RawDMApiVersion); /// /// for use when communicating with the DMAPI. diff --git a/src/Tgstation.Server.Host/Components/Interop/DMApiVersionAtrribute.cs b/src/Tgstation.Server.Host/Components/Interop/DMApiVersionAtrribute.cs deleted file mode 100644 index be4a05a0c3..0000000000 --- a/src/Tgstation.Server.Host/Components/Interop/DMApiVersionAtrribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Tgstation.Server.Host.Components.Interop -{ - /// - /// Attribute for bringing in the from MSBuild. - /// - [AttributeUsage(AttributeTargets.Assembly)] - sealed class DMApiVersionAtrribute : Attribute - { - /// - /// The string of the DMAPI version built. - /// - public string RawDMApiVersion { get; } - - /// - /// Initializes a new instance of the . - /// - /// The value of . - public DMApiVersionAtrribute(string rawDMApiVersion) - { - RawDMApiVersion = rawDMApiVersion ?? throw new ArgumentNullException(nameof(rawDMApiVersion)); - } - } -} diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 4b925e9342..e58c8d036e 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -3,6 +3,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Properties; +using Tgstation.Server.Host.Setup; namespace Tgstation.Server.Host.Configuration { @@ -24,7 +26,7 @@ namespace Tgstation.Server.Host.Configuration /// /// The current . /// - public static readonly Version CurrentConfigVersion = new Version(2, 1, 0); + public static readonly Version CurrentConfigVersion = Version.Parse(MasterVersionsAttribute.Instance.RawConfigurationVersion); /// /// The default value for . @@ -90,7 +92,7 @@ namespace Tgstation.Server.Host.Configuration /// /// If the swagger UI should be made avaiable. /// - public bool HostApiDocumemtation { get; set; } + public bool HostApiDocumentation { get; set; } /// /// Initializes a new instance of the . diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index b1dc85fcee..8656493f63 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -35,6 +35,7 @@ using Tgstation.Server.Host.Database; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; +using Tgstation.Server.Host.Properties; using Tgstation.Server.Host.Security; using Tgstation.Server.Host.Setup; using Tgstation.Server.Host.System; @@ -195,7 +196,7 @@ namespace Tgstation.Server.Host.Core options.SerializerSettings.Converters = new[] { new VersionConverter() }; }); - if (hostingEnvironment.IsDevelopment()) + if (postSetupServices.GeneralConfiguration.HostApiDocumentation) { static string GetDocumentationFilePath(string assemblyLocation) => IOManager.ConcatPath(IOManager.GetDirectoryName(assemblyLocation), String.Concat(IOManager.GetFileNameWithoutExtension(assemblyLocation), ".xml")); var assemblyDocumentationPath = GetDocumentationFilePath(typeof(Application).Assembly.Location); @@ -396,8 +397,7 @@ namespace Tgstation.Server.Host.Core // suppress OperationCancelledExceptions, they are just aborted HTTP requests applicationBuilder.UseCancelledRequestSuppression(); - if (hostingEnvironment.IsDevelopment() - || generalConfiguration.HostApiDocumemtation) + if (generalConfiguration.HostApiDocumentation) { applicationBuilder.UseSwagger(); applicationBuilder.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TGS API V4")); @@ -434,8 +434,6 @@ namespace Tgstation.Server.Host.Core else logger.LogDebug("Web control panel disabled!"); - logger.LogDebug("Starting hosting..."); - // authenticate JWT tokens using our security pipeline if present, returns 401 if bad applicationBuilder.UseAuthentication(); @@ -446,6 +444,13 @@ namespace Tgstation.Server.Host.Core applicationBuilder.UseMvc(); // 404 anything that gets this far + // End of request pipeline setup + var masterVersionsAttribute = MasterVersionsAttribute.Instance; + logger.LogTrace("Configuration version: {0}", masterVersionsAttribute.RawConfigurationVersion); + logger.LogTrace("DMAPI version: {0}", masterVersionsAttribute.RawDMApiVersion); + logger.LogTrace("Web control panel version: {0}", masterVersionsAttribute.RawControlPanelVersion); + + logger.LogDebug("Starting hosting..."); } } } diff --git a/src/Tgstation.Server.Host/IServerFactory.cs b/src/Tgstation.Server.Host/IServerFactory.cs index 2502a65906..1fd1eddee5 100644 --- a/src/Tgstation.Server.Host/IServerFactory.cs +++ b/src/Tgstation.Server.Host/IServerFactory.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Host.IO; @@ -20,7 +20,7 @@ namespace Tgstation.Server.Host /// The arguments for the /// The directory in which to install server updates /// The for the operation. - /// A resulting in a new + /// A resulting in a new if it should be run, otherwise. Task CreateServer(string[] args, string updatePath, CancellationToken cancellationToken); } } diff --git a/src/Tgstation.Server.Host/Jobs/JobManager.cs b/src/Tgstation.Server.Host/Jobs/JobManager.cs index 5066f0cdfb..891d4bc409 100644 --- a/src/Tgstation.Server.Host/Jobs/JobManager.cs +++ b/src/Tgstation.Server.Host/Jobs/JobManager.cs @@ -207,10 +207,9 @@ namespace Tgstation.Server.Host.Jobs try { lock (synchronizationLock) - { jobs.Add(job.Id, jobHandler); - jobHandler.Start(); - } + + jobHandler.Start(); } catch { diff --git a/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs new file mode 100644 index 0000000000..20cc04786c --- /dev/null +++ b/src/Tgstation.Server.Host/Properties/MasterVersionsAttribute.cs @@ -0,0 +1,50 @@ +using System; +using System.Reflection; + +namespace Tgstation.Server.Host.Properties +{ + /// + /// Attribute for bringing in the master versions list from MSBuild that aren't embedded into assemblies by default. + /// + [AttributeUsage(AttributeTargets.Assembly)] + sealed class MasterVersionsAttribute : Attribute + { + /// + /// Return the 's instance of the . + /// + public static MasterVersionsAttribute Instance => Assembly + .GetExecutingAssembly() + .GetCustomAttribute(); + + /// + /// The of the version built. + /// + public string RawConfigurationVersion { get; } + + /// + /// The of the DMAPI version built. + /// + public string RawDMApiVersion { get; } + + /// + /// The of the control panel version built. + /// + public string RawControlPanelVersion { get; } + + /// + /// Initializes a new instance of the . + /// + /// The value of . + /// The value of . + /// The value of . + public MasterVersionsAttribute( + string rawConfigurationVersion, + string rawDMApiVersion, + string rawControlPanelVersion) + { + RawConfigurationVersion = rawConfigurationVersion ?? throw new ArgumentNullException(nameof(rawConfigurationVersion)); + RawDMApiVersion = rawDMApiVersion ?? throw new ArgumentNullException(nameof(rawDMApiVersion)); + RawControlPanelVersion = rawControlPanelVersion ?? throw new ArgumentNullException(nameof(rawControlPanelVersion)); + } + } +} diff --git a/src/Tgstation.Server.Host/ServerFactory.cs b/src/Tgstation.Server.Host/ServerFactory.cs index 9be5679521..55bbd24e3a 100644 --- a/src/Tgstation.Server.Host/ServerFactory.cs +++ b/src/Tgstation.Server.Host/ServerFactory.cs @@ -1,8 +1,9 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -39,24 +40,31 @@ namespace Tgstation.Server.Host } /// + // TODO: Decomplexify +#pragma warning disable CA1506 public async Task CreateServer(string[] args, string updatePath, CancellationToken cancellationToken) { if (args == null) throw new ArgumentNullException(nameof(args)); + var basePath = IOManager.ResolvePath(); IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((context, configuration) => configuration - .SetBasePath( - IOManager.ResolvePath())); + .ConfigureAppConfiguration((context, configuration) => configuration.SetBasePath(basePath)); var setupWizardHostBuilder = CreateDefaultBuilder() .UseSetupApplication(); - IPostSetupServices postSetupServices; + IPostSetupServices postSetupServices; using (var setupHost = setupWizardHostBuilder.Build()) { - postSetupServices = setupHost.Services.GetRequiredService(); + postSetupServices = setupHost.Services.GetRequiredService>(); await setupHost.RunAsync(cancellationToken).ConfigureAwait(false); + + if (postSetupServices.GeneralConfiguration.SetupWizardMode == SetupWizardMode.Only) + { + postSetupServices.Logger.LogInformation("Shutting down due to only running setup wizard."); + return null; + } } var hostBuilder = CreateDefaultBuilder() @@ -82,5 +90,6 @@ namespace Tgstation.Server.Host return new Server(hostBuilder, updatePath); } +#pragma warning restore CA1506 } } diff --git a/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs new file mode 100644 index 0000000000..029ec74c55 --- /dev/null +++ b/src/Tgstation.Server.Host/Setup/IPostSetupServices{TLoggerType}.cs @@ -0,0 +1,16 @@ +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 48353fbb5b..f595e3ba65 100644 --- a/src/Tgstation.Server.Host/Setup/PostSetupServices.cs +++ b/src/Tgstation.Server.Host/Setup/PostSetupServices.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.System; @@ -6,7 +7,7 @@ using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.Setup { /// - sealed class PostSetupServices : IPostSetupServices + sealed class PostSetupServices : IPostSetupServices { /// public IPlatformIdentifier PlatformIdentifier { get; } @@ -20,6 +21,9 @@ namespace Tgstation.Server.Host.Setup /// public FileLoggingConfiguration FileLoggingConfiguration => fileLoggingConfigurationOptions.Value; + /// + public ILogger Logger { get; } + /// /// Backing for . /// @@ -36,19 +40,25 @@ namespace Tgstation.Server.Host.Setup readonly IOptions fileLoggingConfigurationOptions; /// - /// Initializes a new instance of the . + /// Initializes a new instance of the . /// /// The value of . + /// The used to create . /// The containing the value of . /// The containing the value of . /// The containing the value of . public PostSetupServices( IPlatformIdentifier platformIdentifier, + ILoggerFactory loggerFactory, IOptions generalConfigurationOptions, IOptions databaseConfigurationOptions, IOptions fileLoggingConfigurationOptions) { PlatformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); + if (loggerFactory == null) + throw new ArgumentNullException(nameof(loggerFactory)); + + Logger = loggerFactory.CreateLogger(); this.generalConfigurationOptions = generalConfigurationOptions ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); this.databaseConfigurationOptions = databaseConfigurationOptions ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions)); this.fileLoggingConfigurationOptions = fileLoggingConfigurationOptions ?? throw new ArgumentNullException(nameof(fileLoggingConfigurationOptions)); diff --git a/src/Tgstation.Server.Host/Setup/SetupApplication.cs b/src/Tgstation.Server.Host/Setup/SetupApplication.cs index 87548b1145..9f848efa8f 100644 --- a/src/Tgstation.Server.Host/Setup/SetupApplication.cs +++ b/src/Tgstation.Server.Host/Setup/SetupApplication.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog.Events; @@ -73,7 +73,7 @@ namespace Tgstation.Server.Host.Setup /// The to configure. protected virtual void ConfigureHostedService(IServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(typeof(IPostSetupServices<>), typeof(PostSetupServices<>)); services.AddSingleton(); } } diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index b32bd9206d..31b934258e 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -613,7 +613,7 @@ namespace Tgstation.Server.Host.Setup if (String.IsNullOrWhiteSpace(newGeneralConfiguration.GitHubAccessToken)) newGeneralConfiguration.GitHubAccessToken = null; - newGeneralConfiguration.HostApiDocumemtation = await PromptYesNo("Host API Documentation? (y/n): ", cancellationToken).ConfigureAwait(false); + newGeneralConfiguration.HostApiDocumentation = await PromptYesNo("Host API Documentation? (y/n): ", cancellationToken).ConfigureAwait(false); return newGeneralConfiguration; } diff --git a/src/Tgstation.Server.Host/Configuration/SetupWizardMode.cs b/src/Tgstation.Server.Host/Setup/SetupWizardMode.cs similarity index 58% rename from src/Tgstation.Server.Host/Configuration/SetupWizardMode.cs rename to src/Tgstation.Server.Host/Setup/SetupWizardMode.cs index a61515d731..8d0798b88f 100644 --- a/src/Tgstation.Server.Host/Configuration/SetupWizardMode.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizardMode.cs @@ -1,27 +1,27 @@ -namespace Tgstation.Server.Host.Configuration +namespace Tgstation.Server.Host.Setup { /// - /// Determines if the will run + /// Determines if the will run. /// public enum SetupWizardMode { /// - /// Run the wizard if the appsettings.{Environment}.json is not present or empty + /// Run the wizard if the appsettings.{Environment}.json is not present or empty. /// Autodetect, /// - /// Force run the wizard + /// Force run the wizard. /// Force, /// - /// Only run the wizard and exit + /// Only run the wizard and exit. /// Only, /// - /// Never run the wizard + /// Never run the wizard. /// Never } diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index bee26f447e..351989b019 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -41,14 +41,16 @@ - + - - <_Parameter1>$(TgsDmapiVersion) + + <_Parameter1>$(TgsConfigVersion) + <_Parameter2>$(TgsDmapiVersion) + <_Parameter3>$(TgsControlPanelVersion) - + diff --git a/src/Tgstation.Server.Host/appsettings.json b/src/Tgstation.Server.Host/appsettings.json index bdc52afffc..63f9edf1ff 100644 --- a/src/Tgstation.Server.Host/appsettings.json +++ b/src/Tgstation.Server.Host/appsettings.json @@ -10,7 +10,7 @@ "UserLimit": 100, "InstanceLimit": 10, "ValidInstancePaths": null, - "HostApiDocumemtation": false + "HostApiDocumentation": false }, "FileLogging": { "Directory": null, diff --git a/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs b/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs index 07b454cb5f..6039e4e8f7 100644 --- a/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs +++ b/tests/Tgstation.Server.Host.Tests/TestServerFactory.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System; using System.Threading.Tasks; @@ -30,7 +30,8 @@ namespace Tgstation.Server.Host.Tests var factory = Application.CreateDefaultServerFactory(); await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, null, default)); - await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, null, default); + var result = await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, null, default); + Assert.IsNotNull(result); } [TestMethod] @@ -41,7 +42,8 @@ namespace Tgstation.Server.Host.Tests await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, null, default)); await Assert.ThrowsExceptionAsync(() => factory.CreateServer(null, Path, default)); - await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, Path, default); + var result = await factory.CreateServer(new[] { "General:SetupWizardMode=Never" }, Path, default); + Assert.IsNotNull(result); } } } diff --git a/tests/Tgstation.Server.Tests/TestingServer.cs b/tests/Tgstation.Server.Tests/TestingServer.cs index c061a0f9f3..8962ce2d58 100644 --- a/tests/Tgstation.Server.Tests/TestingServer.cs +++ b/tests/Tgstation.Server.Tests/TestingServer.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Tgstation.Server.Host; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; +using Tgstation.Server.Host.Setup; namespace Tgstation.Server.Tests { @@ -78,6 +79,7 @@ namespace Tgstation.Server.Tests String.Format(CultureInfo.InvariantCulture, "General:MinimumPasswordLength={0}", 10), String.Format(CultureInfo.InvariantCulture, "General:InstanceLimit={0}", 11), String.Format(CultureInfo.InvariantCulture, "General:UserLimit={0}", 150), + String.Format(CultureInfo.InvariantCulture, "General:HostApiDocumentation={0}", DumpOpenApiSpecpath), String.Format(CultureInfo.InvariantCulture, "FileLogging:Directory={0}", Path.Combine(Directory, "Logs")), String.Format(CultureInfo.InvariantCulture, "FileLogging:LogLevel={0}", "Trace"), String.Format(CultureInfo.InvariantCulture, "General:ValidInstancePaths:0={0}", Directory),