2using System.Collections.Generic;
3using System.Globalization;
4using System.IdentityModel.Tokens.Jwt;
7using Cyberboss.AspNetCore.AsyncInitializer;
9using Microsoft.AspNetCore.Authentication.JwtBearer;
10using Microsoft.AspNetCore.Builder;
11using Microsoft.AspNetCore.Cors.Infrastructure;
12using Microsoft.AspNetCore.Hosting;
13using Microsoft.AspNetCore.Identity;
14using Microsoft.AspNetCore.Mvc.Infrastructure;
15using Microsoft.Extensions.Configuration;
16using Microsoft.Extensions.DependencyInjection;
17using Microsoft.Extensions.Hosting;
18using Microsoft.Extensions.Logging;
19using Microsoft.Extensions.Options;
25using Serilog.Formatting.Display;
59#pragma warning disable CA1506
81 assemblyInformationProvider,
94 if (postSetupServices.GeneralConfiguration.UseBasicWatchdog)
106 IConfiguration configuration,
108 : base(configuration)
121 IServiceCollection services,
128 ArgumentNullException.ThrowIfNull(postSetupServices);
137 services.AddOptions();
140 services.Configure<HostOptions>(
143 static LogEventLevel? ConvertSeriLogLevel(LogLevel logLevel) =>
146 LogLevel.Critical => LogEventLevel.Fatal,
147 LogLevel.Debug => LogEventLevel.Debug,
148 LogLevel.Error => LogEventLevel.Error,
149 LogLevel.Information => LogEventLevel.Information,
150 LogLevel.Trace => LogEventLevel.Verbose,
151 LogLevel.Warning => LogEventLevel.Warning,
152 LogLevel.None =>
null,
153 _ =>
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Invalid log level {0}", logLevel)),
157 services.SetupLogging(
160 if (microsoftEventLevel.HasValue)
162 config.MinimumLevel.Override(
"Microsoft", microsoftEventLevel.Value);
163 config.MinimumLevel.Override(
"System.Net.Http.HttpClient", microsoftEventLevel.Value);
173 assemblyInformationProvider,
178 var formatter =
new MessageTemplateTextFormatter(
181 +
"): [{Level:u3}] {SourceContext:l}: {Message} ({EventId:x8}){NewLine}{Exception}",
184 logPath = ioManager.
ConcatPath(logPath,
"tgs-.log");
185 var rollingFileConfig = sinkConfig.File(
188 logEventLevel ?? LogEventLevel.Verbose,
190 flushToDiskInterval: TimeSpan.FromSeconds(2),
191 rollingInterval: RollingInterval.Day,
192 rollOnFileSizeLimit:
true);
198 .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
199 .AddJwtBearer(jwtBearerOptions =>
204 jwtBearerOptions.Events =
new JwtBearerEvents
208 OnTokenValidated = ctx => ctx
212 .InjectClaimsIntoContext(
214 ctx.HttpContext.RequestAborted),
221 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
227 options.EnableEndpointRouting =
false;
228 options.ReturnHttpNotAcceptable =
true;
229 options.RespectBrowserAcceptHeader =
true;
231 .AddNewtonsoftJson(options =>
233 options.AllowInputFormatterExceptionMessages =
true;
234 options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
235 options.SerializerSettings.CheckAdditionalContent =
true;
236 options.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
237 options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
238 options.SerializerSettings.Converters =
new List<JsonConverter>
247 var assemblyDocumentationPath = GetDocumentationFilePath(GetType().Assembly.Location);
248 var apiDocumentationPath = GetDocumentationFilePath(typeof(
ApiHeaders).Assembly.Location);
250 services.AddSwaggerGenNewtonsoftSupport();
257 services.AddHttpClient();
264 services.AddDbContextPool<TContext>((serviceProvider, builder) =>
267 builder.EnableSensitiveDataLogging();
269 var databaseConfigOptions = serviceProvider.GetRequiredService<IOptions<DatabaseConfiguration>>();
270 var databaseConfig = databaseConfigOptions.Value ??
throw new InvalidOperationException(
"DatabaseConfiguration missing!");
271 configureAction(builder, databaseConfig);
273 services.AddScoped<
IDatabaseContext>(x => x.GetRequiredService<TContext>());
282 AddTypedContext<MySqlDatabaseContext>();
285 AddTypedContext<SqlServerDatabaseContext>();
288 AddTypedContext<SqliteDatabaseContext>();
291 AddTypedContext<PostgresSqlDatabaseContext>();
294 throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture,
"Invalid {0}: {1}!", nameof(
DatabaseType), dbType));
308 services.AddSingleton<IPasswordHasher<Models.User>, PasswordHasher<Models.User>>();
313 AddWatchdog<WindowsWatchdogFactory>(services, postSetupServices);
326 AddWatchdog<PosixWatchdogFactory>(services, postSetupServices);
335 services.AddSingleton(x =>
new Lazy<IProcessExecutor>(() => x.GetRequiredService<
IProcessExecutor>(),
true));
363 services.AddChatProviderFactory();
371 services.AddFileDownloader();
375 services.AddGitHub();
399 IApplicationBuilder applicationBuilder,
404 IOptions<ControlPanelConfiguration> controlPanelConfigurationOptions,
405 IOptions<GeneralConfiguration> generalConfigurationOptions,
406 IOptions<SwarmConfiguration> swarmConfigurationOptions,
407 ILogger<Application> logger)
409 ArgumentNullException.ThrowIfNull(applicationBuilder);
410 ArgumentNullException.ThrowIfNull(serverControl);
414 ArgumentNullException.ThrowIfNull(serverPortProvider);
415 ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
417 var controlPanelConfiguration = controlPanelConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(controlPanelConfigurationOptions));
418 var generalConfiguration = generalConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(generalConfigurationOptions));
419 var swarmConfiguration = swarmConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(swarmConfigurationOptions));
421 ArgumentNullException.ThrowIfNull(logger);
428 applicationBuilder.UseAdditionalRequestLoggingContext(swarmConfiguration);
431 applicationBuilder.UseServerErrorHandling();
434 applicationBuilder.UseServerBranding(assemblyInformationProvider);
437 applicationBuilder.UseCancelledRequestSuppression();
441 (instanceManager, cancellationToken) => instanceManager.
Ready.WithToken(cancellationToken));
443 if (generalConfiguration.HostApiDocumentation)
445 applicationBuilder.UseSwagger();
446 applicationBuilder.UseSwaggerUI(c => c.SwaggerEndpoint(
"/swagger/v1/swagger.json",
"TGS API"));
447 logger.LogTrace(
"Swagger API generation enabled");
451 Action<CorsPolicyBuilder> corsBuilder =
null;
452 if (controlPanelConfiguration.AllowAnyOrigin)
454 logger.LogTrace(
"Access-Control-Allow-Origin: *");
455 corsBuilder = builder => builder.AllowAnyOrigin();
457 else if (controlPanelConfiguration.AllowedOrigins?.Count > 0)
459 logger.LogTrace(
"Access-Control-Allow-Origin: {allowedOrigins}", String.Join(
',', controlPanelConfiguration.AllowedOrigins));
460 corsBuilder = builder => builder.WithOrigins(controlPanelConfiguration.AllowedOrigins.ToArray());
463 var originalBuilder = corsBuilder;
464 corsBuilder = builder =>
469 .SetPreflightMaxAge(TimeSpan.FromDays(1));
470 originalBuilder?.Invoke(builder);
472 applicationBuilder.UseCors(corsBuilder);
475 if (controlPanelConfiguration.Enable)
477 logger.LogInformation(
"Web control panel enabled.");
478 applicationBuilder.UseFileServer(
new FileServerOptions
481 EnableDefaultFiles =
true,
482 EnableDirectoryBrowsing =
false,
486 logger.LogTrace(
"Web control panel disabled!");
489 applicationBuilder.UseDisabledClientCache();
492 applicationBuilder.UseAuthentication();
495 applicationBuilder.UseDbConflictHandling();
498 applicationBuilder.UseMvc();
504 if (controlPanelConfiguration.Enable)
507 logger.LogDebug(
"Starting hosting on port {httpApiPort}...", serverPortProvider.
HttpApiPort);
IByondInstaller for Posix systems.
IByondInstaller for windows systems.
Constants used for communication with the DMAPI.
static readonly Version InteropVersion
The DMAPI InteropVersion being used.
Configuration options for the web control panel.
DatabaseType DatabaseType
The Configuration.DatabaseType to create.
LogLevel MicrosoftLogLevel
The minimum Microsoft.Extensions.Logging.LogLevel to display in logs for Microsoft library sources.
string GetFullLogDirectory(IIOManager ioManager, IAssemblyInformationProvider assemblyInformationProvider, IPlatformIdentifier platformIdentifier)
Gets the evaluated log Directory.
LogLevel LogLevel
The minimum Microsoft.Extensions.Logging.LogLevel to display in logs.
bool Disable
If file logging is disabled.
General configuration options.
static readonly Version CurrentConfigVersion
The current ConfigVersion.
bool HostApiDocumentation
If the swagger UI should be made avaiable.
uint RestartTimeoutMinutes
The timeout minutes for restarting the server.
Configuration options for the game sessions.
Configuration for the server swarm system.
Configuration for the automatic update system.
Controller for the web control panel.
const string ControlPanelRoute
Route to the ControlPanelController.
IActionResultExecutor<TResult> for LimitedStreamResults.
Sets up dependency injection.
override void ConfigureHostedService(IServiceCollection services)
Configures the IHostedService.
static void AddWatchdog< TSystemWatchdogFactory >(IServiceCollection services, IPostSetupServices postSetupServices)
Adds the IWatchdogFactory implementation.
void ConfigureServices(IServiceCollection services, IAssemblyInformationProvider assemblyInformationProvider, IIOManager ioManager, IPostSetupServices postSetupServices)
Configure the Application's services.
static IServerFactory CreateDefaultServerFactory()
Create the default IServerFactory.
ITokenFactory tokenFactory
The ITokenFactory for the Application.
void Configure(IApplicationBuilder applicationBuilder, IServerControl serverControl, ITokenFactory tokenFactory, IServerPortProvider serverPortProvider, IAssemblyInformationProvider assemblyInformationProvider, IOptions< ControlPanelConfiguration > controlPanelConfigurationOptions, IOptions< GeneralConfiguration > generalConfigurationOptions, IOptions< SwarmConfiguration > swarmConfigurationOptions, ILogger< Application > logger)
Configure the Application.
Application(IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
Initializes a new instance of the Application class.
readonly IWebHostEnvironment hostingEnvironment
The IWebHostEnvironment for the Application.
Backend abstract implementation of IDatabaseContext.
JsonConverter and IYamlTypeConverter for serializing global::System.Versions in semver format.
IIOManager that resolves paths to Environment.CurrentDirectory.
IPostWriteHandler for POSIX systems.
ISymlinkFactory for posix systems.
IPostWriteHandler for Windows systems.
ISymlinkFactory for windows systems.
Attribute for bringing in the master versions list from MSBuild that aren't embedded into assemblies ...
string RawControlPanelVersion
The Version string of the control panel version built.
static MasterVersionsAttribute Instance
Return the Assembly's instance of the MasterVersionsAttribute.
ISystemIdentityFactory for posix systems.
ISystemIdentityFactory for windows systems. Uses long running tasks due to potential networked domain...
Implementation of IServerFactory.
DI root for configuring a SetupWizard.
IConfiguration Configuration
The IConfiguration for the SetupApplication.
Helps keep servers connected to the same database in sync by coordinating updates.
Implements the SystemD notify service protocol.
Implementation of the file transfer service.
Helpers for manipulating the Serilog.Context.LogContext.
static string Template
Common template used for adding our custom log context to serilog.
Implements various filters for Swashbuckle.
static void Configure(SwaggerGenOptions swaggerGenOptions, string assemblyDocumentationPath, string apiDocumentationPath)
Configure the swagger settings.
For downloading and installing BYOND extractions for a given system.
For creating IChatManagers.
Factory for creating IRemoteDeploymentManagers.
Factory for creating IInstances.
Task Ready
Task that completes when the IInstanceManager finishes initializing.
Handler for BridgeParameters.
Factory for creating IGitRemoteFeatures.
For low level interactions with a LibGit2Sharp.IRepository.
Factory for creating LibGit2Sharp.IRepositorys.
Factory for ITopicClients.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
Provides access to the server's HttpApiPort.
ushort HttpApiPort
The port the server listens on.
Initiates server self updates.
Factory for scoping usage of IDatabaseContexts. Meant for use by Components.
For initially setting up a database.
Interface for using filesystems.
string ConcatPath(params string[] paths)
Combines an array of strings into a path.
string GetDirectoryName(string path)
Gets the directory portion of a given path .
string GetFileNameWithoutExtension(string path)
Gets the file name portion of a path with.
Handles changing file modes/permissions after writing.
For creating filesystem symbolic links.
For accessing the disk in a synchronous manner.
Manages the runtime of Jobs.
The service that manages everything to do with jobs.
For creating and accessing authentication contexts.
For injecting global::System.Security.Claims.Claims that Controllers.TgsAuthorizeAttribute can look f...
Contains various cryptographic functions.
For caching ISystemIdentitys.
Factory for ISystemIdentitys.
For creating TokenResponses.
TokenValidationParameters ValidationParameters
The TokenValidationParameters for the ITokenFactory.
Contains IOAuthValidators.
Set of objects needed to configure an Core.Application.
ElasticsearchConfiguration ElasticsearchConfiguration
The Configuration.ElasticsearchConfiguration.
GeneralConfiguration GeneralConfiguration
The Configuration.GeneralConfiguration.
DatabaseConfiguration DatabaseConfiguration
The Configuration.DatabaseConfiguration.
IPlatformIdentifier PlatformIdentifier
The IPlatformIdentifier.
FileLoggingConfiguration FileLoggingConfiguration
The Configuration.FileLoggingConfiguration.
Swarm service operations for the Controllers.SwarmController.
Start and stop controllers for a swarm service.
Used for swarm operations. Functions may be no-op based on configuration.
On Windows, DreamDaemon will show an unskippable prompt when using /world/proc/OpenPort()....
Abstraction for suspending and resuming processes.
Reads and writes to Streams associated with FileTicketResponses.
Service for temporarily storing files to be downloaded or uploaded.
Gets unassigned ports for use by TGS.
DatabaseType
Type of database to user.