首次推送
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
# 连接服务器
|
||||
|
||||
> 用户流程:输入服务器地址 → 输入昵称 → 输入密码(可选) → 点击进入服务器 → 连接成功 → 首次同步
|
||||
> 对应程序流程:准备配置 → TSBridge.connect() → EventBus 收到 Connected 事件 → 首次同步
|
||||
|
||||
---
|
||||
|
||||
## 一、生命周期
|
||||
|
||||
### 1.1 完整生命周期
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[准备配置<br/>地址、昵称、密码] --> B[TSBridge.connect<br/>组装连接参数并注册 EventCallback]
|
||||
B --> C[Go SDK Connect<br/>通过 gomobile 发起 UDP 会话与协议握手]
|
||||
C --> D{连接请求是否成功<br/>判断 connect 返回值}
|
||||
D -- 否 --> E[连接失败处理<br/>记录错误并释放客户端资源]
|
||||
D -- 是 --> F{是否已收到 Connected 事件<br/>等待 EventBus 连接就绪事件}
|
||||
F -- 否 --> G[等待失败处理<br/>处理超时或握手异常]
|
||||
F -- 是 --> H[EventBus Connected 事件<br/>接收连接成功事件]
|
||||
H --> I[首次同步<br/>请求频道、成员和自身身份信息]
|
||||
I --> J[运行就绪<br/>允许发送命令、聊天和语音]
|
||||
J --> K[持续接收 EventBus 事件<br/>归并成员、移动、消息和 Poke]
|
||||
K --> J
|
||||
J --> L{结束原因<br/>区分主动断开与被动中断}
|
||||
L -- 用户主动退出 --> M[TSBridge.disconnect<br/>发送优雅关闭请求]
|
||||
L -- 网络或服务端中断 --> N[EventBus Disconnected 事件<br/>接收断开原因并停止写操作]
|
||||
L -- 自己被踢出 --> O[EventBus Kicked 事件<br/>接收频道踢或服务器踢原因]
|
||||
M --> P[清理运行资源<br/>停止语音、取消请求并清空会话状态]
|
||||
N --> P
|
||||
O --> P
|
||||
P --> Q[生命周期结束<br/>不再承担当前会话请求]
|
||||
```
|
||||
|
||||
### 生命周期约束
|
||||
|
||||
1. `TSBridge.connect()` 发起连接,连接就绪通过 EventBus `Connected` 事件确认。
|
||||
2. EventBus 事件监听应在 `connect()` 之前开始收集,避免连接早期事件无人接收。
|
||||
3. `connect()` 成功只表示连接流程已启动;发送普通命令前必须等待 `Connected` 事件。
|
||||
4. `Connected` 是 SDK 推送的已连接事实,可作为首次同步入口。
|
||||
5. `TSBridge.disconnect()` 用于主动优雅退出;`Disconnected` 事件用于观察最终断开结果或异常断开。
|
||||
6. `Kicked` 事件来源于 `notifyclientleftview` 的特定原因,必须与普通成员离开区分。
|
||||
7. 断开后应停止语音、拒绝新命令,并清理只属于当前会话的状态。
|
||||
|
||||
### 1.2 生命周期阶段与允许操作
|
||||
|
||||
| 阶段 | 允许操作 | 禁止或不建议操作 | 中文说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| 构造前 | 准备配置 | 调用任何 TSBridge 方法 | 连接尚未建立 |
|
||||
| 已配置 | 注册 EventBus 事件收集、读取本地配置 | 发送服务器命令 | 尚未建立网络会话 |
|
||||
| 连接中 | 等待 `Connected` 事件、响应取消 | `getClientsJSON()`、`moveToChannel()` 等业务命令 | 握手尚未确认完成 |
|
||||
| 已连接 | 同步频道和成员、发送聊天、发送语音 | 重复调用 `connect()` | SDK 已具备业务通信条件 |
|
||||
| 断开中 | 停止上层写操作、等待清理 | 发起新业务命令 | 会话正在关闭 |
|
||||
| 已断开 | 释放资源或重新连接 | 复用失效会话发送命令 | 旧会话不再可信 |
|
||||
|
||||
---
|
||||
|
||||
## 二、初始化配置
|
||||
|
||||
### 2.1 初始化配置结构
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[应用启动配置<br/>收集身份、地址、昵称和可选参数] --> B[Identity<br/>提供 TeamSpeak 加密身份]
|
||||
A --> C[服务器地址 addr<br/>提供域名、IP 或 TSDNS 地址]
|
||||
A --> D[昵称 nickname<br/>提供当前连接显示名称]
|
||||
A --> E[连接选项<br/>提供可选运行能力]
|
||||
|
||||
E --> E3[serverPassword<br/>设置服务器连接密码]
|
||||
E --> E4[defaultChannel<br/>设置连接后默认进入的频道名称]
|
||||
E --> E5[defaultChannelPassword<br/>设置默认频道密码]
|
||||
|
||||
B --> F[TSBridge.connect<br/>组装参数并通过 gomobile 发起连接]
|
||||
C --> F
|
||||
D --> F
|
||||
E3 --> F
|
||||
E4 --> F
|
||||
E5 --> F
|
||||
|
||||
F --> G[注册 EventCallback<br/>JNI 回调转 EventBus 事件]
|
||||
G --> H[Go SDK Connect<br/>UDP 会话与协议握手]
|
||||
```
|
||||
|
||||
### 2.2 推荐初始化顺序
|
||||
|
||||
```kotlin
|
||||
// TSBridge.connect() 内部注册 JNI EventCallback,
|
||||
// 将所有 Go 回调转为 EventBus.emit() 事件。
|
||||
// ViewModel 通过 EventBus.events.collect() 接收事件并更新状态。
|
||||
|
||||
// 示例:ServerViewModel 中收集连接事件
|
||||
viewModelScope.launch {
|
||||
EventBus.events.collect { event ->
|
||||
when (event) {
|
||||
is TSEvent.Connected -> {
|
||||
// 开始首次同步
|
||||
performInitialSync()
|
||||
}
|
||||
is TSEvent.Disconnected -> {
|
||||
// 清理会话
|
||||
handleDisconnect(event.message)
|
||||
}
|
||||
else -> { /* 其他事件由对应 ViewModel 处理 */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// connect 发起网络连接,Connected 事件确认握手真正完成。
|
||||
val error = TSBridge.connect(host, nickname, password, defaultChannel, defaultChannelPassword, callbacks)
|
||||
// error 为空字符串表示连接流程已启动,等待 EventBus Connected 事件
|
||||
```
|
||||
|
||||
### 2.3 配置之间的依赖
|
||||
|
||||
| 配置 | 前置条件 | 影响阶段 | 依赖说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Identity` | 必须可用 | 连接、握手 | 缺少身份无法正确创建客户端 |
|
||||
| `addr` | 必须非空且可解析 | 地址解析、连接 | 由 SDK 内部解析器解析 |
|
||||
| `nickname` | 必须满足服务器命名规则 | 握手、上线 | 服务器可能拒绝无效或冲突昵称 |
|
||||
| `serverPassword` | 服务器启用密码时需要 | 握手 | 密码错误会导致连接失败 |
|
||||
| `defaultChannel` | 目标频道名称存在 | 连接完成阶段 | SDK 尝试在连接后自动进入该频道 |
|
||||
| `defaultChannelPassword` | 已设置默认频道且频道有密码 | 进入默认频道 | 单独设置密码而无默认频道没有明确目标 |
|
||||
|
||||
---
|
||||
|
||||
## 三、状态树
|
||||
|
||||
### Client 总状态树(连接相关部分)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
ROOT[Client 生命周期状态树<br/>描述一个连接从创建到结束的完整状态]
|
||||
|
||||
ROOT --> U[未配置 Uninitialized<br/>仅准备 Identity 和连接参数]
|
||||
ROOT --> C[已配置 Configured<br/>EventBus 已注册但尚未连接]
|
||||
ROOT --> N[连接过程 Connecting<br/>正在解析地址并执行握手]
|
||||
ROOT --> R[已连接 Connected<br/>握手完成且可以执行业务命令]
|
||||
|
||||
U --> U1[配置 Identity<br/>准备加密身份]
|
||||
U --> U2[配置地址与昵称<br/>准备基础连接参数]
|
||||
U --> U3[配置连接选项<br/>准备密码和默认频道]
|
||||
|
||||
C --> C1[注册 EventBus 事件收集<br/>绑定服务端推送处理器]
|
||||
C --> C2[等待 connect 调用<br/>尚不能发送业务命令]
|
||||
|
||||
N --> N1[Resolving<br/>SDK 内部解析地址]
|
||||
N --> N2[Handshaking<br/>通过 UDP 建立协议会话]
|
||||
N --> N3[WaitingReady<br/>等待 Connected 事件]
|
||||
N --> N4[ConnectFailed<br/>解析、密码、网络或握手失败]
|
||||
|
||||
R --> R1[Syncing<br/>通过列表命令建立频道和成员基线]
|
||||
R --> R2[Ready<br/>允许聊天、移动、查询和语音]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、时序:构造、连接与首次同步
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as 上层应用<br/>发起连接并展示状态
|
||||
participant VM as ViewModel<br/>收集 EventBus 事件
|
||||
participant BRIDGE as TSBridge<br/>管理连接生命周期
|
||||
participant SDK as Go SDK (gomobile)<br/>管理协议通信
|
||||
participant TS as TeamSpeak 服务器<br/>执行握手和列表请求
|
||||
participant STORE as 业务状态仓库<br/>保存频道和成员基线
|
||||
|
||||
UI->>BRIDGE: connect(host, nickname, password, ...)
|
||||
BRIDGE->>SDK: gomobile 调用 Go Connect
|
||||
SDK->>TS: 连接握手请求<br/>协商身份、密码和会话
|
||||
TS-->>SDK: 握手响应
|
||||
SDK-->>BRIDGE: connect 返回 ""
|
||||
|
||||
SDK->>BRIDGE: OnConnected 回调<br/>gomobile 转换为 JNI 回调
|
||||
BRIDGE->>BRIDGE: EventBus.emit(Connected)
|
||||
BRIDGE->>VM: EventBus SharedFlow<br/>分发 Connected 事件
|
||||
VM->>VM: 更新连接状态
|
||||
|
||||
par 请求频道基线
|
||||
VM->>BRIDGE: TSBridge.getChannelsJSON()
|
||||
BRIDGE->>SDK: gomobile 调用 GetChannelsJSON
|
||||
SDK->>TS: channellist
|
||||
TS-->>SDK: JSON 字符串
|
||||
SDK-->>BRIDGE: 频道 JSON
|
||||
BRIDGE-->>VM: JSON 字符串
|
||||
VM->>STORE: 解析并保存频道基线
|
||||
and 请求成员基线
|
||||
VM->>BRIDGE: TSBridge.getClientsJSON()
|
||||
BRIDGE->>SDK: gomobile 调用 GetClientsJSON
|
||||
SDK->>TS: clientlist
|
||||
TS-->>SDK: JSON 字符串
|
||||
SDK-->>BRIDGE: 成员 JSON
|
||||
BRIDGE-->>VM: JSON 字符串
|
||||
VM->>STORE: 解析并保存成员基线
|
||||
and 读取自身 ID
|
||||
VM->>BRIDGE: TSBridge.getClientID()
|
||||
BRIDGE-->>VM: selfClientID
|
||||
VM->>STORE: 保存自身 ID
|
||||
end
|
||||
|
||||
VM->>STORE: 原子提交频道、成员和自身 ID
|
||||
STORE-->>UI: 同步完成<br/>连接状态进入业务就绪
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、事件依赖
|
||||
|
||||
### 连接相关前置依赖矩阵
|
||||
|
||||
| 操作或事件 | 必须依赖 | 建议依赖 | 依赖失败时的处理 |
|
||||
| --- | --- | --- | --- |
|
||||
| `TSBridge.connect` | 地址、昵称 | 已注册 EventBus 事件收集 | 参数无效时不进入连接流程 |
|
||||
| `connect` 成功 | 已注册 EventBus 事件收集 | — | 返回错误信息并停止等待连接 |
|
||||
| `Connected` 事件 | 已调用 `connect` | — | 超时后终止本次初始化 |
|
||||
| 首次同步 | `Connected` 事件 | 同时读取频道、成员和自身 ID | 任一核心请求失败则不标记业务就绪 |
|
||||
|
||||
### 事件依赖总图(连接阶段)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
CONFIG[初始化配置完成<br/>地址、昵称已准备] --> REG[注册 EventBus 事件收集<br/>确保早期服务端推送可被处理]
|
||||
REG --> CONNECT[TSBridge.connect<br/>启动地址解析、UDP 会话和握手]
|
||||
CONNECT --> CONNECTED[EventBus Connected 事件<br/>SDK 推送连接成功事实]
|
||||
|
||||
CONNECTED --> CID[TSBridge.getClientID<br/>读取当前用户客户端 ID]
|
||||
CONNECTED --> CHANNELS[TSBridge.getChannelsJSON<br/>建立频道基线]
|
||||
CONNECTED --> CLIENTS[TSBridge.getClientsJSON<br/>建立在线成员基线]
|
||||
|
||||
CID --> SELFREADY[当前用户身份就绪<br/>能够识别自己的移动和离开事件]
|
||||
CHANNELS --> DATAREADY[服务器实体就绪<br/>频道和成员引用关系可被验证]
|
||||
CLIENTS --> DATAREADY
|
||||
SELFREADY --> READY[业务就绪<br/>允许移动、聊天和语音]
|
||||
DATAREADY --> READY
|
||||
```
|
||||
|
||||
### 权威性划分
|
||||
|
||||
| 数据 | 推荐权威来源 | 原因 |
|
||||
| --- | --- | --- |
|
||||
| 是否完成连接 | EventBus `Connected` 事件 | `connect()` 只负责启动连接 |
|
||||
| 自身客户端 ID | `TSBridge.getClientID()` | SDK 本地缓存服务器分配的 ID |
|
||||
| 初始频道列表 | `TSBridge.getChannelsJSON()` 响应 | SDK 未列出频道创建、更新、删除事件 |
|
||||
| 初始在线成员 | `TSBridge.getClientsJSON()` 响应 | 建立完整在线成员基线 |
|
||||
Reference in New Issue
Block a user