Files
EngineeringSync/EngineeringSync.Service/Program.cs

152 lines
5.9 KiB
C#
Raw Normal View History

using System.Text.Json;
using EngineeringSync.Infrastructure;
using EngineeringSync.Service.Api;
using EngineeringSync.Service.Hubs;
using EngineeringSync.Service.Services;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService();
// Datenbankpfad: neben der .exe oder im AppData-Ordner (dev: aktuelles Verzeichnis)
var dbPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"EngineeringSync", "engineeringsync.db");
Directory.CreateDirectory(Path.GetDirectoryName(dbPath)!);
builder.Services.AddInfrastructure(dbPath);
builder.Services.AddSignalR();
builder.Services.AddSingleton<WatcherService>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<WatcherService>());
builder.Services.AddSingleton<SyncManager>();
// Kestrel nur auf localhost binden (kein öffentlicher Port)
builder.WebHost.UseUrls("http://localhost:5050");
var app = builder.Build();
// Datenbankmigrationen beim Start
await using (var scope = app.Services.CreateAsyncScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await db.Database.MigrateAsync();
// WAL-Modus aktivieren (muss nach dem Öffnen der DB gesetzt werden)
await db.Database.ExecuteSqlRawAsync("PRAGMA journal_mode=WAL;");
// First-Run-Config laden (falls vorhanden)
var watcher = scope.ServiceProvider.GetRequiredService<WatcherService>();
await ProcessFirstRunConfigAsync(db, watcher);
}
async Task ProcessFirstRunConfigAsync(AppDbContext db, WatcherService watcher)
{
var configPath = Path.Combine(AppContext.BaseDirectory, "firstrun-config.json");
if (!File.Exists(configPath))
return;
try
{
var json = await File.ReadAllTextAsync(configPath);
var root = JsonDocument.Parse(json);
var firstRunElement = root.RootElement.GetProperty("FirstRun");
var projectName = firstRunElement.GetProperty("ProjectName").GetString() ?? "Imported Project";
var engineeringPath = firstRunElement.GetProperty("EngineeringPath").GetString() ?? "";
var simulationPath = firstRunElement.GetProperty("SimulationPath").GetString() ?? "";
var fileExtensionsRaw = firstRunElement.GetProperty("FileExtensions").GetString() ?? "";
var watchAllFiles = firstRunElement.TryGetProperty("WatchAllFiles", out var watchAllElement)
? watchAllElement.GetBoolean()
: false;
// Wenn WatchAllFiles=true oder FileExtensions="*", dann leerer String (alle Dateien)
var fileExtensions = (watchAllFiles || fileExtensionsRaw == "*") ? "" : fileExtensionsRaw;
// Backup-Einstellungen (optional, mit Standardwerten für Rückwärtskompatibilität)
var backupEnabled = true;
string? backupPath = null;
var maxBackupsPerFile = 0;
if (root.RootElement.TryGetProperty("Backup", out var backupElement))
{
if (backupElement.TryGetProperty("BackupEnabled", out var be))
backupEnabled = be.GetBoolean();
if (backupElement.TryGetProperty("BackupPath", out var bp) &&
bp.ValueKind != JsonValueKind.Null)
backupPath = bp.GetString();
if (backupElement.TryGetProperty("MaxBackupsPerFile", out var mb))
maxBackupsPerFile = mb.GetInt32();
}
// Nur erstellen, wenn die Verzeichnisse existieren
if (!Directory.Exists(engineeringPath) || !Directory.Exists(simulationPath))
{
System.Console.WriteLine(
$"[FirstRunConfig] WARNUNG: Engineering- oder Simulations-Pfad existiert nicht. " +
$"Engineering={engineeringPath}, Simulation={simulationPath}");
return;
}
// Prüfen: Existiert bereits ein Projekt mit diesem Namen?
var existingProject = await db.Projects
.FirstOrDefaultAsync(p => p.Name == projectName);
if (existingProject != null)
{
System.Console.WriteLine(
$"[FirstRunConfig] Projekt '{projectName}' existiert bereits. Überspringe Import.");
return;
}
// Neue ProjectConfig erstellen
var project = new EngineeringSync.Domain.Entities.ProjectConfig
{
Name = projectName,
EngineeringPath = engineeringPath,
SimulationPath = simulationPath,
FileExtensions = fileExtensions,
IsActive = true,
CreatedAt = DateTime.UtcNow,
BackupEnabled = backupEnabled,
BackupPath = backupPath,
MaxBackupsPerFile = maxBackupsPerFile
};
db.Projects.Add(project);
await db.SaveChangesAsync();
System.Console.WriteLine(
$"[FirstRunConfig] Projekt '{projectName}' wurde importiert und aktiviert. " +
$"FileExtensions='{fileExtensions}'");
// Initialer Scan: Unterschiede zwischen Engineering- und Simulations-Ordner erkennen
try { await watcher.ScanExistingFilesAsync(project); }
catch (Exception ex)
{
System.Console.WriteLine(
$"[FirstRunConfig] FEHLER beim initialen Scan für '{projectName}': {ex.Message}");
}
// Konfigurationsdatei umbenennen, damit sie beim nächsten Start nicht wieder verarbeitet wird
// (WatcherService.ExecuteAsync lädt das Projekt automatisch aus der DB beim Host-Start)
var processedPath = configPath + ".processed";
if (File.Exists(processedPath))
File.Delete(processedPath);
File.Move(configPath, processedPath);
System.Console.WriteLine($"[FirstRunConfig] Konfigurationsdatei verarbeitet: {configPath} → {processedPath}");
}
catch (Exception ex)
{
System.Console.WriteLine(
$"[FirstRunConfig] FEHLER beim Verarbeiten der Erstkonfiguration: {ex.Message}");
}
}
app.MapHub<NotificationHub>("/notifications");
app.MapProjectsApi();
app.MapChangesApi();
app.Run();