chore: initial project import
This commit is contained in:
commit
26620707a0
347 files changed
+56172
No files matched your search
@@ -0,0 +1,112 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Fleet.Rpc;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Fleet.Server;
|
||||
|
||||
/// <summary>Fleet 服务端的接入点:产品在这里挂上自己的状态、收件箱、事件和 RPC 方法。</summary>
|
||||
public sealed class FleetServerBuilder
|
||||
{
|
||||
private readonly List<Action<RpcRouter<NodeCallContext>, IServiceProvider>> _routeConfigurators = [];
|
||||
|
||||
internal FleetServerBuilder(IServiceCollection services)
|
||||
{
|
||||
Services = services;
|
||||
}
|
||||
|
||||
public IServiceCollection Services { get; }
|
||||
|
||||
internal IReadOnlyList<Action<RpcRouter<NodeCallContext>, IServiceProvider>> RouteConfigurators => _routeConfigurators;
|
||||
|
||||
public FleetServerBuilder AddState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TProvider>()
|
||||
where TProvider : class, IStateProvider
|
||||
{
|
||||
Services.AddSingleton<IStateProvider, TProvider>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public FleetServerBuilder AddInbox<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TInbox>()
|
||||
where TInbox : class, IInbox
|
||||
{
|
||||
Services.AddSingleton<IInbox, TInbox>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public FleetServerBuilder OnNodeEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TSink>()
|
||||
where TSink : class, INodeEventSink
|
||||
{
|
||||
Services.AddSingleton<INodeEventSink, TSink>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public FleetServerBuilder OnEnrolled<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] THook>()
|
||||
where THook : class, IEnrollmentHook
|
||||
{
|
||||
Services.AddSingleton<IEnrollmentHook, THook>();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>注册产品的 RPC 方法(<c>monitor.*</c> 等)。处理函数通过 <see cref="IServiceProvider"/> 在调用时解析服务,避免构造期的循环依赖。</summary>
|
||||
public FleetServerBuilder MapMethods(Action<RpcRouter<NodeCallContext>, IServiceProvider> configure)
|
||||
{
|
||||
_routeConfigurators.Add(configure);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FleetServerExtensions
|
||||
{
|
||||
/// <summary>需要事先在 DI 中注册 <see cref="IFleetStore"/>。</summary>
|
||||
public static FleetServerBuilder AddFleetServer(this IServiceCollection services, Action<FleetServerOptions>? configure = null)
|
||||
{
|
||||
var options = new FleetServerOptions();
|
||||
configure?.Invoke(options);
|
||||
services.AddSingleton(options);
|
||||
|
||||
var builder = new FleetServerBuilder(services);
|
||||
services.AddSingleton(provider =>
|
||||
{
|
||||
ILogger logger = provider.GetRequiredService<ILoggerFactory>().CreateLogger("Fleet.Rpc");
|
||||
var router = new RpcRouter<NodeCallContext>((method, ex) => FleetLog.HandlerFailed(logger, ex, method));
|
||||
foreach (Action<RpcRouter<NodeCallContext>, IServiceProvider> configurator in builder.RouteConfigurators)
|
||||
{
|
||||
configurator(router, provider);
|
||||
}
|
||||
|
||||
return new FleetRouter(router);
|
||||
});
|
||||
services.AddSingleton(provider => new FleetLinkHost(
|
||||
provider.GetRequiredService<IFleetStore>(),
|
||||
provider.GetRequiredService<FleetServerOptions>(),
|
||||
provider.GetRequiredService<TimeProvider>(),
|
||||
provider.GetRequiredService<ILogger<FleetLinkHost>>(),
|
||||
provider.GetServices<IStateProvider>(),
|
||||
provider.GetServices<IInbox>(),
|
||||
provider.GetServices<INodeEventSink>(),
|
||||
provider.GetRequiredService<FleetRouter>()));
|
||||
services.AddSingleton<IFleetConnections>(provider => provider.GetRequiredService<FleetLinkHost>());
|
||||
services.AddSingleton<IStateNotifier>(provider => provider.GetRequiredService<FleetLinkHost>());
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>映射 WebSocket 端点。调用方需要先 <c>app.UseWebSockets()</c>。</summary>
|
||||
public static IEndpointRouteBuilder MapFleetLink(this IEndpointRouteBuilder app, string path)
|
||||
{
|
||||
app.Map(path, async (HttpContext http) =>
|
||||
{
|
||||
if (!http.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
http.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
return;
|
||||
}
|
||||
|
||||
using System.Net.WebSockets.WebSocket socket = await http.WebSockets.AcceptWebSocketAsync();
|
||||
await http.RequestServices.GetRequiredService<FleetLinkHost>().RunConnectionAsync(socket, http.RequestAborted);
|
||||
});
|
||||
return app;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user