using FileShare_Common.Core; using FileShare_Services.Core; using FileShare_Services.Services.FileLibrary; using FileShare_Services.Services.QrCode; namespace FileShare_Services.Endpoints { /// /// 统一端点配置 —— 所有业务端点在此定义一次。 /// 这是 FileShare-API 和 FileShare-PC 的唯一入口。 /// public static class AppEndpoints { /// /// 配置所有业务端点。调用方传入 builder,按需叠加鉴权、过滤器等。 /// /// 端点构建器 /// 是否在错误响应中包含异常详情(开发环境 true) public static ServiceEndpointBuilder Configure(ServiceEndpointBuilder builder, bool includeDetails = false) { // ---- 全局异常拦截(自动捕获所有端点中未处理的异常) ---- builder.Endpoints.AddGlobalFilter(new GlobalExceptionFilter(includeDetails)); builder.ConfigureEndpoints(endpoints => { // ---- 全局日志过滤器(记录每个请求) ---- endpoints.AddGlobalFilter(async (ctx, next) => { Serilog.Log.Information("→ {Method} {Path}", ctx.Method, ctx.Path); await next(ctx); Serilog.Log.Information("← {Method} {Path} | {StatusCode}", ctx.Method, ctx.Path, ctx.StatusCode); }); // ---- 业务端点注册 ---- endpoints.MapGet("api/library/drives", (service, ctx) => service.GetDrivesAsync(ctx)) .WithOpenApi("FileLibrary", "查询服务器磁盘。") .WithName("GetLibraryDrives"); endpoints.MapGet("api/library/directories", (service, request, _) => service.GetDirectoriesAsync(request)) .WithOpenApi("FileLibrary", "查询服务器目录。") .WithName("GetLibraryDirectories"); endpoints.MapGet("api/library/roots", (service, ctx) => service.GetRootsAsync(ctx)) .WithOpenApi("FileLibrary", "查询文件库目录。") .WithName("GetLibraryRoots"); endpoints.MapPost("api/library/roots", (service, request, _) => service.AddRootAsync(request)) .WithOpenApi("FileLibrary", "添加文件库目录。") .WithName("AddLibraryRoot"); endpoints.MapPost("api/library/roots/enabled", (service, request, _) => service.SetRootEnabledAsync(request)) .WithOpenApi("FileLibrary", "启用或禁用文件库目录。") .WithName("SetLibraryRootEnabled"); endpoints.MapPost("api/library/roots/delete", (service, request, _) => service.DeleteRootAsync(request)) .WithOpenApi("FileLibrary", "删除文件库目录。") .WithName("DeleteLibraryRoot"); endpoints.MapPost("api/library/roots/scan", (service, request, _) => service.ScanRootAsync(request)) .WithOpenApi("FileLibrary", "立即扫描文件库目录。") .WithName("ScanLibraryRoot"); endpoints.MapGet("api/files", (service, request, _) => service.SearchFilesAsync(request)) .WithOpenApi("FileLibrary", "分页查询已扫描文件。") .WithName("SearchFiles"); endpoints.MapGet("api/files/browse", (service, request, _) => service.BrowseDirectoryAsync(request)) .WithOpenApi("FileLibrary", "浏览文件库目录结构。") .WithName("BrowseDirectory"); endpoints.MapGet("api/files/recent", (service, request, _) => service.GetRecentFilesAsync(request)) .WithOpenApi("FileLibrary", "获取最近添加或最近播放的文件。") .WithName("GetRecentFiles"); endpoints.MapPost("api/files/played", (service, request, _) => service.MarkFilePlayedAsync(request)) .WithOpenApi("FileLibrary", "标记文件已播放。") .WithName("MarkFilePlayed"); endpoints.MapGet("api/files/detail", (service, request, _) => service.GetFileAsync(request)) .WithOpenApi("FileLibrary", "查询文件详情。") .WithName("GetFileDetail"); endpoints.MapGet("api/files/text", (service, request, _) => service.GetTextPreviewAsync(request)) .WithOpenApi("FileLibrary", "预览文本文件。") .WithName("GetTextPreview"); endpoints.MapGet("api/files/stream", GetFileStreamAsync) .WithOpenApi("FileLibrary", "流式传输文件(支持 Range 请求)。") .WithName("StreamManagedFile"); endpoints.MapGet("api/qrcode", (service, ctx) => service.GenerateQrCodeAsync(ctx)) .WithOpenApi("Utility", "生成局域网访问二维码。") .WithName("GetQrCode"); // ---- 需要鉴权的端点示例 ---- // endpoints.MapGet("api/admin/dashboard", AdminDashboardAsync) // .WithName("AdminDashboard") // .RequireAuthorization = true // .Policy = "AdminOnly"; }); return builder; } #region 业务处理方法 /// /// 从 中解析 , /// 读取查询参数中的文件 ID,返回文件流响应。 /// /// 端点上下文。 /// 文件流响应对象,服务不可用或 ID 无效时返回 null。 private static async Task GetFileStreamAsync(ServiceEndpointContext ctx) { var sp = ctx.Items["ServiceProvider"] as IServiceProvider; var service = sp?.GetService(typeof(IFileStreamService)) as IFileStreamService; if (service is null) return null; if (!int.TryParse(ctx.Query.GetValueOrDefault("id"), out var id) || id <= 0) return null; return await service.GetFileStreamAsync(id); } #endregion } }