Skip to content

Backend

Seeker32 edited this page Aug 11, 2026 · 4 revisions

Rust 后端(src-tauri)

模块结构

src-tauri/src/
├── lib.rs            # 应用入口:注册插件、SessionManager/MonitorService/SftpService、16 个 invoke 命令
├── main.rs           # 启动入口
├── commands/         # Tauri 命令层(薄封装,只委托,无业务逻辑)
│   ├── host.rs       #   list_hosts / save_host / delete_host
│   ├── session.rs    #   open_session / close_session / write_terminal /
│   │                 #   resize_terminal / list_sessions
│   ├── monitor.rs    #   start_monitoring / stop_monitoring / get_monitor_status
│   ├── sftp.rs       #   sftp_list_dir / sftp_download / sftp_upload / sftp_cancel_task
│   └── logging.rs    #   set_log_level
├── core/             # 核心服务层
│   ├── session_manager.rs  # 会话协调器(纯协调,不实现 IO)
│   ├── terminal_service.rs # 终端服务(连接 + PTY + 双向 IO 工作线程)
│   ├── ssh_transport.rs    # 深层 SSH transport(Terminal/SFTP/Exec opaque capability)
│   ├── host_service.rs     # 深层 HostConfig 持久化(校验 + 凭据 + 补偿)
│   ├── monitor_service.rs  # 监控任务生命周期管理(单实例 + 任务状态单一事实)
│   ├── monitor_worker.rs   # 采集循环(注入 connect_fn + /proc 解析 + 网络速率)
│   └── sftp_service.rs     # SFTP 目录 + 传输任务队列(任务状态单一事实)
├── models/           # 数据模型(serde camelCase)
│   ├── host.rs       #   HostConfig / SaveHostRequest / AuthType(含 group 分组)
│   ├── session.rs    #   SessionInfo / SessionStatus / 事件 payload
│   ├── monitor.rs    #   MonitorSnapshot / NetworkInterface / NetworkSnapshot / TaskInfo / TaskStatus
│   └── sftp.rs       #   RemoteEntry / TransferTask / TransferType / SftpTaskStatus / 事件 payload
├── storage/          # 持久化 adapter
│   ├── host_store.rs #   主机配置 JSON 文件存取(app config dir)
│   └── secure_store.rs # OS 安全存储(keyring,密码/私钥口令)
└── errors/
    └── app_error.rs  # AppError(thiserror)+ AppErrorInfo(稳定错误码)

核心服务说明

HostConfigService(host_service.rs,约 960 行)

  • 深层持久化 module:校验 → 加载列表 → 写新凭据并解析引用 → 构造 HostConfig → upsert → 落盘(commit 点)→ 切换 auth type 时清理陈旧凭据
  • HostConfig.group 分组字段:空串表示"未分组",保存/删除/迁移由 service 统一处理
  • CredentialStore adapter seam(set/delete):真实实现包装 OS secure storage,测试用内存实现可注入失败
  • 失败补偿:写新凭据或落盘失败时,删除本次已写入的凭据,保持安全存储与 hosts.json 一致;删除时先落盘再清理凭据,凭据删除失败不阻断
  • command adapter 只构造并委托;open_session 也经 service.get_host 查询主机

SessionManager(session_manager.rs,约 375 行)

  • SessionHandle:meta + runtime_status + command_tx + shutdown + host,组成活跃会话
  • HashMap<String, SessionHandle> 索引所有真实会话;runtime_status 为后端权威状态
  • 锁只用于短暂注册/查找;open / close 在锁外启动或清理其他 module(MonitorService / SftpService 分别注册为独立 Tauri State)

TerminalService(terminal_service.rs,约 1030 行)

  • start_terminal_session:完整连接流程,按 ConnectionPhase 分阶段
  • 每个阶段带超时(run_phase_with_timeout),失败映射到具体 SessionStatus 并携带 AppErrorInfo
  • 状态变更先更新 runtime_status 再 emit session:status(权威路径)
  • 工作线程:非阻塞读取 stdout(4KB 缓冲)→ UTF-8 解码 → emit terminal:data
  • 命令队列:TerminalCommand::{Input, Resize, Shutdown} 通过 mpsc 接收

