LANCommander/LANCommander.Server/Startup/Database.cs
Pat Hartl add770b227 Refactor Settings
Settings for the server are now combined with the settings from the SDK. This introduces a large breaking change and a migration should be created. This refactor utilizes .NET Configuration and the Options pattern. This will allow for the overriding of any setting using envionment variables. It also means that Settings.yml can be used to override any .NET configuration. A SettingsProvider implementation was created, and any updating of settings was changed from SettingsService.SaveSettings() to SettingsProvider.Update(s => { ... })
2025-11-16 12:31:25 -06:00

105 lines
No EOL
4.7 KiB
C#

using LANCommander.SDK.Enums;
using LANCommander.Server.Data;
using LANCommander.Server.Data.Enums;
using LANCommander.Server.Data.Models;
using LANCommander.Server.Services;
using LANCommander.Server.Services.Models;
using LANCommander.Server.Settings.Enums;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Octokit;
using Serilog;
namespace LANCommander.Server.Startup;
public static class Database
{
public static WebApplicationBuilder AddDatabase(this WebApplicationBuilder builder, string[] args)
{
var settings = new Settings.Settings();
builder.Configuration.Bind(settings);
builder.Services.AddDbContextFactory<DatabaseContext>();
builder.Services.AddDbContext<DatabaseContext>();
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var databaseProviderParameter = args.FirstOrDefault(arg => arg.StartsWith("--database-provider="))?.Split('=', 2).Last();
var connectionStringParameter = args.FirstOrDefault(arg => arg.StartsWith("--connection-string="))?.Split('=', 2).Last();
if (!String.IsNullOrWhiteSpace(databaseProviderParameter))
DatabaseContext.Provider = Enum.Parse<DatabaseProvider>(databaseProviderParameter);
else
DatabaseContext.Provider = settings.Server.Database.Provider;
if (!String.IsNullOrWhiteSpace(connectionStringParameter))
DatabaseContext.ConnectionString = connectionStringParameter;
else
DatabaseContext.ConnectionString = settings.Server.Database.ConnectionString;
return builder;
}
public static async Task MigrateDatabaseAsync(this WebApplication app)
{
if (DatabaseContext.Provider != DatabaseProvider.Unknown)
{
using var scope = app.Services.CreateAsyncScope();
using var db = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
var settingsProvider = scope.ServiceProvider.GetRequiredService<SettingsProvider<Settings.Settings>>();
logger.LogDebug("Migrating database if required");
if ((await db.Database.GetPendingMigrationsAsync()).Any())
{
if (DatabaseContext.Provider == DatabaseProvider.SQLite)
{
var dataSource = new SqliteConnectionStringBuilder(settingsProvider.CurrentValue.Server.Database.ConnectionString).DataSource;
var backupName = Path.Combine("Backups", $"LANCommander.db.{DateTime.Now.ToString("dd-MM-yyyy-HH.mm.ss.bak")}");
if (File.Exists(dataSource))
{
Log.Information("Migrations pending, database will be backed up to {BackupName}", backupName);
File.Copy(dataSource, backupName);
}
}
await db.Database.MigrateAsync();
var storageLocationService = scope.ServiceProvider.GetRequiredService<StorageLocationService>();
var archiveLocation = await storageLocationService.AddMissingAsync(l => l.Type == StorageLocationType.Archive && l.Default, new StorageLocation
{
Path = "Uploads",
Type = StorageLocationType.Archive,
Default = true,
});
if (!Directory.Exists(archiveLocation.Value.Path))
Directory.CreateDirectory(archiveLocation.Value.Path);
var mediaLocation = await storageLocationService.AddMissingAsync(l => l.Type == StorageLocationType.Media && l.Default, new StorageLocation
{
Path = "Media",
Type = StorageLocationType.Media,
Default = true,
});
if (!Directory.Exists(mediaLocation.Value.Path))
Directory.CreateDirectory(mediaLocation.Value.Path);
var saveLocation = await storageLocationService.AddMissingAsync(l => l.Type == StorageLocationType.Save && l.Default, new StorageLocation
{
Path = "Saves",
Type = StorageLocationType.Save,
Default = true,
});
if (!Directory.Exists(saveLocation.Value.Path))
Directory.CreateDirectory(saveLocation.Value.Path);
}
else
logger.LogDebug("No pending migrations are available. Skipping database migration.");
}
}
}