using System.Text.Json; using System.Text.Json.Serialization; using Fleet.Core; namespace Monitor.Protocol; /// monitor.* 方法名。新增方法 = 在这里定义名称和 params/result,再在组装处加一行 .On(...)。 public static class MonitorMethods { public const string TestRun = "monitor.test.run"; public const string TestCancel = "monitor.test.cancel"; public const string ProbeDisconnect = "monitor.probe.disconnect"; public const string TestStatus = "monitor.test.status"; public const string Event = "monitor.event"; public const string Host = "monitor.host"; public const string ProbeAgents = "monitor.probe.agents"; public const string ProbeAgentsChanged = "monitor.probe.agents_changed"; // Probe ↔ Agent(点对点会话) public const string Clock = "monitor.clock"; public const string TestPhase = "monitor.test.phase"; public const string TestPhaseEnd = "monitor.test.phase_end"; public const string TestAbort = "monitor.test.abort"; } public static class AgentEventKinds { public const string ProbeConnected = "probe_connected"; public const string ProbeDisconnected = "probe_disconnected"; public const string EndpointChanged = "endpoint_changed"; public const string SessionRejected = "session_rejected"; public const string ClockStep = "clock_step"; public const string Gap = "gap"; public const string CpuSaturated = "cpu_saturated"; public static readonly IReadOnlyList All = [ProbeConnected, ProbeDisconnected, EndpointChanged, SessionRejected, ClockStep, Gap, CpuSaturated]; } public static class TestStatuses { public const string Queued = "queued"; public const string Running = "running"; public const string PhaseDone = "phase_done"; public const string Succeeded = "succeeded"; public const string Failed = "failed"; public const string Aborted = "aborted"; } public sealed class TestPhase { [JsonPropertyName("kind")] public string Kind { get; set; } = ""; [JsonPropertyName("params")] public Dictionary Params { get; set; } = []; [JsonPropertyName("duration_s")] public int DurationSeconds { get; set; } } public sealed class TestRunParams { [JsonPropertyName("test_id")] public TestId TestId { get; set; } /// 在哪个 Probe 上运行:必须是当前连着这个 Agent 的 Probe。 [JsonPropertyName("probe_id")] public ProbeId ProbeId { get; set; } [JsonPropertyName("plan")] public string Plan { get; set; } = ""; [JsonPropertyName("phases")] public List Phases { get; set; } = []; } public sealed class TestRunResult { [JsonPropertyName("accepted")] public bool Accepted { get; set; } } public sealed class TestCancelParams { [JsonPropertyName("test_id")] public TestId TestId { get; set; } } /// Backend → Agent:断开某个 Probe 的会话(Probe 会按退避重连,除非它已经被吊销)。 public sealed class ProbeDisconnectParams { [JsonPropertyName("probe_id")] public ProbeId ProbeId { get; set; } } public sealed class TestStatusParams { [JsonPropertyName("test_id")] public TestId TestId { get; set; } [JsonPropertyName("status")] public string Status { get; set; } = ""; [JsonPropertyName("phase")] public int? Phase { get; set; } [JsonPropertyName("error_code")] public string? ErrorCode { get; set; } } public sealed class AgentEventParams { /// probe_connected 时:这个 Probe 的 id、版本、地址和连接时间(Backend 不用等下一次心跳就能显示)。 [JsonPropertyName("probe")] public ConnectedProbe? Probe { get; set; } [JsonPropertyName("kind")] public string Kind { get; set; } = ""; [JsonPropertyName("at_utc_ms")] public long AtUtcMs { get; set; } [JsonPropertyName("detail")] public string? Detail { get; set; } } public sealed class AgentEndpoint { [JsonPropertyName("agent_id")] public NodeId AgentId { get; set; } [JsonPropertyName("name")] public string Name { get; set; } = ""; [JsonPropertyName("host")] public string Host { get; set; } = ""; [JsonPropertyName("tcp_port")] public int TcpPort { get; set; } [JsonPropertyName("udp_ports")] public List UdpPorts { get; set; } = []; /// Agent 面向 Probe 的 TLS 证书指纹(SHA-256,base64)。 [JsonPropertyName("spki")] public string Spki { get; set; } = ""; } public sealed class ProbeAgentsParams { /// Probe 目前持有的列表版本(用于调试;服务端总是返回当前列表)。 [JsonPropertyName("have_version")] public long HaveVersion { get; set; } } public sealed class ProbeAgentsResult { [JsonPropertyName("version")] public long Version { get; set; } [JsonPropertyName("agents")] public List Agents { get; set; } = []; } /// 注册元数据(Monitor 定义,经 Fleet 的 meta 字段带上来)。 public sealed class AgentEnrollMeta { [JsonPropertyName("probe_tcp_port")] public int ProbeTcpPort { get; set; } = 7443; [JsonPropertyName("probe_udp_ports")] public List ProbeUdpPorts { get; set; } = [7443]; [JsonPropertyName("public_host")] public string? PublicHost { get; set; } [JsonPropertyName("kinds")] public List Kinds { get; set; } = []; } public sealed class LocalLimits { [JsonPropertyName("max_total_mbps")] public double MaxTotalMbps { get; set; } [JsonPropertyName("max_total_pps")] public long MaxTotalPps { get; set; } [JsonPropertyName("allowed_target_cidrs")] public List AllowedTargetCidrs { get; set; } = []; [JsonPropertyName("max_concurrent_tests")] public int MaxConcurrentTests { get; set; } = 1; } /// fleet.hello 的附加字段。 public sealed class AgentHelloMeta { [JsonPropertyName("tls_spki")] public string? TlsSpki { get; set; } [JsonPropertyName("probe_tcp_port")] public int? ProbeTcpPort { get; set; } [JsonPropertyName("probe_udp_ports")] public List? ProbeUdpPorts { get; set; } [JsonPropertyName("local_limits")] public LocalLimits? LocalLimits { get; set; } } /// /// 主机资源占用的只读快照(Agent → Backend,每隔几秒一次)。只有汇总的数字:没有 CPU 型号、主机名、网卡名,也没有任何 IP 地址。 /// 读不到的项是 null。 /// public sealed class HostSnapshot { [JsonPropertyName("cpu_percent")] public double? CpuPercent { get; set; } [JsonPropertyName("mem_used")] public long? MemUsed { get; set; } [JsonPropertyName("mem_total")] public long? MemTotal { get; set; } [JsonPropertyName("disk_used")] public long? DiskUsed { get; set; } [JsonPropertyName("disk_total")] public long? DiskTotal { get; set; } /// 所有物理网卡的累计收发字节(自开机以来)。 [JsonPropertyName("net_rx_total")] public long? NetRxTotal { get; set; } [JsonPropertyName("net_tx_total")] public long? NetTxTotal { get; set; } [JsonPropertyName("net_rx_bps")] public long? NetRxBps { get; set; } [JsonPropertyName("net_tx_bps")] public long? NetTxBps { get; set; } [JsonPropertyName("uptime_s")] public long? UptimeSeconds { get; set; } [JsonPropertyName("at_utc_ms")] public long AtUtcMs { get; set; } } /// Agent 眼中的一个已连接 Probe。 public sealed class ConnectedProbe { [JsonPropertyName("id")] public ProbeId Id { get; set; } [JsonPropertyName("version")] public string? Version { get; set; } /// Probe 的远端地址(经过 NAT 之后的公网 IP:端口)。 [JsonPropertyName("remote")] public string? Remote { get; set; } [JsonPropertyName("since_utc_ms")] public long SinceUtcMs { get; set; } } /// fleet.heartbeat 的附加字段:只有进程内的计数,没有主机信息。 public sealed class AgentHeartbeatExtra { /// 当前连着的 Probe 会话数(等于 的个数)。 [JsonPropertyName("sessions")] public int Sessions { get; set; } /// 当前连着的 Probe:每次心跳都是完整的快照,Backend 靠它纠正错过的 probe_connected / probe_disconnected 事件。 [JsonPropertyName("probes")] public List Probes { get; set; } = []; [JsonPropertyName("pps_in")] public long PpsIn { get; set; } [JsonPropertyName("pps_out")] public long PpsOut { get; set; } [JsonPropertyName("dropped_invalid")] public long DroppedInvalid { get; set; } [JsonPropertyName("dropped_rate_limited")] public long DroppedRateLimited { get; set; } [JsonPropertyName("queue_bytes")] public long QueueBytes { get; set; } } /// Agent 下发给 Probe 的一条线路任务(期望状态类型 line_task_set 里的一项)。 public sealed class LineTask { [JsonPropertyName("id")] public TaskId Id { get; set; } [JsonPropertyName("kind")] public string Kind { get; set; } = ""; [JsonPropertyName("params")] public Dictionary Params { get; set; } = []; /// 数据面用它区分任务;Agent 在本进程生命周期内分配。 [JsonPropertyName("stream_id")] public uint StreamId { get; set; } [JsonPropertyName("port")] public int Port { get; set; } } /// 这条线路的期望状态(Agent → Probe):Probe 按它调和自己一侧的角色。 public sealed class LineTaskSet { public const string StateType = "line_task_set"; [JsonPropertyName("version")] public long Version { get; set; } [JsonPropertyName("tasks")] public List Tasks { get; set; } = []; /// Agent 的数据面端口(Probe 把包发到这里)。 [JsonPropertyName("udp_ports")] public List UdpPorts { get; set; } = []; [JsonPropertyName("tcp_ports")] public List TcpPorts { get; set; } = []; } /// monitor.clock:Probe 用它估计与 Agent 单调时钟的偏移(对称往返假设)。 public sealed class ClockParams { [JsonPropertyName("probe_mono_us")] public long ProbeMonoUs { get; set; } } public sealed class ClockResult { [JsonPropertyName("agent_mono_us")] public long AgentMonoUs { get; set; } } /// 按需测试的一个阶段(Agent → Probe):Agent 编排时间,Probe 准备好自己一侧的角色之后应答。 public sealed class TestPhaseStartParams { [JsonPropertyName("test_id")] public TestId TestId { get; set; } [JsonPropertyName("phase")] public int Phase { get; set; } [JsonPropertyName("kind")] public string Kind { get; set; } = ""; [JsonPropertyName("params")] public Dictionary Params { get; set; } = []; [JsonPropertyName("stream_id")] public uint StreamId { get; set; } [JsonPropertyName("duration_s")] public int DurationSeconds { get; set; } [JsonPropertyName("port")] public int Port { get; set; } } public sealed class TestPhaseStartResult { [JsonPropertyName("accepted")] public bool Accepted { get; set; } } /// 阶段结束(Agent → Probe):Probe 收尾并把自己一侧的列块交给 Agent。sent_count 是 Agent 一侧发出的包数(单向数据流用)。 public sealed class TestPhaseEndParams { [JsonPropertyName("test_id")] public TestId TestId { get; set; } [JsonPropertyName("phase")] public int Phase { get; set; } [JsonPropertyName("stream_id")] public uint StreamId { get; set; } [JsonPropertyName("sent_count")] public long SentCount { get; set; } } /// Probe 收尾之后回复:它交给 Agent 的列块个数(Agent 据此等待全部列块到齐再进入下一阶段)。 public sealed class TestPhaseEndResult { [JsonPropertyName("fragments")] public int Fragments { get; set; } } public sealed class TestAbortParams { [JsonPropertyName("test_id")] public TestId TestId { get; set; } } /// Probe 一侧的列块放在 RawChunk 头部 params 里的保留键:本块覆盖的序号范围 [from, to)(单向数据流由 Agent 一侧按它取行)。 public static class FragmentKeys { public const string SeqFrom = "_seq_from"; public const string SeqTo = "_seq_to"; } [JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] [JsonSerializable(typeof(LineTaskSet))] [JsonSerializable(typeof(ClockParams))] [JsonSerializable(typeof(ClockResult))] [JsonSerializable(typeof(TestPhaseStartParams))] [JsonSerializable(typeof(TestPhaseStartResult))] [JsonSerializable(typeof(TestPhaseEndParams))] [JsonSerializable(typeof(TestPhaseEndResult))] [JsonSerializable(typeof(TestAbortParams))] [JsonSerializable(typeof(TaskSet))] [JsonSerializable(typeof(TestRunParams))] [JsonSerializable(typeof(TestRunResult))] [JsonSerializable(typeof(TestCancelParams))] [JsonSerializable(typeof(ProbeDisconnectParams))] [JsonSerializable(typeof(HostSnapshot))] [JsonSerializable(typeof(TestStatusParams))] [JsonSerializable(typeof(AgentEventParams))] [JsonSerializable(typeof(ProbeAgentsParams))] [JsonSerializable(typeof(ProbeAgentsResult))] [JsonSerializable(typeof(AgentEnrollMeta))] [JsonSerializable(typeof(AgentHelloMeta))] [JsonSerializable(typeof(AgentHeartbeatExtra))] [JsonSerializable(typeof(RawChunkHeader))] public sealed partial class MonitorJsonContext : JsonSerializerContext;