# 数据模型 所有模型 JSON 序列化 camelCase,时间戳为 Unix 毫秒。前后端类型一一对应(Rust serde ↔ TS types)。 ## AppErrorInfo(跨边界错误 payload) ```ts { code: string; detail: string | null } ``` 稳定英文错误码(`AppError::code()`):`SshConnectionError` / `AuthenticationError` / `SessionNotFound` / `InvalidHostConfig` / `StorageError` / `IoError` / `SshProtocolError` / `SecureStoreError` / `CredentialNotFound` / `SftpChannelError` / `SftpPermissionDenied` / `SftpPathNotFound` / `SftpTransferError`。detail 为语言无关诊断,前端按当前语言本地化展示。 ## HostConfig(主机配置,不含明文凭据) ```ts { id: string; // UUID name: string; // 展示名 host: string; // 主机地址 port: number; // SSH 端口 username: string; authType: 'Password' | 'PrivateKey'; passwordRef: string | null; // 安全存储引用键,非明文 privateKeyPath: string | null; passphraseRef: string | null; // 私钥口令引用键 remark: string | null; group: string; // 分组名,空串 = "未分组" } ``` > `SaveHostRequest` 为前端提交形态:额外含 `password` / `passphrase` 明文字段,仅存在于请求中,后端落盘前清除。`host.rs` 模型带 `#[serde(alias = "auth_type")]` 等 legacy 兼容。 ## SessionInfo(真实会话,与 UI 标签解耦) ```ts { sessionId: string; hostId: string; host: string; port: number; username: string; status: 'Connecting' | 'Connected' | 'AuthFailed' | 'Disconnected' | 'Timeout' | 'Error'; createdAt: number; // 毫秒时间戳 } ``` ## MonitorSnapshot(监控快照,单 payload 全量) ```ts { sessionId: string; timestamp: number; // 采集时间 cpuUsage: number | null; // 0.0 ~ 100.0(/proc/stat 增量计算);无基线或缺失时为 null memoryUsage: number | null; // 0.0 ~ 100.0(MemAvailable);字段缺失时为 null diskUsage: number | null; // 0.0 ~ 100.0(根分区,df Use%);df 失败时为 null diskAvailableBytes: number | null; // 根分区剩余容量;df 失败时为 null diskTotalBytes: number | null; // 根分区总容量;df 失败时为 null network: NetworkSnapshot; } ``` > 指标为 `null` 表示"未知"而非 0(与网络速率首轮 null 语义一致):首轮 CPU 无基线样本、`MemAvailable` 缺失(< 3.14 内核)、`df` 采集失败(如 busybox 不支持 `-B1`)时前端展示 `--`,不伪造 0% 或 100%。 ### NetworkSnapshot / NetworkInterface(网络采集) ```ts interface NetworkSnapshot { available: boolean; // /proc/net/dev 是否成功读取并解析(区分失败与无候选接口) interfaces: NetworkInterface[]; // 不含 lo 的候选网卡,按远端返回顺序 } interface NetworkInterface { name: string; // 网卡接口名 receiveBytesPerSecond: number | null; // 下行速率;首次采样或计数异常时为 null transmitBytesPerSecond: number | null; // 上行速率;首次采样或计数异常时为 null } ``` ## TaskInfo(长任务,monitor 使用) ```ts { taskId: string; taskType: string; sessionId: string | null; status: 'Pending' | 'Running' | 'Done' | 'Failed'; createdAt: number; error?: AppErrorInfo | null; // Failed 时存在 } ``` ## TransferTask(SFTP 传输任务) ```ts { taskId: string; // UUID v4 sessionId: string; transferType: 'Upload' | 'Download'; remotePath: string; localPath: string; fileName: string; // 从路径提取,用于 UI totalBytes: number; transferredBytes: number; speedBps: number; status: 'Pending' | 'Running' | 'Done' | 'Failed' | 'Cancelled'; error: AppErrorInfo | null; // Failed 时记录结构化原因;Cancelled 为 null createdAt: number; } ``` ## RemoteEntry(SFTP 目录条目) ```ts { name: string; // 不含路径 path: string; // 完整绝对路径 isDir: boolean; size: number; // bytes,目录为 0 modifiedAt: number; // 毫秒时间戳 permissions: string; // 如 "rwxr-xr-x" } ``` ## 事件 Payload 见 [API.md](API.md#2-事件后端--前端流式推送):SessionStatusEvent、ConnectionProgressEvent、TerminalDataEvent、SftpProgressEvent、SftpTaskStatusEvent、TaskStatusEvent(错误字段均为 `error: AppErrorInfo | null`)。 ## 序列化约定 - Rust 侧统一 `#[serde(rename_all = "camelCase")]` - 旧字段兼容:`#[serde(alias = "snake_case")]`(host.rs 的 auth_type / password_ref / private_key_path / passphrase_ref) - 校验(proptest 属性测试):毫秒时间戳必须 `>= 1_000_000_000_000`(2001-09-09);百分比字段 `0.0~100.0`;端口 `1~65535`