using System.Diagnostics; using Microsoft.EntityFrameworkCore; using Microsoft.FluentUI.AspNetCore.Components; using RomRepoMgr.Blazor.Components; using RomRepoMgr.Database; using RomRepoMgr.Settings; using Serilog; using Serilog.Events; // Start the application Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.Console().Enrich.FromLogContext().CreateLogger(); Log.Information("Welcome to ROM Repository Manager!"); Log.Information("Copyright © 2020-2025 Natalia Portillo"); // Configuration and settings // We need the builder now Log.Debug("Creating the builder..."); WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Access the full configuration Log.Debug("Creating the configuration reader..."); ConfigurationManager config = builder.Configuration; string logFile = config["LogFile"] ?? "logs/rom-repo-mgr.log"; string defaultLogLevel = config["Logging:LogLevel:Default"] ?? "Information"; // Parse to LogEventLevel if(!Enum.TryParse(defaultLogLevel, true, out LogEventLevel level)) { // Fallback if parsing fails #if DEBUG level = LogEventLevel.Debug; #else level = LogEventLevel.Information; #endif } // Now create a logger with the specified log level and log file Log.Logger = new LoggerConfiguration() #if DEBUG .MinimumLevel.Debug() #else .MinimumLevel.Information() #endif .WriteTo.Console() .WriteTo.File(logFile, rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 10 * 1048576) .Enrich.FromLogContext() .CreateLogger(); // Read the rest of the configuration and settings Log.Debug("Reading configuration settings..."); string repoFolder = config["DataFolders:Repository"] ?? "repo"; string importRoms = config["DataFolders:ImportRoms"] ?? "incoming"; string importDats = config["DataFolders:ImportDats"] ?? "incoming-dats"; string exportRoms = config["DataFolders:ExportRoms"] ?? "export"; string exportDats = config["DataFolders:ExportDats"] ?? "export-dats"; string databaseFolder = config["DataFolders:Database"] ?? "db"; string temporaryFolder = config["DataFolders:Temporary"] ?? "tmp"; string compressionTypeString = config["CompressionType"] ?? "Zstd"; // Parse the compression type if(!Enum.TryParse(compressionTypeString, true, out CompressionType compressionType)) { // Fallback if parsing fails compressionType = CompressionType.Zstd; } // Ensure the folders exist Log.Information("Ensuring folders exist..."); string[] folders = [repoFolder, importRoms, importDats, databaseFolder, exportRoms, exportDats, temporaryFolder]; foreach(string folder in folders) { // Check File.Exists for symlinks or junctions if(!Directory.Exists(folder) && !File.Exists(folder)) { Log.Debug("Creating folder: {Folder}", folder); Directory.CreateDirectory(folder); } else Log.Debug("Folder already exists: {Folder}", folder); } // ✅ Plug Serilog into the host builder.Host.UseSerilog(); // Add services to the container. builder.Services.AddRazorComponents().AddInteractiveServerComponents(); builder.Services.AddFluentUIComponents(); // Localization builder.Services.AddLocalization(); Log.Debug("Creating database context..."); builder.Services.AddDbContextFactory(options => { options.UseSqlite($"Data Source={databaseFolder}/database.db"); #if DEBUG options.EnableSensitiveDataLogging(); options.LogTo(Log.Debug); #else options.LogTo(Log.Information, LogLevel.Information); #endif }); builder.Services.AddDataGridEntityFrameworkAdapter(); Log.Debug("Setting the settings..."); Settings.Current = new SetSettings { DatabasePath = Path.Combine(Environment.CurrentDirectory, databaseFolder, "database.db"), TemporaryFolder = Path.Combine(Environment.CurrentDirectory, temporaryFolder), RepositoryPath = Path.Combine(Environment.CurrentDirectory, repoFolder), UseInternalDecompressor = true, Compression = compressionType }; Log.Debug("Building the application..."); WebApplication app = builder.Build(); // Configure the HTTP request pipeline. if(!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", true); // 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.UseAntiforgery(); app.MapStaticAssets(); app.MapRazorComponents().AddInteractiveServerRenderMode(); // Localization string[] supportedCultures = ["en", "es"]; RequestLocalizationOptions localizationOptions = new RequestLocalizationOptions().SetDefaultCulture("en") .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions); Stopwatch stopwatch = new(); using(IServiceScope scope = app.Services.CreateScope()) { IServiceProvider services = scope.ServiceProvider; try { Log.Information("Updating the database..."); stopwatch.Start(); Context dbContext = services.GetRequiredService(); await dbContext.Database.MigrateAsync(); stopwatch.Stop(); Log.Debug("Database migration: {Elapsed} seconds", stopwatch.Elapsed.TotalSeconds); } catch(Exception ex) { Log.Error(ex, "An error occurred while updating the database"); return; } } Log.Debug("Running the application..."); app.Run();