using Avalonia_Services.Core; namespace Avalonia_Services.Extensions { /// /// Desktop (Avalonia-PC) 端点适配器。 /// 将统一端点转换为桌面端可用的路由处理器,支持过滤器和鉴权管道。 /// public class DesktopEndpointAdapter { /// /// 统一端点集合。 /// private readonly ServiceEndpointCollection _endpoints; /// /// 鉴权服务。 /// private readonly IAuthService _authService; /// /// DI 服务提供程序。 /// private readonly IServiceProvider _serviceProvider; /// /// 匹配后的路由结果(与原有 RouteDispatchResult 兼容)。 /// public class RouteResult { /// /// 获取是否匹配到路由。 /// public bool IsMatched { get; init; } /// /// 获取 HTTP 状态码。 /// public int StatusCode { get; init; } = 200; /// /// 获取状态描述文本。 /// public string StatusMessage { get; init; } = ""; /// /// 获取响应数据。 /// public object? Data { get; init; } /// /// 获取响应头字典。 /// public Dictionary ResponseHeaders { get; init; } = new(); /// /// 创建成功响应结果。 /// /// 响应数据。 /// 端点上下文。 /// 路由结果。 public static RouteResult Success(object? data, ServiceEndpointContext ctx) { return new RouteResult { IsMatched = true, StatusCode = ctx.StatusCode, StatusMessage = ctx.StatusMessage, Data = data, ResponseHeaders = new Dictionary(ctx.ResponseHeaders, StringComparer.OrdinalIgnoreCase), }; } /// /// 创建 404 未找到响应。 /// /// 表示未匹配的路由结果。 public static RouteResult NotFound() => new() { IsMatched = false, StatusCode = 404, StatusMessage = "Not Found", }; } /// /// 初始化桌面端点适配器。 /// /// 端点集合。 /// 鉴权服务。 /// DI 服务提供程序。 public DesktopEndpointAdapter( ServiceEndpointCollection endpoints, IAuthService authService, IServiceProvider serviceProvider) { _endpoints = endpoints; _authService = authService; _serviceProvider = serviceProvider; } /// /// 处理来自前端(WebView2 Bridge)的请求。 /// /// 规范化路径,如 "api/wData" /// HTTP 方法 /// 请求体字符串 /// 请求头字典 /// 查询参数字典 public async Task HandleRequestAsync( string path, string method, string? body, Dictionary? headers = null, Dictionary? query = null) { // 查找匹配的端点(忽略大小写 + 方法匹配) var endpoint = _endpoints.Endpoints.FirstOrDefault(e => e.SupportsHost(EndpointHostTarget.Pc) && string.Equals(e.Pattern, path, StringComparison.OrdinalIgnoreCase) && string.Equals(e.HttpMethod, method, StringComparison.OrdinalIgnoreCase)); if (endpoint is null) { return RouteResult.NotFound(); } // 构建上下文 var ctx = new ServiceEndpointContext { Path = path, Method = method, Body = body, Headers = headers ?? new Dictionary(StringComparer.OrdinalIgnoreCase), Query = query ?? new Dictionary(StringComparer.OrdinalIgnoreCase), Items = { ["ServiceProvider"] = _serviceProvider }, }; try { // 1. 鉴权检查 if (endpoint.RequireAuthorization) { var user = await _authService.AuthenticateAsync(ctx); if (user is null) { ctx.StatusCode = 401; ctx.StatusMessage = "Unauthorized"; ctx.ResponseBody = new { success = false, error = "Unauthorized" }; return RouteResult.Success(ctx.ResponseBody, ctx); } if (endpoint.Roles.Count > 0) { var authorized = await _authService.AuthorizeAsync(user, $"roles:{string.Join(',', endpoint.Roles)}"); if (!authorized) { ctx.StatusCode = 403; ctx.StatusMessage = "Forbidden"; ctx.ResponseBody = new { success = false, error = "Forbidden" }; return RouteResult.Success(ctx.ResponseBody, ctx); } } else if (!string.IsNullOrEmpty(endpoint.Policy)) { var authorized = await _authService.AuthorizeAsync(user, endpoint.Policy); if (!authorized) { ctx.StatusCode = 403; ctx.StatusMessage = "Forbidden"; ctx.ResponseBody = new { success = false, error = "Forbidden" }; return RouteResult.Success(ctx.ResponseBody, ctx); } } ctx.Items["User"] = user; } // 2. 构建过滤管道:全局过滤器 → 端点过滤器 → 处理器 var pipeline = BuildPipeline(endpoint); // 3. 执行管道 await pipeline(ctx); return RouteResult.Success(ctx.ResponseBody, ctx); } catch (Exception ex) { ctx.StatusCode = 500; ctx.StatusMessage = "Internal Server Error"; ctx.ResponseBody = new { success = false, error = ex.Message }; return RouteResult.Success(ctx.ResponseBody, ctx); } } /// /// 构建过滤管道(全局过滤器 + 端点过滤器 → 端点处理器)。 /// private EndpointFilterDelegate BuildPipeline(ServiceEndpoint endpoint) { // 最内层:端点处理器 EndpointFilterDelegate handler = async (ctx) => { ctx.ResponseBody = await endpoint.Handler(ctx); }; // 先包裹端点专属过滤器(后注册的先执行) var filters = new List(); filters.AddRange(_endpoints.GlobalFilters); filters.AddRange(endpoint.Filters); for (int i = filters.Count - 1; i >= 0; i--) { var filter = filters[i]; var next = handler; handler = (ctx) => filter.InvokeAsync(ctx, next); } return handler; } } /// /// Desktop 端的辅助扩展。不依赖 IServiceCollection(由宿主项目自行完成 DI 注册)。 /// public static class DesktopServiceExtensions { /// /// 快速构建 DesktopEndpointAdapter(用于非 DI 场景如 MainWindow)。 /// public static DesktopEndpointAdapter CreateAdapter( this ServiceEndpointCollection endpoints, IServiceProvider serviceProvider) { var auth = (serviceProvider.GetService(typeof(IAuthService)) as IAuthService) ?? new AnonymousAuthService(); return new DesktopEndpointAdapter(endpoints, auth, serviceProvider); } } }