SshTransport(ssh_transport.rs,约 975 行)

  • 对外只提供 Terminal / SFTP / Exec 三种 opaque capability;ssh2::Session、Channel、SFTP handle、blocking mode 与第三方错误转换均留在 implementation 内
  • Terminal、SFTP、Monitoring 各自独立底层 SSH 连接;SFTP blocking IO 不影响 Terminal 连接级状态
  • 会话打开并行建立 Terminal 与 SFTP 连接;SFTP 连接失败只交付一次,后续操作按需重连;Session 关闭丢弃迟到连接结果
  • 真实 SSH 并发 E2E 由环境变量 TITAN_SSH_E2E_* 驱动(未配置时 ignored)

MonitorService + MonitorWorker(约 590 + 700 行)

  • MonitorService:start/stop/get_status,维护 taskId 与 session 映射;transition_task_status 为单一迁移入口(先更新 registry 校验合法性,再 emit task:status
  • MonitorWorker:独立 SSH 连接,每 2 秒执行采集脚本一次
  • 采集脚本解析 /proc/meminfo/proc/stat(CPU 增量计算)、df -B1 //proc/net/dev(网络接口 RX/TX 速率,不含 lo,相邻采样差)
  • 连接/采集失败走 transition 为 Failed(终态),不自动重连;stop 后迟到的迁移被拒绝且不发事件

SftpService(sftp_service.rs,约 1600 行)

  • 每条会话复用一条独立 SFTP 连接并串行远程操作;registry 锁只用于短暂查找
  • enqueue_download / enqueue_upload:任务入队(Pending),后台线程执行
  • transition_task:单一迁移入口,先更新 registry(含 error)再 emit sftp:task_status;终态迁移同步移除取消令牌
  • CancelToken(Arc)支持任务取消;cleanup_session 以 registry 为权威,终态任务不重复取消,清理后整会话任务移除
  • 进度约每 500ms emit 一次 sftp:progress;测试使用内存 SFTP adapter(memory_sftp)覆盖真实 worker 全链路

错误模型(errors/app_error.rs)

  • AppError:应用层错误枚举(SSH 连接/认证、会话、存储、SFTP 等 13 类),code() 返回稳定英文错误码(如 SshConnectionErrorCredentialNotFound
  • AppErrorInfo:跨 Tauri 边界的 IPC 错误 payload({ code, detail }),语言无关;detail 保留底层诊断供前端本地化展示
  • 命令层统一 map_err(AppErrorInfo::from),不再向前端泄漏底层库错误类型

Storage

  • HostStore:hosts.json 存储于 Tauri app config dir,增删改查 + 排序
  • SecureStorepassword_key(host_id) / passphrase_key(host_id) 作为 keyring 条目键

技术依赖

依赖 用途
tauri 2.10.3 应用框架(无额外 feature)
ssh2 0.9 SSH 协议(libssh2 绑定)
tokio 1 异步运行时(仅 sync / rt / rt-multi-thread / macros,按需 feature)
keyring 3.6 OS 凭据存储(apple-native / windows-native / sync-secret-service)
uuid / chrono 任务 ID 与毫秒时间戳
thiserror / anyhow 错误处理
log + env_logger 后端日志(等级由 set_log_level 运行时调整)
tauri-plugin-shell / tauri-plugin-dialog shell 与文件对话框

开发依赖

  • proptest 1.4(属性测试)、mockall 0.12(mock)、tauri test feature
  • macOS 附加 security-framework 3.7

测试覆盖

#[cfg(test)] 存在于:host_service(save/delete 组合与补偿、无明文 proptest)、session_manager、terminal_service、ssh_transport、monitor_worker(含网络速率解析)、monitor_service(迁移合法性)、sftp_service(worker 全链路 + transition)、models(proptest)、storage(host_store、secure_store)、errors(错误码稳定)、commands(logging 等级解析)。运行:cd src-tauri && cargo test

Clone this wiki locally