Files

174 lines
7.5 KiB
C#
Raw Permalink Normal View History

using EngineeringSync.Domain.Constants;
using EngineeringSync.Domain.Entities;
using EngineeringSync.Infrastructure;
using EngineeringSync.Service.Hubs;
using EngineeringSync.Service.Models;
using EngineeringSync.Service.Services;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
namespace EngineeringSync.Service.Api;
public static class ProjectsApi
{
public static IEndpointRouteBuilder MapProjectsApi(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/projects");
group.MapGet("/", async (IDbContextFactory<AppDbContext> dbFactory) =>
{
await using var db = await dbFactory.CreateDbContextAsync();
var projects = await db.Projects.OrderBy(p => p.Name).ToListAsync();
return Results.Ok(projects);
});
group.MapGet("/{id:guid}", async (Guid id, IDbContextFactory<AppDbContext> dbFactory) =>
{
await using var db = await dbFactory.CreateDbContextAsync();
var project = await db.Projects.FindAsync(id);
return project is null ? Results.NotFound() : Results.Ok(project);
});
group.MapPost("/", async (CreateProjectRequest req, IDbContextFactory<AppDbContext> dbFactory,
WatcherService watcher, IHubContext<NotificationHub> hubContext, ILoggerFactory loggerFactory) =>
{
var logger = loggerFactory.CreateLogger("ProjectsApi");
if (!Directory.Exists(req.EngineeringPath))
return Results.BadRequest($"Engineering-Pfad existiert nicht: {req.EngineeringPath}");
if (!Directory.Exists(req.SimulationPath))
return Results.BadRequest($"Simulations-Pfad existiert nicht: {req.SimulationPath}");
await using var db = await dbFactory.CreateDbContextAsync();
var project = new ProjectConfig
{
Name = req.Name,
EngineeringPath = req.EngineeringPath,
SimulationPath = req.SimulationPath,
FileExtensions = req.FileExtensions,
IsActive = req.IsActive,
BackupEnabled = req.BackupEnabled,
BackupPath = req.BackupPath,
MaxBackupsPerFile = req.MaxBackupsPerFile
};
db.Projects.Add(project);
await db.SaveChangesAsync();
await watcher.StartWatchingAsync(project);
_ = Task.Run(async () =>
{
try { await watcher.ScanExistingFilesAsync(project); }
catch (Exception ex) { logger.LogError(ex, "Fehler beim initialen Scan für Projekt {Id}", project.Id); }
});
await hubContext.Clients.All.SendAsync(HubMethodNames.ProjectConfigChanged, CancellationToken.None);
return Results.Created($"/api/projects/{project.Id}", project);
});
group.MapPut("/{id:guid}", async (Guid id, UpdateProjectRequest req,
IDbContextFactory<AppDbContext> dbFactory, WatcherService watcher, IHubContext<NotificationHub> hubContext,
ILoggerFactory loggerFactory) =>
{
var logger = loggerFactory.CreateLogger("ProjectsApi");
await using var db = await dbFactory.CreateDbContextAsync();
var project = await db.Projects.FindAsync(id);
if (project is null) return Results.NotFound();
if (!Directory.Exists(req.EngineeringPath))
return Results.BadRequest($"Engineering-Pfad existiert nicht: {req.EngineeringPath}");
if (!Directory.Exists(req.SimulationPath))
return Results.BadRequest($"Simulations-Pfad existiert nicht: {req.SimulationPath}");
project.Name = req.Name;
project.EngineeringPath = req.EngineeringPath;
project.SimulationPath = req.SimulationPath;
project.FileExtensions = req.FileExtensions;
project.IsActive = req.IsActive;
project.BackupEnabled = req.BackupEnabled;
project.BackupPath = req.BackupPath;
project.MaxBackupsPerFile = req.MaxBackupsPerFile;
await db.SaveChangesAsync();
// Watcher neu starten (stoppt automatisch den alten)
await watcher.StartWatchingAsync(project);
_ = Task.Run(async () =>
{
try { await watcher.ScanExistingFilesAsync(project); }
catch (Exception ex) { logger.LogError(ex, "Fehler beim initialen Scan für Projekt {Id}", project.Id); }
});
await hubContext.Clients.All.SendAsync(HubMethodNames.ProjectConfigChanged, CancellationToken.None);
return Results.Ok(project);
});
group.MapDelete("/{id:guid}", async (Guid id, IDbContextFactory<AppDbContext> dbFactory,
WatcherService watcher, IHubContext<NotificationHub> hubContext) =>
{
await using var db = await dbFactory.CreateDbContextAsync();
var project = await db.Projects.FindAsync(id);
if (project is null) return Results.NotFound();
await watcher.StopWatchingAsync(id);
db.Projects.Remove(project);
await db.SaveChangesAsync();
await hubContext.Clients.All.SendAsync(HubMethodNames.ProjectConfigChanged, CancellationToken.None);
return Results.NoContent();
});
group.MapGet("/scan", async (string engineeringPath, string simulationPath, string fileExtensions) =>
{
if (!Directory.Exists(engineeringPath))
return Results.BadRequest($"Engineering-Pfad existiert nicht: {engineeringPath}");
if (!Directory.Exists(simulationPath))
return Results.BadRequest($"Simulations-Pfad existiert nicht: {simulationPath}");
var extensions = string.IsNullOrWhiteSpace(fileExtensions) || fileExtensions == "*"
? new HashSet<string>()
: fileExtensions.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var scanAll = extensions.Count == 0;
var engFiles = scanAll
? Directory.EnumerateFiles(engineeringPath, "*", SearchOption.AllDirectories).ToList()
: Directory.EnumerateFiles(engineeringPath, "*", SearchOption.AllDirectories)
.Where(f => extensions.Contains(Path.GetExtension(f)))
.ToList();
var results = new List<ScanResultEntry>();
foreach (var engFile in engFiles)
{
var relativePath = Path.GetRelativePath(engineeringPath, engFile);
var simFile = Path.Combine(simulationPath, relativePath);
var engInfo = new FileInfo(engFile);
var engHash = await FileHasher.ComputeAsync(engFile);
var existsInSim = File.Exists(simFile);
var needsSync = !existsInSim;
if (existsInSim)
{
var simHash = await FileHasher.ComputeAsync(simFile);
needsSync = engHash != simHash;
}
if (needsSync)
{
results.Add(new ScanResultEntry(
relativePath,
existsInSim ? "Modified" : "Created",
engInfo.Length,
engInfo.LastWriteTimeUtc
));
}
}
return Results.Ok(results);
});
return app;
}
}