Initial commit: ReTeamSpeak cross-platform TeamSpeak client
CI/CD / Build Frontend (push) Failing after 11s
CI/CD / Test (macos-latest) (push) Has been cancelled
CI/CD / Test (windows-latest) (push) Has been cancelled
CI/CD / Build Desktop (linux) (push) Has been cancelled
CI/CD / Build Desktop (macos) (push) Has been cancelled
CI/CD / Build Desktop (windows) (push) Has been cancelled
CI/CD / Release (push) Has been cancelled
CI/CD / Test (ubuntu-latest) (push) Failing after 2s
CI/CD / Build Frontend (push) Failing after 11s
CI/CD / Test (macos-latest) (push) Has been cancelled
CI/CD / Test (windows-latest) (push) Has been cancelled
CI/CD / Build Desktop (linux) (push) Has been cancelled
CI/CD / Build Desktop (macos) (push) Has been cancelled
CI/CD / Build Desktop (windows) (push) Has been cancelled
CI/CD / Release (push) Has been cancelled
CI/CD / Test (ubuntu-latest) (push) Failing after 2s
- tscore: Protocol implementation (packets, crypto, connection handshake) - tsaudio: Audio engine (capture, playback, codec, VAD, jitter buffer) - tsdb: SQLite database (identities, bookmarks, messages, settings) - shared: Core types and events - tauri-app: Tauri v2 desktop application with React frontend - docs: SRS, SAD, SDD documentation - CI/CD: GitHub Actions workflow - 32 unit tests passing
This commit is contained in:
@@ -0,0 +1,401 @@
|
||||
# 系统架构设计文档 (SAD)
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档描述 TeamSpeak 3 客户端系统的整体架构设计,基于对参考代码库(tsclientlib、Qint、SimpleBot、ts3stats)的分析结果。
|
||||
|
||||
## 2. 系统架构图
|
||||
|
||||
```
|
||||
+-----------------------------------------------------------------------+
|
||||
| 前端层 (Frontend) |
|
||||
| |
|
||||
| +-----------+ +----------+ +--------+ +------+ +-----+ +-----+ |
|
||||
| | 连接对话框 | | 聊天视图 | | 频道树 | | 面板 | |文件 | |插件 | |
|
||||
| +-----------+ +----------+ +--------+ +------+ +-----+ +-----+ |
|
||||
| |
|
||||
| +---------------------------+ +--------------------------+ |
|
||||
| | 连接状态管理 | | 数据状态镜像 | |
|
||||
| +---------------------------+ +--------------------------+ |
|
||||
| |
|
||||
| +------------------------------------------------------------------+ |
|
||||
| | 后端抽象层 (Backend Abstraction) | |
|
||||
| | IBackend <--- TauriBackend / BrowserBackend ---> | |
|
||||
| +------------------------------------------------------------------+ |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Tauri: IPC (invoke + event) | Browser: WebSocket + HTTP
|
||||
v v
|
||||
+-----------------------------------------------------------------------+
|
||||
| 壳层 (Shell Layer) |
|
||||
| |
|
||||
| 桌面壳 (Tauri) Web壳 (Actix-web) |
|
||||
| +---------------------+ +------------------------+ |
|
||||
| | 命令处理器 | | REST/WebSocket 端点 | |
|
||||
| | 窗口桥接器 | | GraphQL 端点 | |
|
||||
| +---------------------+ +------------------------+ |
|
||||
| | 核心协调器 | | WebSocket 处理器 | |
|
||||
| | 文件传输管理器 | +------------------------+ |
|
||||
| +---------------------+ |
|
||||
+-----------------------------------------------------------------------+
|
||||
| |
|
||||
| 共享依赖 |
|
||||
v v
|
||||
+-----------------------------------------------------------------------+
|
||||
| 代理库 (Proxy Library) - 核心业务逻辑 |
|
||||
| |
|
||||
| +---------------------+ +--------------------+ +----------------+ |
|
||||
| | 全局状态管理 | | 连接管理器 | | 数据库管理器 | |
|
||||
| | (QintState) | | (QintConnection) | | (DbHandler) | |
|
||||
| +---------------------+ +--------------------+ +----------------+ |
|
||||
| +--------------------+ +----------------+ |
|
||||
| | 音频管道 | | 工具组件 | |
|
||||
| | AudioToTs | | 文件缓存 | |
|
||||
| | TsToAudio | | 链接预览 | |
|
||||
| +--------------------+ | 全文搜索 | |
|
||||
| | 热键管理 | |
|
||||
| | 身份加密 | |
|
||||
| +----------------+ |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
|
||||
| 依赖
|
||||
v
|
||||
+-----------------------------------------------------------------------+
|
||||
| 代码生成层 (proxy-codegen) |
|
||||
| |
|
||||
| build.rs 读取 tsproto-structs -> 生成: |
|
||||
| - Rust: JsEvent, JsProperty, JsM2B, convert_event() 等 |
|
||||
| - TypeScript: book_events.ts (PropertyId, PropertyValue, OChange) |
|
||||
+-----------------------------------------------------------------------+
|
||||
|
|
||||
v
|
||||
+-----------------------------------------------------------------------+
|
||||
| TeamSpeak 协议库 (tsclientlib / tsproto) |
|
||||
| - TeamSpeak 协议实现 |
|
||||
| - 连接管理、状态维护、音频编解码 |
|
||||
| - 事件系统(属性变更、消息、音频) |
|
||||
+-----------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## 3. 分层架构
|
||||
|
||||
### 3.1 前端层 (Frontend Layer)
|
||||
|
||||
**职责**: 用户界面展示和用户交互处理
|
||||
|
||||
**技术栈**: Svelte 5 + TypeScript + Rsbuild
|
||||
|
||||
**主要组件**:
|
||||
- **连接对话框**: 服务器连接配置界面
|
||||
- **聊天视图**: 文本消息收发界面
|
||||
- **频道树**: 频道和客户端树状视图
|
||||
- **面板**: 设置、文件浏览器等侧边面板
|
||||
- **插件系统**: 动态加载的插件模块
|
||||
|
||||
**关键特性**:
|
||||
- 响应式状态管理 (Svelte stores)
|
||||
- 跨平台兼容 (Tauri/Web)
|
||||
- 实时事件更新
|
||||
|
||||
### 3.2 壳层 (Shell Layer)
|
||||
|
||||
**职责**: 平台特定的传输适配和系统集成
|
||||
|
||||
**两种实现**:
|
||||
|
||||
#### 3.2.1 桌面壳 (Tauri Desktop)
|
||||
- **技术栈**: Rust + Tauri v2
|
||||
- **职责**:
|
||||
- 原生窗口管理
|
||||
- 系统托盘集成
|
||||
- 文件对话框
|
||||
- 全局热键
|
||||
- IPC 通信 (invoke + event)
|
||||
|
||||
#### 3.2.2 Web 壳 (Actix-web Server)
|
||||
- **技术栈**: Rust + Actix-web
|
||||
- **职责**:
|
||||
- HTTP REST 端点
|
||||
- WebSocket 通信
|
||||
- GraphQL 查询端点
|
||||
- 静态文件服务
|
||||
|
||||
### 3.3 代理层 (Proxy Layer)
|
||||
|
||||
**职责**: 核心业务逻辑,平台无关
|
||||
|
||||
**技术栈**: Rust + Actix actor 模型
|
||||
|
||||
**主要组件**:
|
||||
|
||||
#### 3.3.1 QintState (全局状态管理)
|
||||
- 连接映射管理
|
||||
- 音频数据管理
|
||||
- 热键配置
|
||||
- 设置管理
|
||||
- 文件缓存
|
||||
- 链接预览
|
||||
- 全文搜索索引
|
||||
|
||||
#### 3.3.2 QintConnection (连接管理器)
|
||||
- TeamSpeak 服务器连接生命周期
|
||||
- 事件处理和分发
|
||||
- 消息路由
|
||||
- 音频路由
|
||||
- 文件传输管理
|
||||
|
||||
#### 3.3.3 DbHandler (数据库管理器)
|
||||
- SQLite/Diesel ORM
|
||||
- 身份管理
|
||||
- 服务器/书签管理
|
||||
- 聊天消息存储
|
||||
- GraphQL 查询支持
|
||||
|
||||
#### 3.3.4 音频管道
|
||||
- **AudioToTs**: 麦克风采集 → Opus 编码 → 发送到服务器
|
||||
- **TsToAudio**: 接收服务器音频 → Opus 解码 → 混音 → 播放
|
||||
- 支持 SDL2 (桌面) 和 Oboe (Android) 后端
|
||||
|
||||
### 3.4 代码生成层 (Code Generation Layer)
|
||||
|
||||
**职责**: 从协议定义自动生成类型安全的代码
|
||||
|
||||
**输入**: tsproto-structs 的 TOML/CSV 声明文件
|
||||
|
||||
**输出**:
|
||||
- Rust 类型 (JsEvent, JsProperty, JsM2B 等)
|
||||
- TypeScript 类型 (book_events.ts)
|
||||
- 事件转换函数
|
||||
- 消息序列化/反序列化代码
|
||||
|
||||
### 3.5 协议库层 (Protocol Library Layer)
|
||||
|
||||
**职责**: TeamSpeak 3 协议的底层实现
|
||||
|
||||
**主要组件**:
|
||||
|
||||
#### 3.5.1 tsclientlib (高层客户端库)
|
||||
- 连接配置和构建
|
||||
- 状态同步
|
||||
- 音频处理
|
||||
- 地址解析 (IP/DNS SRV/TSDNS)
|
||||
|
||||
#### 3.5.2 tsproto (协议引擎)
|
||||
- UDP 数据包处理
|
||||
- 加密/解密 (AES-128-EAX)
|
||||
- 压缩/解压 (QuickLZ)
|
||||
- 可靠传输 (CUBIC 拥塞控制)
|
||||
- 连接握手
|
||||
|
||||
#### 3.5.3 ts-bookkeeping (状态管理)
|
||||
- 服务器状态维护
|
||||
- 客户端/频道/组数据
|
||||
- 事件生成
|
||||
|
||||
#### 3.5.4 tsproto-packets (包解析)
|
||||
- 数据包格式定义
|
||||
- 命令解析器
|
||||
- 零拷贝解析
|
||||
|
||||
## 4. 设计模式
|
||||
|
||||
### 4.1 Actor 模型
|
||||
- 使用 Actix 框架实现并发隔离
|
||||
- 每个 TeamSpeak 连接是独立的 Actor
|
||||
- 通过消息传递进行通信
|
||||
|
||||
### 4.2 桥接模式
|
||||
- `AppToFrontendBridge` trait 解耦核心逻辑和传输层
|
||||
- 两种实现: WindowBridge (Tauri) 和 WsBridge (Web)
|
||||
|
||||
### 4.3 策略模式
|
||||
- 前端的 `IBackend` 接口
|
||||
- 两种实现: TauriBackend 和 BrowserBackend
|
||||
|
||||
### 4.4 代码生成模式
|
||||
- 从声明式 TOML/CSV 生成重复代码
|
||||
- 确保类型安全和一致性
|
||||
|
||||
### 4.5 状态机模式
|
||||
- 连接状态管理 (Uninitialized → Connecting → Connected → Disconnected)
|
||||
|
||||
### 4.6 观察者模式
|
||||
- Svelte stores 实现响应式状态传播
|
||||
- 事件系统实现组件间通信
|
||||
|
||||
## 5. 数据流
|
||||
|
||||
### 5.1 入站数据流 (服务器 → 应用)
|
||||
|
||||
```
|
||||
UDP Socket
|
||||
↓
|
||||
Connection::poll_incoming_udp_packet()
|
||||
↓
|
||||
PacketCodec::handle_udp_packet()
|
||||
├── 解密 (AES-128-EAX)
|
||||
├── 重组分片
|
||||
├── 解压 (QuickLZ)
|
||||
└── 生成 StreamItem
|
||||
├── Command → InCommandBuf
|
||||
├── Audio → InAudioBuf
|
||||
└── Ack → 更新发送队列
|
||||
↓
|
||||
Client::handle_command()
|
||||
↓
|
||||
Connection (tsclientlib)::poll_next()
|
||||
├── 解析为 InMessage
|
||||
├── 应用到 data::Connection 状态
|
||||
├── 生成 events::Event
|
||||
└── 返回 StreamItem::BookEvents
|
||||
```
|
||||
|
||||
### 5.2 出站数据流 (应用 → 服务器)
|
||||
|
||||
```
|
||||
应用层调用
|
||||
↓
|
||||
OutCommandExt::send_with_result()
|
||||
↓
|
||||
Connection::send_command_with_result()
|
||||
├── 添加 return_code
|
||||
├── 更新本地状态
|
||||
↓
|
||||
client::Client::send_packet()
|
||||
↓
|
||||
PacketCodec::encode_packet()
|
||||
├── 压缩 + 分片 (QuickLZ)
|
||||
├── 加密 (AES-128-EAX)
|
||||
└── 分配 packet_id
|
||||
↓
|
||||
Resender::send_packet()
|
||||
├── 加入发送队列
|
||||
└── CUBIC 拥塞控制
|
||||
↓
|
||||
UDP Socket 发送
|
||||
```
|
||||
|
||||
### 5.3 音频数据流
|
||||
|
||||
```
|
||||
麦克风 → AudioToTs (Actor)
|
||||
├── VAD 检测
|
||||
├── 响度测量
|
||||
├── Opus 编码
|
||||
└── 发送到服务器
|
||||
|
||||
服务器 → tsclientlib::Connection
|
||||
├── AudioData::S2C
|
||||
└── TsToAudio (Actor)
|
||||
├── Opus 解码
|
||||
├── 每客户端音量
|
||||
├── 混音
|
||||
├── 噪声抑制
|
||||
└── SDL2/Oboe 输出
|
||||
```
|
||||
|
||||
## 6. 关键接口
|
||||
|
||||
### 6.1 AppToFrontendBridge
|
||||
```rust
|
||||
pub trait AppToFrontendBridge {
|
||||
fn send(&self, msg: &MessageP2F);
|
||||
fn close(&self);
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 MessageF2P / MessageP2F
|
||||
```rust
|
||||
// 前端 → 代理
|
||||
pub enum MessageF2P {
|
||||
Connect(ConnectOptions),
|
||||
Disconnect(DisconnectOptions),
|
||||
SendMessage { target, message, return_code },
|
||||
SetClientVolume { client, volume },
|
||||
SetWhispering(Option<WhisperData>),
|
||||
Change { change: JsM2B, return_code },
|
||||
}
|
||||
|
||||
// 代理 → 前端
|
||||
pub enum MessageP2F {
|
||||
Error(String),
|
||||
Connected { server, own_client },
|
||||
DisconnectedTemporarily(),
|
||||
TalkersChanged(Vec<(String, bool)>),
|
||||
Events(Vec<JsEvent>),
|
||||
Message(JsInMessage),
|
||||
Loudnesses(HashMap<String, f32>),
|
||||
Result(ResultStruct),
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 IBackend / IBackendConnection
|
||||
```typescript
|
||||
interface IBackend {
|
||||
createNewConnection(returnCodes: ReturnCodeTracker): IBackendConnection;
|
||||
graphql<T>(query: string, variables?: Record<string, unknown>): Promise<{data: T}>;
|
||||
get_settings(): Promise<Record<string, unknown>>;
|
||||
set_settings(diff: Record<string, unknown>): Promise<void>;
|
||||
}
|
||||
|
||||
interface IBackendConnection {
|
||||
id: string;
|
||||
connect(onMsg, onError, onClose): Promise<void>;
|
||||
send(data: OutMsg): void;
|
||||
close(): void;
|
||||
fetch_image(req: IFileRequest): Promise<string | undefined>;
|
||||
upload_bytes(req: IFileRequest, data: Blob): Promise<TransferResult>;
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 平台适配
|
||||
|
||||
| 功能 | 桌面 (Tauri) | Web (Browser) | Android |
|
||||
|------|-------------|---------------|---------|
|
||||
| 音频后端 | SDL2 | N/A | Oboe |
|
||||
| TLS | OpenSSL | N/A | rustls |
|
||||
| 文件对话框 | Tauri 插件 | HTML input | Tauri |
|
||||
| 系统托盘 | Tauri tray-icon | N/A | N/A |
|
||||
| 全局热键 | livesplit-hotkey | N/A | N/A |
|
||||
|
||||
## 8. 依赖关系
|
||||
|
||||
```
|
||||
src-tauri ──────depends on──────> qint-proxy ──────depends on──────> tsclientlib
|
||||
│ │ │
|
||||
└──depends on──> proxy-codegen ────┘ tsproto
|
||||
│ │ tsproto-packets
|
||||
└──depends on──> tauri v2 └──depends on──> diesel (SQLite) tsproto-types
|
||||
└──depends on──> audiopus/opus
|
||||
└──depends on──> sdl2/oboe
|
||||
└──depends on──> tantivy (search)
|
||||
└──depends on──> juniper (GraphQL)
|
||||
|
||||
webapp ──────depends on──────> qint-proxy (same as above)
|
||||
│
|
||||
└──depends on──> actix-web
|
||||
└──depends on──> proxy-codegen
|
||||
```
|
||||
|
||||
## 9. 关键技术决策
|
||||
|
||||
| 决策 | 选择 | 理由 |
|
||||
|------|------|------|
|
||||
| 异步运行时 | Tokio | Rust 生态最成熟的异步运行时 |
|
||||
| Actor 框架 | Actix | 成熟的 Actor 模型实现 |
|
||||
| 加密 | AES-128-EAX + ECDH | TeamSpeak 协议规范要求 |
|
||||
| 压缩 | QuickLZ | TeamSpeak 协议使用的压缩算法 |
|
||||
| 拥塞控制 | CUBIC | 类似 TCP CUBIC,适合实时通信 |
|
||||
| 代码生成 | t4rust-derive | 从声明式数据生成大量重复代码 |
|
||||
| 音频编解码 | Opus | TeamSpeak 3 默认编解码器 |
|
||||
| 数据库 | SQLite + Diesel | 轻量级嵌入式数据库 + 类型安全 ORM |
|
||||
| 前端框架 | Svelte 5 | 轻量级响应式框架 |
|
||||
| 桌面框架 | Tauri v2 | 跨平台原生桌面应用 |
|
||||
| Web 框架 | Actix-web | 高性能 Rust Web 框架 |
|
||||
|
||||
## 10. 安全考虑
|
||||
|
||||
1. **身份加密**: 使用 ChaCha20-Poly1305 加密存储身份私钥
|
||||
2. **传输加密**: 使用 AES-128-EAX 加密所有命令和语音数据
|
||||
3. **密钥交换**: 使用 ECDH (prime256v1) 进行密钥交换
|
||||
4. **防 DoS**: 使用 RSA 拼图防止连接洪水攻击
|
||||
5. **身份验证**: 使用 Hashcash 机制防止身份伪造
|
||||
Reference in New Issue
Block a user