Skip to content

Architecture

Wenkang Zhu edited this page Aug 10, 2026 · 3 revisions

架构设计

1. 分层模型

┌─────────────────────────────────────────────┐
│ React 前端 (src/)                           │
│  Stores (Zustand) · Components · Pages       │
│  只负责视图渲染与状态流转,不解析 shell 输出   │
└──────────────────┬──────────────────────────┘
                   │ invoke(请求/响应)  ·  event(流式)
┌──────────────────▼──────────────────────────┐
│ Tauri 命令层 (commands/)                    │
│  host · session · monitor · sftp            │
│  薄封装:参数校验 → 调用 core → 返回模型     │
└──────────────────┬──────────────────────────┘
┌──────────────────▼──────────────────────────┐
│ Core 服务层 (core/)                         │
│  session_manager · terminal_service         │
│  monitor_service · sftp_service             │
│  ssh_transport · host_service · monitor_worker│
└──────────────────┬──────────────────────────┘
┌──────────────────▼──────────────────────────┐
│ 存储 (storage/) · 模型 (models/) · 错误 (errors/)│
│  host_store · secure_store                  │
└─────────────────────────────────────────────┘

2. 核心原则

Session ≠ UI

  • SessionManager 持有真实 SSH 会话(SessionHandle),键为 sessionId
  • 前端标签页(TerminalTabs)只是视图,activeView 指向 sessionId 或 'home'
  • 关闭标签页时只调 close_session,会话生命周期由后端统一管理

通信模型

  • invoke:请求/响应。如 open_sessionsftp_list_dirwrite_terminal
  • event:流式推送。如 terminal:datasession:statusmonitor:snapshot
  • 所有 payload 均为结构化 JSON(camelCase),前后端类型定义一一对应(Rust serde rename_all = "camelCase" + TS types)

服务隔离

  • terminal_service:会话建立、PTY、终端双向 IO(约 1100 行,唯一持有终端工作线程逻辑)
  • ssh_transport:深层 SSH transport module(约 970 行),对外只暴露 Terminal / SFTP / Exec 三种 opaque capability;ssh2::Session、Channel、blocking mode 与第三方错误转换全部留在内部,不向上层泄漏
  • sftp_service:SFTP 目录浏览、传输任务队列(上传/下载/取消),每条会话复用一条独立 SFTP 连接并串行操作(约 1560 行)
  • monitor_service + monitor_worker:独立 SSH 长连接周期采集,单实例管理(共约 1000 行)
  • host_service:深层 HostConfig 持久化 module(约 950 行),拥有校验、凭据写入与引用解析、落盘与失败补偿的完整 save/delete 流程
  • session_manager:纯协调层,注册/索引/生命周期,不实现 IO 或采集(约 375 行)

连接模型(ssh_transport 深化)

  • Terminal、SFTP、Monitoring 各自使用独立底层 SSH 连接;SFTP 的 blocking IO 不再影响 Terminal 的连接级状态
  • 会话打开时并行启动 Terminal 与 SFTP 连接;首个 SFTP 请求等待正在进行的连接,后台失败交付一次后由下一次操作触发按需重连
  • Session 关闭立即移除 SFTP registry、唤醒等待者并丢弃迟到的连接结果

3. 会话生命周期

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 + message)
  → 建立后 emit terminal:data 流式输出
前端 openSession → startMonitoring(独立监控任务)
close_session → 后端统一 teardown:停止 Terminal → 清理该会话的
  Monitoring task/snapshot → 清理 SFTP 任务与共享连接 → 移除会话
  前端只清理本地投影(不主动 stop 监控)

权威性约定

  • 会话状态以后端 runtime_status 为权威:Terminal 先更新后端元数据再发事件,list_sessions 直接读取;前端只消费 session:status,不再回写
  • 任务状态以所属 module 的 registry 为权威:先更新 registry(校验迁移合法性)再发事件,迟到的迁移被拒绝且不发事件

4. 事件流

事件 方向 触发时机
terminal:data 后端 → 前端 终端输出(UTF-8,4KB 缓冲非阻塞读)
session:status 后端 → 前端 会话状态变更(Connecting/Connected/AuthFailed/Timeout/Error/Disconnected)
session:progress 后端 → 前端 连接阶段诊断(连接中的卡点提示)
monitor:snapshot 后端 → 前端 每 2 秒采集一次服务器指标
task:status 后端 → 前端 监控长任务状态变更(Pending/Running/Done/Failed)
sftp:progress 后端 → 前端 传输进度(约每 500ms)
sftp:task_status 后端 → 前端 任务状态变更(Pending/Running/Done/Failed/Cancelled)

5. 并发模型

  • 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 可并发

6. 安全设计

  • 主机配置只存 password_ref / passphrase_ref 引用键,不存明文
  • 明文凭据只存在于 SaveHostRequest 请求中,落盘前清除
  • 保存顺序:写新凭据 → 落盘(commit 点)→ 清理陈旧凭据;任一失败补偿删除本次已写入的凭据
  • 删除顺序:先落盘移除条目(commit 点),成功后再尽力清理两个凭据 key(幂等)
  • secure_store 基于 keyring(macOS Keychain / Windows Credential Manager / Linux secret-service)
  • macOS 额外启用 hardened runtime + entitlements

Clone this wiki locally