Files
re-teamspeak/docs/architecture.md
T
ReTeamSpeak ea08823c97
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
Initial commit: ReTeamSpeak cross-platform TeamSpeak client
- 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
2026-05-12 14:41:54 +09:00

14 KiB

系统架构设计文档 (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

pub trait AppToFrontendBridge {
    fn send(&self, msg: &MessageP2F);
    fn close(&self);
}

6.2 MessageF2P / MessageP2F

// 前端 → 代理
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

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 机制防止身份伪造