# 断开连接

> 用户流程：主动断开 / 网络异常断开 / 被踢出 → 清理会话 → 返回主页
> 对应程序流程：TsClient.disconnect() 或 onDisconnected(error) 或 onKicked(reason) → 停止写操作 → 清理会话状态

---

## 一、状态树

### Client 总状态树（断开相关部分）

```mermaid
flowchart TD
    ROOT[Client 生命周期状态树<br/>断开相关部分]

    ROOT --> D[断开过程 Disconnecting<br/>正在主动或被动结束会话]
    ROOT --> X[已结束 Terminated<br/>当前会话资源已清理]

    D --> D1[GracefulDisconnect<br/>用户调用 TsClient.disconnect 优雅退出]
    D --> D2[UnexpectedDisconnect<br/>网络或服务端导致 onDisconnected]
    D --> D3[Kicked<br/>onKicked 表示自己被踢]

    X --> X1[清理命令请求<br/>取消未完成的业务操作]
    X --> X2[清理语音与传输<br/>停止语音和文件连接]
    X --> X3[清理会话状态<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/>保存当前连接的临时事实

    alt 用户主动断开
        UI->>VM: DisconnectRequested
        VM->>VM: 状态改为 disconnecting
        VM->>BRIDGE: TSBridge.disconnect()
        BRIDGE->>SDK: gomobile Disconnect
        SDK->>TS: shutdown reason
        TS-->>SDK: 连接关闭
        SDK-->>BRIDGE: OnDisconnected 回调
        BRIDGE->>BRIDGE: EventBus.emit(Disconnected)
        BRIDGE->>VM: EventBus 分发 Disconnected 事件
    else 网络或服务器异常
        TS--xSDK: UDP 会话中断
        SDK-->>BRIDGE: OnDisconnected 回调
        BRIDGE->>BRIDGE: EventBus.emit(Disconnected)
        BRIDGE->>VM: EventBus 分发 Disconnected 事件
    else 自己被踢
        TS-->>SDK: notifyclientleftview reasonid=4/5
        SDK-->>BRIDGE: OnKicked 回调
        BRIDGE->>BRIDGE: EventBus.emit(Kicked)
        BRIDGE->>VM: EventBus 分发 Kicked 事件
    end

    VM->>VM: 停止语音与文件传输
    VM->>STORE: 清理频道、成员和 Pending
    STORE-->>UI: 返回已断开或失败页面
```

---

## 三、事件依赖

### 断开相关前置依赖矩阵

| 操作或事件 | 必须依赖 | 建议依赖 | 依赖失败时的处理 |
| --- | --- | --- | --- |
| `Disconnected` 事件 | 已注册 EventBus 事件收集 | 保存断开原因 | 停止全部依赖连接的操作 |
| `Kicked` 事件 | 已注册 EventBus 事件收集 | 区分 reasonid 4 和 5 | 清理会话且不伪装为普通成员离开 |

### 事件依赖图（断开阶段）

```mermaid
flowchart TD
    DISCONNECTED[EventBus Disconnected 事件<br/>接收连接终止事件] --> STOP[停止依赖操作<br/>禁止命令、语音和新文件传输]
    KICKED[EventBus Kicked 事件<br/>接收自己被踢事件] --> STOP
    STOP --> CLEAN[清理会话状态<br/>移除当前连接的实体与 Pending]
```

### 服务端通知映射

| 服务端通知 | TSBridge 回调 → EventBus 事件 | 上层状态依赖 | 中文说明 |
| --- | --- | --- | --- |
| `notifyclientleftview`，`reasonid=4/5` 且为自己 | `OnKicked` → `Kicked` | 当前会话、语音、导航 | SDK 将自己被踢转换为独立事件 |

### 生命周期约束（断开相关）

- `TSBridge.disconnect()` 用于主动优雅退出；`Disconnected` 事件用于观察最终断开结果或异常断开。
- `Kicked` 事件来源于 `notifyclientleftview` 的特定原因，必须与普通成员离开区分。
- 断开后应停止语音、拒绝新命令，并清理只属于当前会话的状态。

### 权威性划分

| 数据 | 推荐权威来源 | 原因 |
| --- | --- | --- |
| 被踢状态 | EventBus `Kicked` 事件 | SDK 已从离开事件原因中识别自己被踢 |

### 统一实现原则（断开相关）

- **断开时统一清理当前会话资源。** 防止旧成员、频道和 Pending 污染下一次连接。
