XFEExtension.NetCore.ServerInteractive
[DLL] Server interaction extension, including user identity verification and querying in conjunction with AutoConfig
关注
0
Fork
0
Star
0
using System.Diagnostics;
using System.Net;
using System.Collections.Frozen;
using XFEExtension.NetCore.AutoImplement;
using XFEExtension.NetCore.CyberComm;
using XFEExtension.NetCore.DelegateExtension;
using XFEExtension.NetCore.ServerInteractive.Exceptions;
using XFEExtension.NetCore.ServerInteractive.Implements.ServerService;
using XFEExtension.NetCore.ServerInteractive.Interfaces.CoreService;
using XFEExtension.NetCore.ServerInteractive.Models.ServerModels;
using XFEExtension.NetCore.ServerInteractive.Utilities.Helpers;
using XFEExtension.NetCore.StringExtension;
using XFEExtension.NetCore.XFETransform.Json;
namespace XFEExtension.NetCore.ServerInteractive.Utilities.Server;
/// <summary>
/// XFE服务器核心
/// </summary>
[CreateImpl]
public abstract class XFEServerCore : ServerCoreServiceBase
{
/// <summary>
/// 是否接收非标准的Json字符串
/// </summary>
public bool AcceptNonStandardJson { get; set; } = true;
/// <summary>
/// 是否接收GET请求
/// </summary>
public bool AcceptGet { get; set; }
/// <summary>
/// 是否接收POST请求
/// </summary>
public bool AcceptPost { get; set; } = true;
/// <summary>
/// 服务器核心错误委托
/// </summary>
public XFEEventHandler<XFEServerCore, ServerCoreErrorEventArgs>? ServerCoreError { get; set; }
/// <summary>
/// 获取IP地址的函数,默认为从请求事件参数中获取客户端IP地址
/// </summary>
public Func<CyberCommRequestEventArgs, string> GetIPFunction { get; set; } = args => args.ClientIP;
/// <summary>
/// 主入口点路径(ServerCore主要入口点),默认为空字符串(为空时直接使用次级入口点)。
/// 多个核心服务器绑定同一端口时,使用不同的主入口点区分核心服务器。
/// </summary>
public string MainEntryPoint { get; set; } = string.Empty;
/// <summary>
/// 核心服务列表
/// </summary>
internal readonly List<IServerCoreOriginalService> ServerCoreServiceList = [];
/// <summary>
/// 核心校验服务列表
/// </summary>
internal IReadOnlyList<Func<IServerCoreVerifyService>> ServerCoreVerifyServiceList = [];
/// <summary>
/// 核心标准服务工厂字典(按路由路径创建实例)
/// </summary>
internal IReadOnlyDictionary<string, Func<IServerCoreStandardService>> StandardCoreServiceDictionary = FrozenDictionary<string, Func<IServerCoreStandardService>>.Empty;
/// <summary>
/// 通配符路由服务工厂列表(模式 → 工厂)
/// </summary>
internal IReadOnlyList<(string Pattern, Func<IServerCoreStandardService> Factory)> WildcardCoreServiceList = [];
/// <summary>
/// 禁用框架请求日志的入口点路径或通配符模式集合
/// </summary>
internal IReadOnlySet<string> NoLogEntryPointSet = FrozenSet<string>.Empty;
/// <summary>
/// 网络通讯服务器
/// </summary>
public CyberCommServer CyberCommServer { get; internal set; } = new();
/// <summary>底层 CyberComm 限制。</summary>
public CyberCommLimitOptions TransportLimits { get; internal set; } = new();
/// <summary>底层 TLS 配置。</summary>
public CyberCommTlsOptions? TlsOptions { get; internal set; }
/// <summary>
/// 当前核心所属的共享监听主机。
/// </summary>
internal XFEServerCoreHost? ServerCoreHost { get; set; }
/// <summary>
/// 主入口点包含的路径段数量。
/// </summary>
internal int MainEntryPointSegmentCount => GetEntryPointSegments(MainEntryPoint).Count;
/// <summary>
/// 处理已经由共享监听主机分发到当前核心的请求。
/// </summary>
internal async Task ProcessRequest(CyberCommRequestEventArgs e, CancellationToken cancellationToken = default)
{
var r = new ServerCoreReturnArgs
{
Args = e,
ServerCore = this
};
try
{
cancellationToken.ThrowIfCancellationRequested();
var clientIP = e.ClientIP;
try { clientIP = GetIPFunction(e); } catch (Exception ex) { Console.WriteLine($"[WARN]获取IP地址失败:{ex.Message}"); }
r.ClientIP = clientIP;
// 在校验日志产生前解析并匹配入口点,以便 [NoLog] 能关闭完整的框架请求日志。
string route;
Func<IServerCoreStandardService>? serviceFactory;
string? matchedPattern;
try
{
var url = e.RequestUrl;
if (url is null)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("请求URL为空")
});
return;
}
if (!TryGetRoute(url, out route))
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException($"请求路径不匹配主入口点: {MainEntryPoint}")
});
return;
}
if (route.IsNullOrEmpty())
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("请求路由为空")
});
return;
}
TryResolveService(route, out serviceFactory, out matchedPattern);
r.SuppressLog = matchedPattern is not null && NoLogEntryPointSet.Contains(matchedPattern);
}
catch (Exception ex)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.InternalServerError,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("解析请求路由时发生异常", ex)
});
return;
}
try
{
foreach (var serverCoreVerifyService in ServerCoreVerifyServiceList.Select(serverCoreVerifyFactory => serverCoreVerifyFactory()))
{
cancellationToken.ThrowIfCancellationRequested();
serverCoreVerifyService.ReturnArgs = r;
serverCoreVerifyService.Args = e;
if (!serverCoreVerifyService.VerifyRequest() || !await serverCoreVerifyService.VerifyRequestAsync().ConfigureAwait(false))
{
if (e.Context is not null && !e.Context.Response.IsCompleted)
await e.ReplyAndClose("请求未通过验证", r.StatusCode == HttpStatusCode.InternalServerError ? HttpStatusCode.Forbidden : r.StatusCode).ConfigureAwait(false);
return;
}
}
}
catch (Exception ex)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = r.StatusCode,
Handled = r.Handled,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("请求校验失败", ex)
});
return;
}
// 从URL路径中提取路由信息
XFEJsonNode? queryableJsonNode = null;
try
{
// 尝试解析请求体为JSON(可选)
if (e.RequestBody is not null)
{
queryableJsonNode = e.RequestBody;
}
}
catch (Exception ex)
{
if (!AcceptNonStandardJson)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("无法解析 JSON 请求体", ex)
});
return;
}
}
try
{
Stopwatch? stopWatch = null;
if (!r.SuppressLog)
{
Console.Write($"[{e.CorrelationId}]({ServerCoreName})【{clientIP}】请求路由-{route}:");
stopWatch = Stopwatch.StartNew();
}
if (serviceFactory is not null && matchedPattern is not null)
{
var serviceInstance = serviceFactory();
try
{
serviceInstance.XFEServerCore = this;
serviceInstance.Route = route;
serviceInstance.Json = queryableJsonNode;
serviceInstance.Args = e;
serviceInstance.ReturnArgs = r;
serviceInstance.Initialize();
// 根据匹配的模式调用对应的处理方法(同步与异步互斥,优先同步)
if (serviceInstance.SyncEntryPoints.TryGetValue(matchedPattern, out var syncHandler))
syncHandler();
else if (serviceInstance.AsyncEntryPoints.TryGetValue(matchedPattern, out var asyncHandler))
await asyncHandler().WaitAsync(cancellationToken).ConfigureAwait(false);
else
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.NotFound,
ReturnArgs = r,
ServerException = new ExecutionUnregisteredException($"服务已注册但路由未找到对应处理方法-{route}")
});
}
}
catch (Exception ex)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = r.StatusCode,
Handled = r.Handled,
ReturnArgs = r,
ServerException = new XFEServerCoreRequestInnerException($"请求异常-{route}", ex)
});
}
if (stopWatch is not null)
{
stopWatch.Stop();
Console.WriteLine($"\t[耗时 {InteractiveHelper.GetStopWatchTime(stopWatch)}]");
}
return;
}
r.Handled = true;
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.NotFound,
ReturnArgs = r,
ServerException = new ExecutionUnregisteredException($"请求的路由未注册-{route}")
});
}
catch (Exception ex)
{
r.Handled = false;
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.InternalServerError,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("处理标准请求时发生异常", ex)
});
}
}
catch (Exception ex)
{
r.Handled = false;
Console.WriteLine($"[ERROR]处理请求时发生未捕获的异常:{ex.Message}");
Console.WriteLine($"[TRACE] {ex.StackTrace}");
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.InternalServerError,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("处理请求时发生未捕获的异常", ex)
});
}
}
/// <summary>
/// 启动核心服务
/// </summary>
/// <returns></returns>
public override async Task StartServerCore()
{
ServerCoreHost ??= XFEServerCoreHost.Configure([this]).Single();
await ServerCoreHost.StartServerCore().ConfigureAwait(false);
}
/// <summary>
/// 规范化主入口点,移除首尾及重复的路径分隔符。
/// </summary>
internal static string NormalizeMainEntryPoint(string? mainEntryPoint) => string.Join(
"/",
(mainEntryPoint ?? string.Empty).Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
/// <summary>
/// 获取请求URL中的全部非空路径段。
/// </summary>
internal static IReadOnlyList<string> GetRequestSegments(Uri requestUrl) => requestUrl.Segments
.Skip(1)
.Select(segment => Uri.UnescapeDataString(segment.Trim('/')))
.Where(segment => segment.Length > 0)
.ToArray();
/// <summary>
/// 尝试匹配当前核心的主入口点,并提取次级路由。
/// </summary>
internal bool TryGetRoute(Uri requestUrl, out string route)
{
var requestSegments = GetRequestSegments(requestUrl);
var entryPointSegments = GetEntryPointSegments(MainEntryPoint);
if (requestSegments.Count < entryPointSegments.Count)
{
route = string.Empty;
return false;
}
for (var i = 0; i < entryPointSegments.Count; i++)
{
if (requestSegments[i] == entryPointSegments[i]) continue;
route = string.Empty;
return false;
}
route = string.Join("/", requestSegments.Skip(entryPointSegments.Count));
return true;
}
/// <summary>
/// 按精确路由优先、最具体通配符次之的规则查找服务。
/// </summary>
private bool TryResolveService(string route, out Func<IServerCoreStandardService>? serviceFactory, out string? matchedPattern)
{
if (StandardCoreServiceDictionary.TryGetValue(route, out serviceFactory))
{
matchedPattern = route;
return true;
}
matchedPattern = null;
serviceFactory = null;
var bestPriority = int.MinValue;
foreach (var (pattern, factory) in WildcardCoreServiceList)
{
if (!RouteMatchHelper.MatchWildcardRoute(pattern, route)) continue;
// 在所有命中的候选中选择最具体的模式(字面量段越多越优先),避免结果依赖注册顺序。
var currentPriority = RouteMatchHelper.GetWildcardPatternPriority(pattern);
if (currentPriority <= bestPriority) continue;
bestPriority = currentPriority;
matchedPattern = pattern;
serviceFactory = factory;
}
return serviceFactory is not null;
}
internal void NotifyServerStarted(object? sender, EventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.ServerStarted(sender, e);
}
internal void NotifyRequestReceived(object? sender, CyberCommRequestEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.RequestReceived(sender, e);
}
internal void NotifyClientConnected(object? sender, CyberCommServerEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.ClientConnected(sender, e);
}
internal void NotifyMessageReceived(object? sender, CyberCommServerEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.MessageReceived(sender, e);
}
internal void NotifyConnectionClosed(object? sender, CyberCommServerEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.ConnectionClosed(sender, e);
}
private static IReadOnlyList<string> GetEntryPointSegments(string mainEntryPoint) => mainEntryPoint
.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}
using System.Diagnostics;
using System.Net;
using System.Collections.Frozen;
using XFEExtension.NetCore.AutoImplement;
using XFEExtension.NetCore.CyberComm;
using XFEExtension.NetCore.DelegateExtension;
using XFEExtension.NetCore.ServerInteractive.Exceptions;
using XFEExtension.NetCore.ServerInteractive.Implements.ServerService;
using XFEExtension.NetCore.ServerInteractive.Interfaces.CoreService;
using XFEExtension.NetCore.ServerInteractive.Models.ServerModels;
using XFEExtension.NetCore.ServerInteractive.Utilities.Helpers;
using XFEExtension.NetCore.StringExtension;
using XFEExtension.NetCore.XFETransform.Json;
namespace XFEExtension.NetCore.ServerInteractive.Utilities.Server;
/// <summary>
/// XFE服务器核心
/// </summary>
[CreateImpl]
public abstract class XFEServerCore : ServerCoreServiceBase
{
/// <summary>
/// 是否接收非标准的Json字符串
/// </summary>
public bool AcceptNonStandardJson { get; set; } = true;
/// <summary>
/// 是否接收GET请求
/// </summary>
public bool AcceptGet { get; set; }
/// <summary>
/// 是否接收POST请求
/// </summary>
public bool AcceptPost { get; set; } = true;
/// <summary>
/// 服务器核心错误委托
/// </summary>
public XFEEventHandler<XFEServerCore, ServerCoreErrorEventArgs>? ServerCoreError { get; set; }
/// <summary>
/// 获取IP地址的函数,默认为从请求事件参数中获取客户端IP地址
/// </summary>
public Func<CyberCommRequestEventArgs, string> GetIPFunction { get; set; } = args => args.ClientIP;
/// <summary>
/// 主入口点路径(ServerCore主要入口点),默认为空字符串(为空时直接使用次级入口点)。
/// 多个核心服务器绑定同一端口时,使用不同的主入口点区分核心服务器。
/// </summary>
public string MainEntryPoint { get; set; } = string.Empty;
/// <summary>
/// 核心服务列表
/// </summary>
internal readonly List<IServerCoreOriginalService> ServerCoreServiceList = [];
/// <summary>
/// 核心校验服务列表
/// </summary>
internal IReadOnlyList<Func<IServerCoreVerifyService>> ServerCoreVerifyServiceList = [];
/// <summary>
/// 核心标准服务工厂字典(按路由路径创建实例)
/// </summary>
internal IReadOnlyDictionary<string, Func<IServerCoreStandardService>> StandardCoreServiceDictionary = FrozenDictionary<string, Func<IServerCoreStandardService>>.Empty;
/// <summary>
/// 通配符路由服务工厂列表(模式 → 工厂)
/// </summary>
internal IReadOnlyList<(string Pattern, Func<IServerCoreStandardService> Factory)> WildcardCoreServiceList = [];
/// <summary>
/// 禁用框架请求日志的入口点路径或通配符模式集合
/// </summary>
internal IReadOnlySet<string> NoLogEntryPointSet = FrozenSet<string>.Empty;
/// <summary>
/// 网络通讯服务器
/// </summary>
public CyberCommServer CyberCommServer { get; internal set; } = new();
/// <summary>底层 CyberComm 限制。</summary>
public CyberCommLimitOptions TransportLimits { get; internal set; } = new();
/// <summary>底层 TLS 配置。</summary>
public CyberCommTlsOptions? TlsOptions { get; internal set; }
/// <summary>
/// 当前核心所属的共享监听主机。
/// </summary>
internal XFEServerCoreHost? ServerCoreHost { get; set; }
/// <summary>
/// 主入口点包含的路径段数量。
/// </summary>
internal int MainEntryPointSegmentCount => GetEntryPointSegments(MainEntryPoint).Count;
/// <summary>
/// 处理已经由共享监听主机分发到当前核心的请求。
/// </summary>
internal async Task ProcessRequest(CyberCommRequestEventArgs e, CancellationToken cancellationToken = default)
{
var r = new ServerCoreReturnArgs
{
Args = e,
ServerCore = this
};
try
{
cancellationToken.ThrowIfCancellationRequested();
var clientIP = e.ClientIP;
try { clientIP = GetIPFunction(e); } catch (Exception ex) { Console.WriteLine($"[WARN]获取IP地址失败:{ex.Message}"); }
r.ClientIP = clientIP;
// 在校验日志产生前解析并匹配入口点,以便 [NoLog] 能关闭完整的框架请求日志。
string route;
Func<IServerCoreStandardService>? serviceFactory;
string? matchedPattern;
try
{
var url = e.RequestUrl;
if (url is null)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("请求URL为空")
});
return;
}
if (!TryGetRoute(url, out route))
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException($"请求路径不匹配主入口点: {MainEntryPoint}")
});
return;
}
if (route.IsNullOrEmpty())
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("请求路由为空")
});
return;
}
TryResolveService(route, out serviceFactory, out matchedPattern);
r.SuppressLog = matchedPattern is not null && NoLogEntryPointSet.Contains(matchedPattern);
}
catch (Exception ex)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.InternalServerError,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("解析请求路由时发生异常", ex)
});
return;
}
try
{
foreach (var serverCoreVerifyService in ServerCoreVerifyServiceList.Select(serverCoreVerifyFactory => serverCoreVerifyFactory()))
{
cancellationToken.ThrowIfCancellationRequested();
serverCoreVerifyService.ReturnArgs = r;
serverCoreVerifyService.Args = e;
if (!serverCoreVerifyService.VerifyRequest() || !await serverCoreVerifyService.VerifyRequestAsync().ConfigureAwait(false))
{
if (e.Context is not null && !e.Context.Response.IsCompleted)
await e.ReplyAndClose("请求未通过验证", r.StatusCode == HttpStatusCode.InternalServerError ? HttpStatusCode.Forbidden : r.StatusCode).ConfigureAwait(false);
return;
}
}
}
catch (Exception ex)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = r.StatusCode,
Handled = r.Handled,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("请求校验失败", ex)
});
return;
}
// 从URL路径中提取路由信息
XFEJsonNode? queryableJsonNode = null;
try
{
// 尝试解析请求体为JSON(可选)
if (e.RequestBody is not null)
{
queryableJsonNode = e.RequestBody;
}
}
catch (Exception ex)
{
if (!AcceptNonStandardJson)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.BadRequest,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("无法解析 JSON 请求体", ex)
});
return;
}
}
try
{
Stopwatch? stopWatch = null;
if (!r.SuppressLog)
{
Console.Write($"[{e.CorrelationId}]({ServerCoreName})【{clientIP}】请求路由-{route}:");
stopWatch = Stopwatch.StartNew();
}
if (serviceFactory is not null && matchedPattern is not null)
{
var serviceInstance = serviceFactory();
try
{
serviceInstance.XFEServerCore = this;
serviceInstance.Route = route;
serviceInstance.Json = queryableJsonNode;
serviceInstance.Args = e;
serviceInstance.ReturnArgs = r;
serviceInstance.Initialize();
// 根据匹配的模式调用对应的处理方法(同步与异步互斥,优先同步)
if (serviceInstance.SyncEntryPoints.TryGetValue(matchedPattern, out var syncHandler))
syncHandler();
else if (serviceInstance.AsyncEntryPoints.TryGetValue(matchedPattern, out var asyncHandler))
await asyncHandler().WaitAsync(cancellationToken).ConfigureAwait(false);
else
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.NotFound,
ReturnArgs = r,
ServerException = new ExecutionUnregisteredException($"服务已注册但路由未找到对应处理方法-{route}")
});
}
}
catch (Exception ex)
{
ServerCoreError?.Invoke(this, new()
{
StatusCode = r.StatusCode,
Handled = r.Handled,
ReturnArgs = r,
ServerException = new XFEServerCoreRequestInnerException($"请求异常-{route}", ex)
});
}
if (stopWatch is not null)
{
stopWatch.Stop();
Console.WriteLine($"\t[耗时 {InteractiveHelper.GetStopWatchTime(stopWatch)}]");
}
return;
}
r.Handled = true;
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.NotFound,
ReturnArgs = r,
ServerException = new ExecutionUnregisteredException($"请求的路由未注册-{route}")
});
}
catch (Exception ex)
{
r.Handled = false;
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.InternalServerError,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("处理标准请求时发生异常", ex)
});
}
}
catch (Exception ex)
{
r.Handled = false;
Console.WriteLine($"[ERROR]处理请求时发生未捕获的异常:{ex.Message}");
Console.WriteLine($"[TRACE] {ex.StackTrace}");
ServerCoreError?.Invoke(this, new()
{
StatusCode = HttpStatusCode.InternalServerError,
ReturnArgs = r,
ServerException = new ProcessStandardRequestException("处理请求时发生未捕获的异常", ex)
});
}
}
/// <summary>
/// 启动核心服务
/// </summary>
/// <returns></returns>
public override async Task StartServerCore()
{
ServerCoreHost ??= XFEServerCoreHost.Configure([this]).Single();
await ServerCoreHost.StartServerCore().ConfigureAwait(false);
}
/// <summary>
/// 规范化主入口点,移除首尾及重复的路径分隔符。
/// </summary>
internal static string NormalizeMainEntryPoint(string? mainEntryPoint) => string.Join(
"/",
(mainEntryPoint ?? string.Empty).Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
/// <summary>
/// 获取请求URL中的全部非空路径段。
/// </summary>
internal static IReadOnlyList<string> GetRequestSegments(Uri requestUrl) => requestUrl.Segments
.Skip(1)
.Select(segment => Uri.UnescapeDataString(segment.Trim('/')))
.Where(segment => segment.Length > 0)
.ToArray();
/// <summary>
/// 尝试匹配当前核心的主入口点,并提取次级路由。
/// </summary>
internal bool TryGetRoute(Uri requestUrl, out string route)
{
var requestSegments = GetRequestSegments(requestUrl);
var entryPointSegments = GetEntryPointSegments(MainEntryPoint);
if (requestSegments.Count < entryPointSegments.Count)
{
route = string.Empty;
return false;
}
for (var i = 0; i < entryPointSegments.Count; i++)
{
if (requestSegments[i] == entryPointSegments[i]) continue;
route = string.Empty;
return false;
}
route = string.Join("/", requestSegments.Skip(entryPointSegments.Count));
return true;
}
/// <summary>
/// 按精确路由优先、最具体通配符次之的规则查找服务。
/// </summary>
private bool TryResolveService(string route, out Func<IServerCoreStandardService>? serviceFactory, out string? matchedPattern)
{
if (StandardCoreServiceDictionary.TryGetValue(route, out serviceFactory))
{
matchedPattern = route;
return true;
}
matchedPattern = null;
serviceFactory = null;
var bestPriority = int.MinValue;
foreach (var (pattern, factory) in WildcardCoreServiceList)
{
if (!RouteMatchHelper.MatchWildcardRoute(pattern, route)) continue;
// 在所有命中的候选中选择最具体的模式(字面量段越多越优先),避免结果依赖注册顺序。
var currentPriority = RouteMatchHelper.GetWildcardPatternPriority(pattern);
if (currentPriority <= bestPriority) continue;
bestPriority = currentPriority;
matchedPattern = pattern;
serviceFactory = factory;
}
return serviceFactory is not null;
}
internal void NotifyServerStarted(object? sender, EventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.ServerStarted(sender, e);
}
internal void NotifyRequestReceived(object? sender, CyberCommRequestEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.RequestReceived(sender, e);
}
internal void NotifyClientConnected(object? sender, CyberCommServerEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.ClientConnected(sender, e);
}
internal void NotifyMessageReceived(object? sender, CyberCommServerEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.MessageReceived(sender, e);
}
internal void NotifyConnectionClosed(object? sender, CyberCommServerEventArgs e)
{
foreach (var service in ServerCoreServiceList)
service.ConnectionClosed(sender, e);
}
private static IReadOnlyList<string> GetEntryPointSegments(string mainEntryPoint) => mainEntryPoint
.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}