# 系统架构设计文档 (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), Change { change: JsM2B, return_code }, } // 代理 → 前端 pub enum MessageP2F { Error(String), Connected { server, own_client }, DisconnectedTemporarily(), TalkersChanged(Vec<(String, bool)>), Events(Vec), Message(JsInMessage), Loudnesses(HashMap), Result(ResultStruct), } ``` ### 6.3 IBackend / IBackendConnection ```typescript interface IBackend { createNewConnection(returnCodes: ReturnCodeTracker): IBackendConnection; graphql(query: string, variables?: Record): Promise<{data: T}>; get_settings(): Promise>; set_settings(diff: Record): Promise; } interface IBackendConnection { id: string; connect(onMsg, onError, onClose): Promise; send(data: OutMsg): void; close(): void; fetch_image(req: IFileRequest): Promise; upload_bytes(req: IFileRequest, data: Blob): Promise; } ``` ## 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 机制防止身份伪造