using System.Collections.Concurrent; using System.Net.WebSockets; using System.Text.Json; using System.Text.Json.Serialization.Metadata; using Fleet.Core; using Fleet.Rpc; using Microsoft.Extensions.Logging; namespace Fleet.Server; /// /// 服务端连接宿主:在线表 + 服务端发起的调用 + 状态推送通知。每个 WebSocket 对应一个 。 /// public sealed class FleetLinkHost : IFleetConnections, IStateNotifier { private readonly ConcurrentDictionary _connections = new(); internal FleetLinkHost( IFleetStore store, FleetServerOptions options, TimeProvider time, ILogger logger, IEnumerable stateProviders, IEnumerable inboxes, IEnumerable sinks, FleetRouter router, IServerIdentity? serverIdentity = null, IBinaryAttestor? binaryAttestor = null) { ServerIdentity = serverIdentity; BinaryAttestor = binaryAttestor; Store = store; Options = options; Time = time; Logger = logger; StateProviders = [.. stateProviders]; Inboxes = inboxes.ToDictionary(i => i.Channel); Sinks = [.. sinks]; Router = router.Inner; RoleOf = router.RoleOf; } internal IFleetStore Store { get; } /// 服务器的身份密钥;没有时节点连接用旧的明文认证。 internal IServerIdentity? ServerIdentity { get; } /// 节点二进制的把关;没有时不检查。 internal IBinaryAttestor? BinaryAttestor { get; } internal FleetServerOptions Options { get; } internal TimeProvider Time { get; } internal ILogger Logger { get; } internal IReadOnlyList StateProviders { get; } internal IReadOnlyDictionary Inboxes { get; } internal IReadOnlyList Sinks { get; } internal RpcRouter Router { get; } internal Func? RoleOf { get; } public IReadOnlyCollection OnlineNodes => [.. _connections.Keys]; public bool IsOnline(NodeId node) => _connections.ContainsKey(node); public NodeSessionInfo? GetSession(NodeId node) => _connections.TryGetValue(node, out NodeConnection? c) ? c.Session : null; /// 处理一条 WebSocket 连接,直到连接结束。 public async Task RunConnectionAsync(WebSocket socket, CancellationToken ct) { using var connection = new NodeConnection(this, socket); await connection.RunAsync(ct); } /// 返回被替换掉的旧连接(如果有)。 internal NodeConnection? Register(NodeConnection connection) { NodeConnection? replaced = null; _connections.AddOrUpdate( connection.NodeId, connection, (_, existing) => { replaced = existing; return connection; }); return replaced; } internal void Unregister(NodeConnection connection) => _connections.TryRemove(new KeyValuePair(connection.NodeId, connection)); public async ValueTask> RequestAsync( NodeId node, string method, TParams parameters, JsonTypeInfo paramsInfo, JsonTypeInfo resultInfo, CancellationToken ct) { if (!_connections.TryGetValue(node, out NodeConnection? connection)) { return Result.Fail(FleetErrors.NodeOffline, "node is not connected"); } Result raw = await connection.RequestAsync(method, JsonSerializer.SerializeToElement(parameters, paramsInfo), ct); if (!raw.TryGet(out JsonElement value, out FleetError? error)) { return Result.Fail(error); } try { TResult? result = value.Deserialize(resultInfo); return result is null ? Result.Fail(FleetErrors.Internal, "empty result") : Result.Ok(result); } catch (JsonException) { return Result.Fail(FleetErrors.Internal, "result could not be parsed"); } } public async ValueTask NotifyAsync(NodeId node, string method, TParams parameters, JsonTypeInfo paramsInfo, CancellationToken ct) { if (!_connections.TryGetValue(node, out NodeConnection? connection)) { return false; } return await connection.SendAsync(RpcMessage.Notification(method, parameters, paramsInfo), ct); } public async ValueTask CloseAllAsync(string reason) { foreach (NodeConnection connection in _connections.Values.ToArray()) { await connection.CloseAsync(reason); } } public async ValueTask DisconnectAsync(NodeId node, string reason, CancellationToken ct) { if (_connections.TryGetValue(node, out NodeConnection? connection)) { await connection.RevokeAsync(reason, ct); } } public void NotifyChanged(NodeId node) { if (_connections.TryGetValue(node, out NodeConnection? connection)) { connection.SignalStateChanged(); } } public void NotifyAllChanged() { foreach (NodeConnection connection in _connections.Values) { connection.SignalStateChanged(); } } } /// 产品注册的 RPC 方法路由。 public sealed class FleetRouter { public FleetRouter(RpcRouter inner, Func? roleOf) { Inner = inner; RoleOf = roleOf; } internal RpcRouter Inner { get; } internal Func? RoleOf { get; } /// 已注册的入站方法名(只读,测试用它核对声明表)。 public IReadOnlyCollection Methods => Inner.Methods; public MethodTable Table => Inner.Table; }