diff --git a/LANCommander/Program.cs b/LANCommander/Program.cs index c04aff1..7340d21 100644 --- a/LANCommander/Program.cs +++ b/LANCommander/Program.cs @@ -11,228 +11,238 @@ using System.Text; using Hangfire; using NLog; -Logger Logger = LogManager.GetCurrentClassLogger(); - -var builder = WebApplication.CreateBuilder(args); - -ConfigurationManager configuration = builder.Configuration; - -// Add services to the container. -Logger.Debug("Loading settings"); -var settings = SettingService.GetSettings(true); -Logger.Debug("Loaded!"); - -#region Validate Settings -Logger.Debug("Validating settings"); -if (settings?.Authentication?.TokenSecret?.Length < 16) +namespace LANCommander { - Logger.Debug("JWT token secret is too short. Regenerating..."); - settings.Authentication.TokenSecret = Guid.NewGuid().ToString(); - SettingService.SaveSettings(settings); -} -Logger.Debug("Done validating settings"); -#endregion - -Logger.Debug("Configuring MVC and Blazor"); -builder.Services.AddMvc(options => options.EnableEndpointRouting = false); -builder.Services.AddRazorPages(); -builder.Services.AddServerSideBlazor().AddCircuitOptions(option => -{ - option.DetailedErrors = true; -}).AddHubOptions(option => -{ - option.MaximumReceiveMessageSize = 1024 * 1024 * 11; - option.DisableImplicitFromServicesParameters = true; -}); - -Logger.Debug("Starting web server on port {Port}", settings.Port); -builder.WebHost.ConfigureKestrel(options => -{ - // Configure as HTTP only - options.ListenAnyIP(settings.Port); -}); - -Logger.Debug("Initializing DatabaseContext with connection string {ConnectionString}", settings.DatabaseConnectionString); -builder.Services.AddDbContext(b => -{ - b.UseLazyLoadingProxies(); - b.UseSqlite(settings.DatabaseConnectionString); -}); - -builder.Services.AddDatabaseDeveloperPageExceptionFilter(); - -Logger.Debug("Initializing Identity"); -builder.Services.AddDefaultIdentity((IdentityOptions options) => -{ - options.SignIn.RequireConfirmedAccount = false; - options.SignIn.RequireConfirmedEmail = false; - - options.Password.RequireNonAlphanumeric = settings.Authentication.PasswordRequireNonAlphanumeric; - options.Password.RequireLowercase = settings.Authentication.PasswordRequireLowercase; - options.Password.RequireUppercase = settings.Authentication.PasswordRequireUppercase; - options.Password.RequireDigit = settings.Authentication.PasswordRequireDigit; - options.Password.RequiredLength = settings.Authentication.PasswordRequiredLength; -}) - .AddRoles() - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - -builder.Services.AddAuthentication(options => -{ - /*options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;*/ -}) - .AddJwtBearer(options => + internal class Program { - options.SaveToken = true; - options.RequireHttpsMetadata = false; - options.TokenValidationParameters = new TokenValidationParameters() + static async Task Main(string[] args) { - ValidateIssuer = false, - ValidateAudience = false, - // ValidAudience = configuration["JWT:ValidAudience"], - // ValidIssuer = configuration["JWT:ValidIssuer"], - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.Authentication.TokenSecret)) - }; - }); + Logger Logger = LogManager.GetCurrentClassLogger(); -Logger.Debug("Initializing Controllers"); -builder.Services.AddControllers().AddJsonOptions(x => -{ - x.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles; -}); + var builder = WebApplication.CreateBuilder(args); -Logger.Debug("Initializing Hangfire"); -builder.Services.AddHangfire(configuration => - configuration - .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) - .UseSimpleAssemblyNameTypeSerializer() - .UseRecommendedSerializerSettings() - .UseInMemoryStorage()); -builder.Services.AddHangfireServer(); + ConfigurationManager configuration = builder.Configuration; -Logger.Debug("Registering Swashbuckle"); -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); + // Add services to the container. + Logger.Debug("Loading settings"); + var settings = SettingService.GetSettings(true); + Logger.Debug("Loaded!"); -Logger.Debug("Registering AntDesign Blazor"); -builder.Services.AddAntDesign(); + #region Validate Settings + Logger.Debug("Validating settings"); + if (settings?.Authentication?.TokenSecret?.Length < 16) + { + Logger.Debug("JWT token secret is too short. Regenerating..."); + settings.Authentication.TokenSecret = Guid.NewGuid().ToString(); + SettingService.SaveSettings(settings); + } + Logger.Debug("Done validating settings"); + #endregion -builder.Services.AddHttpClient(); + Logger.Debug("Configuring MVC and Blazor"); + builder.Services.AddMvc(options => options.EnableEndpointRouting = false); + builder.Services.AddRazorPages(); + builder.Services.AddServerSideBlazor().AddCircuitOptions(option => + { + option.DetailedErrors = true; + }).AddHubOptions(option => + { + option.MaximumReceiveMessageSize = 1024 * 1024 * 11; + option.DisableImplicitFromServicesParameters = true; + }); -Logger.Debug("Registering Services"); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); + Logger.Debug("Starting web server on port {Port}", settings.Port); + builder.WebHost.ConfigureKestrel(options => + { + // Configure as HTTP only + options.ListenAnyIP(settings.Port); + }); -builder.Services.AddSingleton(); -builder.Services.AddSingleton(); + Logger.Debug("Initializing DatabaseContext with connection string {ConnectionString}", settings.DatabaseConnectionString); + builder.Services.AddDbContext(b => + { + b.UseLazyLoadingProxies(); + b.UseSqlite(settings.DatabaseConnectionString); + }); -if (settings.Beacon) -{ - Logger.Debug("The beacons have been lit! LANCommander calls for players!"); - builder.Services.AddHostedService(); -} + builder.Services.AddDatabaseDeveloperPageExceptionFilter(); -builder.WebHost.UseStaticWebAssets(); + Logger.Debug("Initializing Identity"); + builder.Services.AddDefaultIdentity((IdentityOptions options) => + { + options.SignIn.RequireConfirmedAccount = false; + options.SignIn.RequireConfirmedEmail = false; -builder.WebHost.UseKestrel(options => -{ - options.Limits.MaxRequestBodySize = 1024 * 1024 * 150; -}); + options.Password.RequireNonAlphanumeric = settings.Authentication.PasswordRequireNonAlphanumeric; + options.Password.RequireLowercase = settings.Authentication.PasswordRequireLowercase; + options.Password.RequireUppercase = settings.Authentication.PasswordRequireUppercase; + options.Password.RequireDigit = settings.Authentication.PasswordRequireDigit; + options.Password.RequiredLength = settings.Authentication.PasswordRequiredLength; + }) + .AddRoles() + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); -builder.Host.UseNLog(); + builder.Services.AddAuthentication(options => + { + /*options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;*/ + }) + .AddJwtBearer(options => + { + options.SaveToken = true; + options.RequireHttpsMetadata = false; + options.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuer = false, + ValidateAudience = false, + // ValidAudience = configuration["JWT:ValidAudience"], + // ValidIssuer = configuration["JWT:ValidIssuer"], + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.Authentication.TokenSecret)) + }; + }); -Logger.Debug("Building Application"); -var app = builder.Build(); + Logger.Debug("Initializing Controllers"); + builder.Services.AddControllers().AddJsonOptions(x => + { + x.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles; + }); -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - Logger.Debug("App has been run in a development environment"); - app.UseMigrationsEndPoint(); - app.UseSwagger(); - app.UseSwaggerUI(); -} -else -{ - app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); -} + Logger.Debug("Initializing Hangfire"); + builder.Services.AddHangfire(configuration => + configuration + .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) + .UseSimpleAssemblyNameTypeSerializer() + .UseRecommendedSerializerSettings() + .UseInMemoryStorage()); + builder.Services.AddHangfireServer(); -app.UseHangfireDashboard(); + Logger.Debug("Registering Swashbuckle"); + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); -// app.UseHttpsRedirection(); -app.UseStaticFiles(); + Logger.Debug("Registering AntDesign Blazor"); + builder.Services.AddAntDesign(); -app.UseRouting(); + builder.Services.AddHttpClient(); -app.UseAuthentication(); -app.UseAuthorization(); + Logger.Debug("Registering Services"); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); -app.UseMvcWithDefaultRoute(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); -app.MapHub("/hubs/gameserver"); + if (settings.Beacon) + { + Logger.Debug("The beacons have been lit! LANCommander calls for players!"); + builder.Services.AddHostedService(); + } -Logger.Debug("Registering Endpoints"); -app.UseEndpoints(endpoints => -{ - endpoints.MapBlazorHub(); - endpoints.MapFallbackToPage("/_Host"); - endpoints.MapControllers(); -}); + builder.WebHost.UseStaticWebAssets(); -Logger.Debug("Ensuring required directories exist"); -if (!Directory.Exists(settings.Archives.StoragePath)) - Directory.CreateDirectory(settings.Archives.StoragePath); + builder.WebHost.UseKestrel(options => + { + options.Limits.MaxRequestBodySize = 1024 * 1024 * 150; + }); -if (!Directory.Exists("Icon")) - Directory.CreateDirectory("Icon"); + builder.Host.UseNLog(); -if (!Directory.Exists(settings.UserSaves.StoragePath)) - Directory.CreateDirectory(settings.UserSaves.StoragePath); + Logger.Debug("Building Application"); + var app = builder.Build(); -if (!Directory.Exists("Snippets")) - Directory.CreateDirectory("Snippets"); + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + Logger.Debug("App has been run in a development environment"); + app.UseMigrationsEndPoint(); + app.UseSwagger(); + app.UseSwaggerUI(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } -// Migrate -Logger.Debug("Migrating database if required"); -await using var scope = app.Services.CreateAsyncScope(); -using var db = scope.ServiceProvider.GetService(); -await db.Database.MigrateAsync(); + app.UseHangfireDashboard(); -// Autostart any server processes -Logger.Debug("Autostarting Servers"); -var serverService = scope.ServiceProvider.GetService(); -var serverProcessService = scope.ServiceProvider.GetService(); + // app.UseHttpsRedirection(); + app.UseStaticFiles(); -foreach (var server in await serverService.Get(s => s.Autostart).ToListAsync()) -{ - try - { - Logger.Debug("Autostarting server {ServerName} with a delay of {AutostartDelay} seconds", server.Name, server.AutostartDelay); + app.UseRouting(); - if (server.AutostartDelay > 0) - await Task.Delay(server.AutostartDelay); + app.UseAuthentication(); + app.UseAuthorization(); - serverProcessService.StartServerAsync(server); - } - catch (Exception ex) - { - Logger.Debug(ex, "An unexpected error occurred while trying to autostart the server {ServerName}", server.Name); + app.UseMvcWithDefaultRoute(); + + app.MapHub("/hubs/gameserver"); + + Logger.Debug("Registering Endpoints"); + app.UseEndpoints(endpoints => + { + endpoints.MapBlazorHub(); + endpoints.MapFallbackToPage("/_Host"); + endpoints.MapControllers(); + }); + + Logger.Debug("Ensuring required directories exist"); + if (!Directory.Exists(settings.Archives.StoragePath)) + Directory.CreateDirectory(settings.Archives.StoragePath); + + if (!Directory.Exists("Icon")) + Directory.CreateDirectory("Icon"); + + if (!Directory.Exists(settings.UserSaves.StoragePath)) + Directory.CreateDirectory(settings.UserSaves.StoragePath); + + if (!Directory.Exists("Snippets")) + Directory.CreateDirectory("Snippets"); + + // Migrate + Logger.Debug("Migrating database if required"); + await using var scope = app.Services.CreateAsyncScope(); + using var db = scope.ServiceProvider.GetService(); + await db.Database.MigrateAsync(); + + // Autostart any server processes + Logger.Debug("Autostarting Servers"); + var serverService = scope.ServiceProvider.GetService(); + var serverProcessService = scope.ServiceProvider.GetService(); + + foreach (var server in await serverService.Get(s => s.Autostart).ToListAsync()) + { + try + { + Logger.Debug("Autostarting server {ServerName} with a delay of {AutostartDelay} seconds", server.Name, server.AutostartDelay); + + if (server.AutostartDelay > 0) + await Task.Delay(server.AutostartDelay); + + serverProcessService.StartServerAsync(server); + } + catch (Exception ex) + { + Logger.Debug(ex, "An unexpected error occurred while trying to autostart the server {ServerName}", server.Name); + } + } + + app.Run(); + } } } -app.Run(); \ No newline at end of file