using System.Text.Json.Serialization; namespace ThingHK; // ===== 数据契约(与 ThingHK_GUIDE.md 第 2.4 节一致,schemaVersion=1) ===== // 这些类型同时用于:HTTP 响应、SSE 推送、--scan 命令输出。 // 任何字段变更必须递增 SensorSnapshot.SchemaVersion。 /// /// 传感器快照:一次全量采样的标准化输出。 /// 同时用于 GET /snapshot 响应、GET /stream SSE 事件、--scan 命令输出。 /// internal sealed class SensorSnapshot { /// 数据契约版本, breaking 变更时递增 public int SchemaVersion { get; set; } = 1; /// 采样时间戳(UTC 毫秒) public long Timestamp { get; set; } /// 从 Kernel 启动到首次产生快照的毫秒数(仅首个快照有意义,后续为 0) public double ColdStartMs { get; set; } /// Kernel 是否以管理员权限运行 public bool IsAdmin { get; set; } /// 当前 Kernel 是否已完成首轮扫描(ready 信号依据) public bool Ready { get; set; } /// 本次快照包含的硬件分组 public List Groups { get; set; } = new(); } internal sealed class SensorGroup { /// 分组标识(hardware type 小写,如 cpu/gpuintel/storage) public string Id { get; set; } = ""; /// 分组显示名(如 CPU / GpuIntel) public string Name { get; set; } = ""; /// 该分组下的传感器列表 public List Sensors { get; set; } = new(); } internal sealed class SensorEntry { /// 全局唯一 ID:{groupId}/{hwName}/{sensorType}/{sensorName} 小写化 public string Id { get; set; } = ""; public string Name { get; set; } = ""; public string Type { get; set; } = ""; public string HardwareName { get; set; } = ""; /// 传感器当前值;null 表示首轮未就绪或硬件不可读 public float? Value { get; set; } public string Unit { get; set; } = ""; } /// /// /status 路由响应:用于冷启动就绪探测(见指南第 3.1 节)。 /// 前端通过轮询此接口判断是否可请求 /snapshot 或订阅 /stream。 /// internal sealed class KernelStatus { public bool Ready { get; set; } public bool IsAdmin { get; set; } public double UptimeMs { get; set; } public int GroupCount { get; set; } public int SensorCount { get; set; } public List Providers { get; set; } = new(); public int SchemaVersion { get; set; } = 1; } /// /// /config 请求体:运行时调整采样配置。 /// 字段均可选,仅传递需要变更的字段。 /// internal sealed class ConfigRequest { /// 快通道采样间隔(毫秒),0 或负数表示不变 public int? FastIntervalMs { get; set; } /// 慢通道采样间隔(毫秒),0 或负数表示不变 public int? SlowIntervalMs { get; set; } /// SSE 推送间隔(毫秒),仅影响后续 stream 订阅,0 或负数表示不变 public int? StreamIntervalMs { get; set; } } internal sealed class ConfigResponse { public bool Success { get; set; } public int FastIntervalMs { get; set; } public int SlowIntervalMs { get; set; } public int StreamIntervalMs { get; set; } } /// /// 根路由健康检查响应。 /// internal sealed class HealthResponse { public bool Ok { get; set; } = true; public string Name { get; set; } = "ThingHK"; public string Version { get; set; } = "0.2.0"; } /// /// 错误响应:AOT 下所有 BadRequest/NotFound 必须用强类型,不能用匿名对象。 /// internal sealed class ErrorResponse { public ErrorResponse(string error, string message) { Error = error; Message = message; } public string Error { get; set; } public string Message { get; set; } } /// /// JSON 源生成上下文:消除 Native AOT 下反射式序列化的 IL3050/IL2026 警告。 /// 所有 HTTP 响应类型必须在此注册,否则 AOT 下序列化会抛异常。 /// [JsonSourceGenerationOptions( WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] [JsonSerializable(typeof(SensorSnapshot))] [JsonSerializable(typeof(KernelStatus))] [JsonSerializable(typeof(ConfigRequest))] [JsonSerializable(typeof(ConfigResponse))] [JsonSerializable(typeof(ConfigRequest[]))] [JsonSerializable(typeof(HealthResponse))] [JsonSerializable(typeof(ErrorResponse))] internal sealed partial class ThingHKJsonContext : JsonSerializerContext;