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; }
/// PawnIO 驱动是否已安装(ring0 传感器读取依赖它或 WinRing0,缺失时温度/频率通常无法读取)
public bool PawnIoInstalled { 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))]
[JsonSerializable(typeof(HardwareConfig))]
[JsonSerializable(typeof(HardwareConfigResponse))]
[JsonSerializable(typeof(HardwareConfigUpdateResponse))]
[JsonSerializable(typeof(HardwareConfigUpdateRequest))]
internal sealed partial class ThingHKJsonContext : JsonSerializerContext;