-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Seeker32 edited this page Aug 11, 2026
·
3 revisions
┌─────────────────────────────────────────────┐
│ React 前端 (src/) │
│ Stores (Zustand) · Components · Pages │
│ 只负责视图渲染与状态流转,不解析 shell 输出 │
└──────────────────┬──────────────────────────┘
│ invoke(请求/响应) · event(流式)
┌──────────────────▼──────────────────────────┐
│ Tauri 命令层 (commands/) │
│ host · session · monitor · sftp · logging │
│ 薄封装:参数校验 → 调用 core → 返回模型 │
└──────────────────┬──────────────────────────┘
┌──────────────────▼──────────────────────────┐
│ Core 服务层 (core/) │
│ session_manager · terminal_service │
│ monitor_service · sftp_service │
│ ssh_transport · host_service · monitor_worker│
└──────────────────┬──────────────────────────┘
┌──────────────────▼──────────────────────────┐
│ 存储 (storage/) · 模型 (models/) · 错误 (errors/)│
│ host_store · secure_store · app_error │
└─────────────────────────────────────────────┘
-
SessionManager持有真实 SSH 会话(SessionHandle),键为sessionId - 前端标签页(
TerminalTabs)只是视图,activeView指向 sessionId 或'home' - 关闭标签页时只调
close_session,会话生命周期由后端统一管理
-
invoke:请求/响应。如
open_session、sftp_list_dir、write_terminal、set_log_level -
event:流式推送。如
terminal:data、session:status、monitor:snapshot - 所有 payload 均为结构化 JSON(camelCase),前后端类型定义一一对应(Rust serde
rename_all = "camelCase"+ TS types) - 错误统一为语言无关的
AppErrorInfo { code, detail }:code 为稳定英文标识,detail 保留底层诊断,由前端按当前语言本地化展示
-
terminal_service:会话建立、PTY、终端双向 IO(约 1030 行,唯一持有终端工作线程逻辑) -
ssh_transport:深层 SSH transport module(约 975 行),对外只暴露 Terminal / SFTP / Exec 三种 opaque capability;ssh2::Session、Channel、blocking mode 与第三方错误转换全部留在内部,不向上层泄漏 -
sftp_service:SFTP 目录浏览、传输任务队列(上传/下载/取消),每条会话复用一条独立 SFTP 连接并串行操作(约 1600 行) -
monitor_service+monitor_worker:独立 SSH 长连接周期采集(CPU / 内存 / 磁盘 + 网络接口速率),单实例管理(共约 1300 行) -
host_service:深层 HostConfig 持久化 module(约 960 行),拥有校验、凭据写入与引用解析、落盘与失败补偿的完整 save/delete 流程,含分组字段 -
session_manager:纯协调层,注册/索引/生命周期,不实现 IO 或采集(约 375 行)
- Terminal、SFTP、Monitoring 各自使用独立底层 SSH 连接;SFTP 的 blocking IO 不再影响 Terminal 的连接级状态
- 会话打开时并行启动 Terminal 与 SFTP 连接;首个 SFTP 请求等待正在进行的连接,后台失败交付一次后由下一次操作触发按需重连
- Session 关闭立即移除 SFTP registry、唤醒等待者并丢弃迟到的连接结果
open_session (invoke)
→ session_manager 生成 sessionId + SessionInfo
→ terminal_service 启动工作线程
LoadingCredentials → ConnectingTcp → SshHandshake
→ Authenticating → OpeningChannel → RequestingPty → StartingShell
→ 成功: Connected(先更新后端 runtime_status,再 emit session:status)
→ 失败: AuthFailed | Timeout | Error(emit session:status + error)
→ 建立后 emit terminal:data 流式输出
前端 openSession → startMonitoring(独立监控任务)
close_session → 后端统一 teardown:停止 Terminal → 清理该会话的
Monitoring task/snapshot → 清理 SFTP 任务与共享连接 → 移除会话
前端只清理本地投影(不主动 stop 监控)
- 会话状态以后端
runtime_status为权威:Terminal 先更新后端元数据再发事件,list_sessions直接读取;前端只消费session:status,不再回写 - 任务状态以所属 module 的 registry 为权威:先更新 registry(校验迁移合法性)再发事件,迟到的迁移被拒绝且不发事件
| 事件 | 方向 | 触发时机 |
|---|---|---|
terminal:data |
后端 → 前端 | 终端输出(UTF-8,4KB 缓冲非阻塞读) |
session:status |
后端 → 前端 | 会话状态变更(Connecting/Connected/AuthFailed/Timeout/Error/Disconnected),携带 error: AppErrorInfo
|
session:progress |
后端 → 前端 | 连接阶段诊断(连接中的卡点提示) |
monitor:snapshot |
后端 → 前端 | 每 2 秒采集一次服务器指标(含网络接口速率) |
task:status |
后端 → 前端 | 监控长任务状态变更(Pending/Running/Done/Failed),携带 error: AppErrorInfo
|
sftp:progress |
后端 → 前端 | 传输进度(约每 500ms) |
sftp:task_status |
后端 → 前端 | 任务状态变更(Pending/Running/Done/Failed/Cancelled),携带 error: AppErrorInfo
|
- Tokio 异步运行时承载 Tauri 命令与事件发射
-
std::sync::mpsc:前端写操作通过 channel 发送
TerminalCommand(Input/Resize/Shutdown)给终端工作线程 - Arc shutdown:会话关闭信号,线程轮询退出
-
opaque capability:Terminal / SFTP / Exec 各自持独立
ssh2::Session,transport 内部持有 channel 所有权与 blocking mode 调度;registry 锁只用于短暂查找,不跨远程 IO,不同 Session 可并发 -
监控采集:monitor_worker 每 2 秒开新 channel 执行远端脚本一次,CPU 用相邻
/proc/stat采样增量计算,网络速率用相邻/proc/net/dev计数差计算(首次采样为 None)
- 主机配置只存
password_ref/passphrase_ref引用键,不存明文 - 明文凭据只存在于
SaveHostRequest请求中,落盘前清除 - 保存顺序:写新凭据 → 落盘(commit 点)→ 清理陈旧凭据;任一失败补偿删除本次已写入的凭据
- 删除顺序:先落盘移除条目(commit 点),成功后再尽力清理两个凭据 key(幂等)
-
secure_store基于 keyring(macOS Keychain / Windows Credential Manager / Linux secret-service) - macOS 额外启用 hardened runtime + entitlements
- 跨边界错误不携带已本地化文案,只传稳定英文 code + 诊断 detail,避免语言泄漏到后端