77 lines
4.2 KiB
Markdown
77 lines
4.2 KiB
Markdown
# 架构重构(单独轨道,尚未开始)
|
||
|
||
**当前不要做。** 改动面覆盖几乎全部 `src-tauri` 服务、`src/desktop.d.ts`、`src/platform/*` 和测试替身。本文件只记录怎么拆,避免和日常功能 PR 缠在一起。
|
||
|
||
当前真实分层是 **commands → services → domain DTO**。目录里虽有 `application/`、`infrastructure/`,但:
|
||
|
||
- `infrastructure/` 只有 `file_log`,services 并不走它。
|
||
- `application/state.rs` 是服务集合,不是端口组合根。
|
||
- 稳定 IPC 错误码放在 `domain/error.rs` 的 `codes`(如 `native.taskJoin`),不是空壳 `DomainError` 类型。
|
||
- SSH / 存储 / 桌面服务直接 `use tauri::AppHandle`;known_hosts 还用 `bind_app_handle` 全局 static。
|
||
- 前后端契约靠手写 `src/desktop.d.ts` + `shared/types/`,没有 specta / ts-rs。
|
||
|
||
产品数据流保持不变:UI → Zustand → `src/platform/*` → Tauri command → Rust 服务。重构不得把 SSH、文件系统或加密拉回 React,也不得改成插件宿主。
|
||
|
||
## 为什么单独做
|
||
|
||
1. EventSink 要改所有 `app.emit` 调用点,和功能修复冲突时极难回滚。
|
||
2. specta 会动 command 签名和前端 `invoke` 形状,必须一次对齐 CI,不能「先生成一半」。
|
||
3. 把 storage / SSH / 凭据收进 infrastructure trait,等于重写生命周期,和转发 retain、桌面 worker 取消语义绑在一起。
|
||
|
||
一次只开一条轨道,合入后再开下一条。每条轨道自己的 PR,跑 `npm run test:patrol` 和 `npm run acceptance:full`。
|
||
|
||
## 轨道 A:EventSink(先做,最小)
|
||
|
||
目标:services 不再拿 `AppHandle`,也不再 `bind_app_handle`。
|
||
|
||
1. 在 `application/` 定义:
|
||
|
||
```rust
|
||
pub trait EventSink: Send + Sync {
|
||
fn emit_json(&self, channel: &str, payload: serde_json::Value);
|
||
fn emit_empty(&self, channel: &str);
|
||
}
|
||
```
|
||
|
||
2. `TauriEventSink(AppHandle)` 只放在 application / command 边界。
|
||
3. `SshService`、known_hosts、RDP/VNC engine、license 等改为持有 `Arc<dyn EventSink>`。
|
||
4. 删除 `known_hosts` 的 `APP_HANDLE` / `PENDING` / `ONCE_TRUSTED` 全局 static,收进 `AppState`。
|
||
5. 单测用内存 `EventSink` 断言事件,不启 Tauri。
|
||
|
||
完成标准:`rg "use tauri::AppHandle" src-tauri/src/services` 为空(command 层可以留)。行为与现网事件名、payload 完全一致。
|
||
|
||
## 轨道 B:契约生成(specta 或 ts-rs)
|
||
|
||
目标:消灭「Rust DTO / `desktop.d.ts` / `shared/types`」三处手工对齐。
|
||
|
||
1. 选一个:`tauri-specta`(和 command 绑定)或 `ts-rs`(只生成类型)。不要两个一起上。
|
||
2. Rust 侧先把 `serde_json::Value` 逃逸收成强类型(`ProxyConfig`、`JumpHostConfig`、会话字段)。
|
||
3. 生成文件放到例如 `shared/types/*.generated.ts`,CI 跑 `git diff --exit-code`。
|
||
4. 手写 `src/desktop.d.ts` 只留窗口/`opsxApi` 外壳,领域类型改 re-export 生成结果。
|
||
5. `test/setup.ts` 跟着生成类型改,不要继续复制一份松散 `unknown`。
|
||
|
||
完成标准:改一个 command 字段,忘跑生成则 CI 红。不要在这一轨改 EventSink 或换存储引擎。
|
||
|
||
## 轨道 C:infrastructure 端口(最后)
|
||
|
||
目标:I/O 可替换,services 只编排。
|
||
|
||
建议端口(按需,不要一次全铺):
|
||
|
||
| Trait | 先搬谁 | 不要顺便做 |
|
||
| -------------- | ---------------------------------- | ----------------------- |
|
||
| `SessionStore` | `services/storage.rs` 的 JSON 会话 | 不要同时改成 SQLite |
|
||
| `SecretStore` | `credential_store.rs` | 不要同时改系统 keychain |
|
||
| `SshTransport` | 仅当要换 russh 时再抽 | 默认保持 libssh2 |
|
||
|
||
`infrastructure/mod.rs` 里现在的「SQLite / keychain / PTY 适配器」是过期注释,做 C 轨时改成与真实 trait 一致,没做的删掉,避免再写成已存在。
|
||
|
||
IPC 错误码继续用 `domain/error.rs` 的 `codes` 常量,不要再加一层空壳 `DomainError`。
|
||
|
||
## 明确不做(本轨道也不做)
|
||
|
||
- 六边形/整仓重命名目录来「看起来像五层」。
|
||
- 对外 CLI、MCP、插件宿主。
|
||
- 把结账/签发搬回桌面进程。
|
||
- 和签名、公证、自动更新、功能修复混在同一个 PR。
|