using System.Text.Json; using System.Text.Json.Serialization; namespace Fleet.Rpc; /// 框架保留的方法名。fleet.* 只属于框架,产品使用自己的前缀。 public static class FleetMethods { public const string Challenge = "fleet.challenge"; public const string Auth = "fleet.auth"; public const string Hello = "fleet.hello"; public const string Heartbeat = "fleet.heartbeat"; public const string Stopping = "fleet.stopping"; public const string StateSync = "fleet.state.sync"; public const string OutboxAck = "fleet.outbox.ack"; public const string Revoked = "fleet.revoked"; } /// /// 框架自己的方法声明,两个平面各一份。认证和握手阶段由连接代码直接处理的(Inline)不经过路由器。 /// 同一个方法名在两个平面里可以有不同的发起方:fleet.state.sync 在节点面是服务端发给节点,在对等面是 Agent 发给 Probe。 /// public static class FleetMethodTable { public static readonly MethodTable Table = new( [ // 节点面 MethodSpec.Notification(FleetMethods.Challenge, RpcSide.Server).AsInline(), MethodSpec.Request(FleetMethods.Auth, RpcSide.Node).AsInline(), MethodSpec.Request(FleetMethods.Hello, RpcSide.Node).AsInline(), MethodSpec.Notification(FleetMethods.Heartbeat, RpcSide.Node).AsInline(), MethodSpec.Notification(FleetMethods.Stopping, RpcSide.Node).AsInline(), MethodSpec.Request(FleetMethods.StateSync, RpcSide.Server), MethodSpec.Notification(FleetMethods.OutboxAck, RpcSide.Server), MethodSpec.Notification(FleetMethods.Revoked, RpcSide.Server), // 对等面 MethodSpec.Notification(PeerMethods.Challenge, RpcSide.Listener).AsInline(), MethodSpec.Request(PeerMethods.Auth, RpcSide.Dialer).AsInline(), MethodSpec.Request(FleetMethods.StateSync, RpcSide.Listener), MethodSpec.Notification(FleetMethods.OutboxAck, RpcSide.Listener), ]); } public sealed class ChallengeParams { [JsonPropertyName("nonce")] public string Nonce { get; set; } = ""; [JsonPropertyName("expires_at_ms")] public long ExpiresAtMs { get; set; } /// 服务器这次连接的临时 ECDH 公钥(SPKI,base64);服务器有身份密钥时才有。 [JsonPropertyName("server_eph")] public string? ServerEphemeral { get; set; } /// 服务器密钥对「随机数加临时公钥」的签名(base64):节点据此确认对面是操作员授权的服务器。 [JsonPropertyName("server_sig")] public string? ServerSignature { get; set; } } public sealed class AuthParams { [JsonPropertyName("node_id")] public string NodeId { get; set; } = ""; /// 对 fleet|v1|auth|{node_id}|{nonce} 的签名(base64)。 [JsonPropertyName("signature")] public string Signature { get; set; } = ""; /// 节点的临时 ECDH 公钥(SPKI,base64):有它就是安全链路,签名覆盖双方的临时公钥,认证结果起所有帧都是加密的。 [JsonPropertyName("node_eph")] public string? NodeEphemeral { get; set; } } public sealed class AuthResult { /// pending | active [JsonPropertyName("status")] public string Status { get; set; } = ""; } public sealed class HelloParams { [JsonPropertyName("node_version")] public string NodeVersion { get; set; } = ""; [JsonPropertyName("capabilities")] public List Capabilities { get; set; } = []; [JsonPropertyName("now_utc_ms")] public long NowUtcMs { get; set; } /// 产品自定义的元数据(例如 MoShiro 的 tls_spki、probe_ports、local_limits 摘要)。 [JsonPropertyName("meta")] public JsonElement? Meta { get; set; } } public sealed class HelloResult { [JsonPropertyName("server_time_ms")] public long ServerTimeMs { get; set; } /// 节点时钟 − 服务端时钟(毫秒,未扣除网络往返)。 [JsonPropertyName("clock_offset_ms")] public long ClockOffsetMs { get; set; } } public sealed class HeartbeatParams { [JsonPropertyName("extra")] public JsonElement? Extra { get; set; } } public sealed class StateSyncParams { [JsonPropertyName("type")] public string Type { get; set; } = ""; [JsonPropertyName("version")] public long Version { get; set; } [JsonPropertyName("doc")] public JsonElement Doc { get; set; } } public sealed class StateSyncResult { [JsonPropertyName("applied_version")] public long AppliedVersion { get; set; } [JsonPropertyName("rejected")] public List Rejected { get; set; } = []; } public sealed class RejectedItem { [JsonPropertyName("id")] public string Id { get; set; } = ""; /// unsupported | budget_exceeded | policy_denied | … [JsonPropertyName("reason")] public string Reason { get; set; } = ""; } public sealed class OutboxAckParams { [JsonPropertyName("ids")] public List Ids { get; set; } = []; [JsonPropertyName("duplicates")] public List Duplicates { get; set; } = []; } public sealed class RevokedParams { [JsonPropertyName("reason")] public string Reason { get; set; } = ""; } public sealed class StoppingParams { [JsonPropertyName("reason")] public string Reason { get; set; } = "stopping"; } [JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] [JsonSerializable(typeof(RpcMessage))] [JsonSerializable(typeof(ChallengeParams))] [JsonSerializable(typeof(AuthParams))] [JsonSerializable(typeof(AuthResult))] [JsonSerializable(typeof(HelloParams))] [JsonSerializable(typeof(HelloResult))] [JsonSerializable(typeof(HeartbeatParams))] [JsonSerializable(typeof(StoppingParams))] [JsonSerializable(typeof(StateSyncParams))] [JsonSerializable(typeof(StateSyncResult))] [JsonSerializable(typeof(OutboxAckParams))] [JsonSerializable(typeof(RevokedParams))] public sealed partial class FleetRpcContext : JsonSerializerContext;