Files

132 lines
5.6 KiB
Markdown
Raw Permalink Normal View History

2026-07-20 19:01:03 +08:00
# 浏览频道与成员
> 用户流程:分配到默认频道 → 浏览频道列表 → 浏览频道中的人员分布 → poke 服务器内成员
> 对应程序流程:TsClient.getChannelList() 建立频道基线 → TsClient.getClientList() 建立成员基线 → 持续接收 onClient* 事件增量更新
---
## 一、状态树
### 同步状态
```mermaid
flowchart TD
SYNC[同步状态<br/>建立服务器数据基线]
SYNC --> S0[未同步 Unsynced<br/>已连接但尚无完整数据]
SYNC --> S1[同步中 Syncing<br/>调用 getChannelList 和 getClientList]
SYNC --> S2[已同步 Synchronized<br/>列表基线可供 UI 使用]
SYNC --> S3[同步失败 SyncFailed<br/>列表请求失败或上下文失效]
```
### 成员状态
```mermaid
flowchart TD
MEMBER[成员状态<br/>维护在线用户及频道位置]
MEMBER --> M0[空基线 Empty<br/>尚未执行 ListClients]
MEMBER --> M1[已有基线 Loaded<br/>getClientList 已建立成员表]
MEMBER --> M2[增量更新 Updating<br/>OnClientEnter/Leave/Moved 正在归并]
MEMBER --> M3[不一致 Inconsistent<br/>事件引用未知成员或频道]
```
### 成员实体状态树
```mermaid
flowchart TD
ENTITY[成员实体状态树<br/>描述 ListClients 基线与实时事件如何协同]
ENTITY --> BASE[基线分支<br/>由客户端请求建立完整成员集合]
ENTITY --> DELTA[增量分支<br/>由服务端推送维护实时变化]
ENTITY --> SELF[当前用户分支<br/>通过 ClientID 识别自己的事件]
ENTITY --> REPAIR[修复分支<br/>处理事件缺失或引用不一致]
BASE --> B1[getClientList 请求<br/>获取服务器当前全部在线客户端]
B1 --> B2[按 clientID 建表<br/>使用客户端 ID 去重保存]
B2 --> B3[按 channelID 建索引<br/>派生每个频道的成员列表]
DELTA --> D1[onClientEnter<br/>新增或覆盖进入视野的成员]
DELTA --> D2[onClientMoved<br/>覆盖成员的 channelID]
DELTA --> D3[onClientLeave<br/>按 clientID 幂等删除成员]
SELF --> S1[getClientId 本地调用<br/>读取服务器分配的自身 ID]
S1 --> S2[事件 clientID 比对<br/>判断移动或离开事件是否属于自己]
S2 --> S3[更新自身频道事实<br/>自己的移动决定实际所在频道]
REPAIR --> R1[检测未知 clientID<br/>移动或离开事件找不到实体]
R1 --> R2[重新调用 getClientList<br/>用完整列表修复成员基线]
REPAIR --> R3[检测未知 channelID<br/>成员引用本地不存在的频道]
R3 --> R4[重新调用 getChannelList<br/>用完整列表修复频道基线]
```
---
## 二、时序:成员进入、移动与离开
```mermaid
sequenceDiagram
participant TS as TeamSpeak 服务器<br/>产生在线成员变化
participant SDK as Go SDK (gomobile)<br/>解析 notify* 通知
participant BRIDGE as TSBridge<br/>JNI 回调转 EventBus
participant EB as EventBus<br/>事件合并与分发
participant REDUCER as ViewModel<br/>debounce 后刷新成员
participant STORE as 成员实体仓库<br/>以 clientID 保存唯一成员
participant UI as 频道树 UI<br/>派生人数和成员预览
TS-->>SDK: notifycliententerview
SDK->>BRIDGE: OnClientEnter(Client)
BRIDGE->>EB: emit(ClientEnter)
TS-->>SDK: notifyclientmoved
SDK->>BRIDGE: OnClientMoved(id, channelID)
BRIDGE->>EB: emit(ClientMoved)
TS-->>SDK: notifyclientleftview
SDK->>BRIDGE: OnClientLeave(id, reason)
BRIDGE->>EB: emit(ClientLeave)
Note over EB: debounce 300ms 合并
EB->>REDUCER: collect → refreshClientList()
REDUCER->>STORE: TSBridge.getClientsJSON() → 全量刷新
STORE-->>UI: 实体引用变化
```
---
## 三、事件依赖
### 成员相关前置依赖矩阵
| 操作或事件 | 必须依赖 | 建议依赖 | 依赖失败时的处理 |
| --- | --- | --- | --- |
| `getClientsJSON` 增量归并 | 已有频道基线更易校验 | 与 `getChannelsJSON` 同一同步批次 | 未知频道触发频道补偿读取 |
| `ClientEnter` 事件 | 已注册 EventBus 事件收集 | 已有成员基线 | debounce 后全量刷新 |
| `ClientMoved` 事件 | 已注册 EventBus 事件收集 | 已有成员基线和自身 ID | debounce 后全量刷新 |
| `ClientLeave` 事件 | 已注册 EventBus 事件收集 | 已有成员基线 | debounce 后全量刷新 |
### 服务端通知映射
| 服务端通知 | TSBridge 回调 → EventBus 事件 | 上层状态依赖 | 中文说明 |
| --- | --- | --- | --- |
| `notifycliententerview` | `OnClientEnter``ClientEnter` | 成员实体表、频道成员 Selector | 新成员进入视野后 debounce 合并刷新 |
| `notifyclientleftview` | `OnClientLeave``ClientLeave` | 成员实体表、离开原因 | debounce 合并刷新 |
| `notifyclientmoved` | `OnClientMoved``ClientMoved` | 成员位置、当前用户频道 | debounce 合并刷新 |
| `notifyclientpoke` | `OnPoked``Poked` | Poke 通知或成员卡 | 立即分发,展示发送者和 Poke 内容 |
### 缺失事件能力带来的依赖限制
根据 SDK 文档,当前公开事件不包含频道创建、频道更新和频道删除。因此:
1. `TsClient.getChannelList()` 是频道目录的主要权威来源。
2. 不能假设频道列表会依靠 `onClient*` 事件永久保持最新。
3. 发现成员引用未知频道时,应重新调用 `TsClient.getChannelList()`
4. 如果产品需要实时频道管理,应扩展 SDK 对相应 `notify*` 通知的支持。
### 权威性划分
| 数据 | 推荐权威来源 | 原因 |
| --- | --- | --- |
| 成员实时变化 | EventBus `ClientEnter/Leave/Moved` 事件 | 服务端主动推送实时事实,debounce 后全量刷新 |