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 match = _endpoints.Endpoints
.Where(e =>
e.SupportsHost(EndpointHostTarget.Pc) &&
string.Equals(e.HttpMethod, method, StringComparison.OrdinalIgnoreCase))
.Select(e => new
{
Endpoint = e,
IsMatched = ServiceEndpointPatternMatcher.TryMatch(e.Pattern, path, out var routeValues),
RouteValues = routeValues,
})
.FirstOrDefault(candidate => candidate.IsMatched);
var endpoint = match?.Endpoint;
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),
RouteValues = match!.RouteValues,
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);
}
}
}