Move away from top level statements to keep everything under LANCommander namespace
parent
485b6febbe
commit
006bfcb866
|
@ -11,228 +11,238 @@ using System.Text;
|
||||||
using Hangfire;
|
using Hangfire;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
Logger Logger = LogManager.GetCurrentClassLogger();
|
namespace LANCommander
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Logger.Debug("JWT token secret is too short. Regenerating...");
|
internal class Program
|
||||||
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<LANCommander.Data.DatabaseContext>(b =>
|
|
||||||
{
|
|
||||||
b.UseLazyLoadingProxies();
|
|
||||||
b.UseSqlite(settings.DatabaseConnectionString);
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
|
||||||
|
|
||||||
Logger.Debug("Initializing Identity");
|
|
||||||
builder.Services.AddDefaultIdentity<User>((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<Role>()
|
|
||||||
.AddEntityFrameworkStores<LANCommander.Data.DatabaseContext>()
|
|
||||||
.AddDefaultTokenProviders();
|
|
||||||
|
|
||||||
builder.Services.AddAuthentication(options =>
|
|
||||||
{
|
|
||||||
/*options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;*/
|
|
||||||
})
|
|
||||||
.AddJwtBearer(options =>
|
|
||||||
{
|
{
|
||||||
options.SaveToken = true;
|
static async Task Main(string[] args)
|
||||||
options.RequireHttpsMetadata = false;
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters()
|
|
||||||
{
|
{
|
||||||
ValidateIssuer = false,
|
Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
ValidateAudience = false,
|
|
||||||
// ValidAudience = configuration["JWT:ValidAudience"],
|
|
||||||
// ValidIssuer = configuration["JWT:ValidIssuer"],
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(settings.Authentication.TokenSecret))
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
Logger.Debug("Initializing Controllers");
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Services.AddControllers().AddJsonOptions(x =>
|
|
||||||
{
|
|
||||||
x.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles;
|
|
||||||
});
|
|
||||||
|
|
||||||
Logger.Debug("Initializing Hangfire");
|
ConfigurationManager configuration = builder.Configuration;
|
||||||
builder.Services.AddHangfire(configuration =>
|
|
||||||
configuration
|
|
||||||
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
|
|
||||||
.UseSimpleAssemblyNameTypeSerializer()
|
|
||||||
.UseRecommendedSerializerSettings()
|
|
||||||
.UseInMemoryStorage());
|
|
||||||
builder.Services.AddHangfireServer();
|
|
||||||
|
|
||||||
Logger.Debug("Registering Swashbuckle");
|
// Add services to the container.
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
Logger.Debug("Loading settings");
|
||||||
builder.Services.AddSwaggerGen();
|
var settings = SettingService.GetSettings(true);
|
||||||
|
Logger.Debug("Loaded!");
|
||||||
|
|
||||||
Logger.Debug("Registering AntDesign Blazor");
|
#region Validate Settings
|
||||||
builder.Services.AddAntDesign();
|
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");
|
Logger.Debug("Starting web server on port {Port}", settings.Port);
|
||||||
builder.Services.AddScoped<SettingService>();
|
builder.WebHost.ConfigureKestrel(options =>
|
||||||
builder.Services.AddScoped<ArchiveService>();
|
{
|
||||||
builder.Services.AddScoped<CategoryService>();
|
// Configure as HTTP only
|
||||||
builder.Services.AddScoped<GameService>();
|
options.ListenAnyIP(settings.Port);
|
||||||
builder.Services.AddScoped<ScriptService>();
|
});
|
||||||
builder.Services.AddScoped<GenreService>();
|
|
||||||
builder.Services.AddScoped<KeyService>();
|
|
||||||
builder.Services.AddScoped<TagService>();
|
|
||||||
builder.Services.AddScoped<CompanyService>();
|
|
||||||
builder.Services.AddScoped<IGDBService>();
|
|
||||||
builder.Services.AddScoped<ServerService>();
|
|
||||||
builder.Services.AddScoped<ServerConsoleService>();
|
|
||||||
builder.Services.AddScoped<GameSaveService>();
|
|
||||||
|
|
||||||
builder.Services.AddSingleton<ServerProcessService>();
|
Logger.Debug("Initializing DatabaseContext with connection string {ConnectionString}", settings.DatabaseConnectionString);
|
||||||
builder.Services.AddSingleton<IPXRelayService>();
|
builder.Services.AddDbContext<LANCommander.Data.DatabaseContext>(b =>
|
||||||
|
{
|
||||||
|
b.UseLazyLoadingProxies();
|
||||||
|
b.UseSqlite(settings.DatabaseConnectionString);
|
||||||
|
});
|
||||||
|
|
||||||
if (settings.Beacon)
|
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||||
{
|
|
||||||
Logger.Debug("The beacons have been lit! LANCommander calls for players!");
|
|
||||||
builder.Services.AddHostedService<BeaconService>();
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WebHost.UseStaticWebAssets();
|
Logger.Debug("Initializing Identity");
|
||||||
|
builder.Services.AddDefaultIdentity<User>((IdentityOptions options) =>
|
||||||
|
{
|
||||||
|
options.SignIn.RequireConfirmedAccount = false;
|
||||||
|
options.SignIn.RequireConfirmedEmail = false;
|
||||||
|
|
||||||
builder.WebHost.UseKestrel(options =>
|
options.Password.RequireNonAlphanumeric = settings.Authentication.PasswordRequireNonAlphanumeric;
|
||||||
{
|
options.Password.RequireLowercase = settings.Authentication.PasswordRequireLowercase;
|
||||||
options.Limits.MaxRequestBodySize = 1024 * 1024 * 150;
|
options.Password.RequireUppercase = settings.Authentication.PasswordRequireUppercase;
|
||||||
});
|
options.Password.RequireDigit = settings.Authentication.PasswordRequireDigit;
|
||||||
|
options.Password.RequiredLength = settings.Authentication.PasswordRequiredLength;
|
||||||
|
})
|
||||||
|
.AddRoles<Role>()
|
||||||
|
.AddEntityFrameworkStores<LANCommander.Data.DatabaseContext>()
|
||||||
|
.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");
|
Logger.Debug("Initializing Controllers");
|
||||||
var app = builder.Build();
|
builder.Services.AddControllers().AddJsonOptions(x =>
|
||||||
|
{
|
||||||
|
x.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles;
|
||||||
|
});
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
Logger.Debug("Initializing Hangfire");
|
||||||
if (app.Environment.IsDevelopment())
|
builder.Services.AddHangfire(configuration =>
|
||||||
{
|
configuration
|
||||||
Logger.Debug("App has been run in a development environment");
|
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
|
||||||
app.UseMigrationsEndPoint();
|
.UseSimpleAssemblyNameTypeSerializer()
|
||||||
app.UseSwagger();
|
.UseRecommendedSerializerSettings()
|
||||||
app.UseSwaggerUI();
|
.UseInMemoryStorage());
|
||||||
}
|
builder.Services.AddHangfireServer();
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseHangfireDashboard();
|
Logger.Debug("Registering Swashbuckle");
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
// app.UseHttpsRedirection();
|
Logger.Debug("Registering AntDesign Blazor");
|
||||||
app.UseStaticFiles();
|
builder.Services.AddAntDesign();
|
||||||
|
|
||||||
app.UseRouting();
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
app.UseAuthentication();
|
Logger.Debug("Registering Services");
|
||||||
app.UseAuthorization();
|
builder.Services.AddScoped<SettingService>();
|
||||||
|
builder.Services.AddScoped<ArchiveService>();
|
||||||
|
builder.Services.AddScoped<CategoryService>();
|
||||||
|
builder.Services.AddScoped<GameService>();
|
||||||
|
builder.Services.AddScoped<ScriptService>();
|
||||||
|
builder.Services.AddScoped<GenreService>();
|
||||||
|
builder.Services.AddScoped<KeyService>();
|
||||||
|
builder.Services.AddScoped<TagService>();
|
||||||
|
builder.Services.AddScoped<CompanyService>();
|
||||||
|
builder.Services.AddScoped<IGDBService>();
|
||||||
|
builder.Services.AddScoped<ServerService>();
|
||||||
|
builder.Services.AddScoped<ServerConsoleService>();
|
||||||
|
builder.Services.AddScoped<GameSaveService>();
|
||||||
|
|
||||||
app.UseMvcWithDefaultRoute();
|
builder.Services.AddSingleton<ServerProcessService>();
|
||||||
|
builder.Services.AddSingleton<IPXRelayService>();
|
||||||
|
|
||||||
app.MapHub<GameServerHub>("/hubs/gameserver");
|
if (settings.Beacon)
|
||||||
|
{
|
||||||
|
Logger.Debug("The beacons have been lit! LANCommander calls for players!");
|
||||||
|
builder.Services.AddHostedService<BeaconService>();
|
||||||
|
}
|
||||||
|
|
||||||
Logger.Debug("Registering Endpoints");
|
builder.WebHost.UseStaticWebAssets();
|
||||||
app.UseEndpoints(endpoints =>
|
|
||||||
{
|
|
||||||
endpoints.MapBlazorHub();
|
|
||||||
endpoints.MapFallbackToPage("/_Host");
|
|
||||||
endpoints.MapControllers();
|
|
||||||
});
|
|
||||||
|
|
||||||
Logger.Debug("Ensuring required directories exist");
|
builder.WebHost.UseKestrel(options =>
|
||||||
if (!Directory.Exists(settings.Archives.StoragePath))
|
{
|
||||||
Directory.CreateDirectory(settings.Archives.StoragePath);
|
options.Limits.MaxRequestBodySize = 1024 * 1024 * 150;
|
||||||
|
});
|
||||||
|
|
||||||
if (!Directory.Exists("Icon"))
|
builder.Host.UseNLog();
|
||||||
Directory.CreateDirectory("Icon");
|
|
||||||
|
|
||||||
if (!Directory.Exists(settings.UserSaves.StoragePath))
|
Logger.Debug("Building Application");
|
||||||
Directory.CreateDirectory(settings.UserSaves.StoragePath);
|
var app = builder.Build();
|
||||||
|
|
||||||
if (!Directory.Exists("Snippets"))
|
// Configure the HTTP request pipeline.
|
||||||
Directory.CreateDirectory("Snippets");
|
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
|
app.UseHangfireDashboard();
|
||||||
Logger.Debug("Migrating database if required");
|
|
||||||
await using var scope = app.Services.CreateAsyncScope();
|
|
||||||
using var db = scope.ServiceProvider.GetService<DatabaseContext>();
|
|
||||||
await db.Database.MigrateAsync();
|
|
||||||
|
|
||||||
// Autostart any server processes
|
// app.UseHttpsRedirection();
|
||||||
Logger.Debug("Autostarting Servers");
|
app.UseStaticFiles();
|
||||||
var serverService = scope.ServiceProvider.GetService<ServerService>();
|
|
||||||
var serverProcessService = scope.ServiceProvider.GetService<ServerProcessService>();
|
|
||||||
|
|
||||||
foreach (var server in await serverService.Get(s => s.Autostart).ToListAsync())
|
app.UseRouting();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Logger.Debug("Autostarting server {ServerName} with a delay of {AutostartDelay} seconds", server.Name, server.AutostartDelay);
|
|
||||||
|
|
||||||
if (server.AutostartDelay > 0)
|
app.UseAuthentication();
|
||||||
await Task.Delay(server.AutostartDelay);
|
app.UseAuthorization();
|
||||||
|
|
||||||
serverProcessService.StartServerAsync(server);
|
app.UseMvcWithDefaultRoute();
|
||||||
}
|
|
||||||
catch (Exception ex)
|
app.MapHub<GameServerHub>("/hubs/gameserver");
|
||||||
{
|
|
||||||
Logger.Debug(ex, "An unexpected error occurred while trying to autostart the server {ServerName}", server.Name);
|
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<DatabaseContext>();
|
||||||
|
await db.Database.MigrateAsync();
|
||||||
|
|
||||||
|
// Autostart any server processes
|
||||||
|
Logger.Debug("Autostarting Servers");
|
||||||
|
var serverService = scope.ServiceProvider.GetService<ServerService>();
|
||||||
|
var serverProcessService = scope.ServiceProvider.GetService<ServerProcessService>();
|
||||||
|
|
||||||
|
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();
|
|
Loading…
Reference in New Issue