# 文件传输

> 用户流程：选择文件 → 上传/下载 → 等待传输完成
> 对应程序流程：FileTransferInit → DialFileTransfer → UploadFileData / DownloadFileData
> 注：文件传输 API 暂未在 `TsClient` 中封装，需通过 `TSBridge` 直接调用 gomobile 对象

---

## 一、状态树

### 文件状态

```mermaid
flowchart TD
    FILE[文件状态<br/>维护上传和下载过程]

    FILE --> F0[空闲 Idle<br/>没有文件传输任务]
    FILE --> F1[初始化 Initializing<br/>请求 FileTransferInitUpload 或 Download]
    FILE --> F2[连接中 Dialing<br/>DialFileTransfer 建立 TCP 连接]
    FILE --> F3[传输中 Transferring<br/>UploadFileData 或 DownloadFileData 搬运数据]
    FILE --> F4[完成 Completed<br/>文件数据传输结束]
    FILE --> F5[失败 Failed<br/>初始化、连接或传输发生错误]
```

---

## 二、时序：文件上传与下载

```mermaid
sequenceDiagram
    participant UI as 文件操作 UI<br/>选择上传或下载任务
    participant SDK as teamspeak-go SDK<br/>初始化文件传输并提供辅助函数
    participant TS as TeamSpeak 服务器<br/>分配文件传输连接信息
    participant TCP as 文件 TCP 连接<br/>承载实际文件字节流
    participant IO as 本地 Reader/Writer<br/>提供上传源或接收下载结果

    alt 上传文件
        UI->>SDK: FileTransferInitUpload(channelID, path, password, size, overwrite)<br/>中文注释：请求初始化频道文件上传
        SDK->>TS: ftinitupload<br/>中文注释：提交目标路径、大小和覆盖选项
        TS-->>SDK: FileUploadInfo<br/>中文注释：返回 host、port 和传输 key
        SDK-->>UI: uploadInfo<br/>中文注释：初始化成功后才能建立数据连接
        UI->>SDK: DialFileTransfer(host, port, key)<br/>中文注释：建立独立 TCP 文件连接
        SDK->>TCP: TCP connect<br/>中文注释：连接服务器文件传输端口
        UI->>SDK: UploadFileData(host, info, reader)<br/>中文注释：从本地 Reader 读取上传内容
        IO-->>SDK: 文件字节流<br/>中文注释：持续提供待上传数据
        SDK->>TCP: 上传字节流<br/>中文注释：通过 TCP 发送文件内容
        TCP->>TS: 完成上传<br/>中文注释：服务器保存频道文件
    else 下载文件
        UI->>SDK: FileTransferInitDownload(channelID, path, password)<br/>中文注释：请求初始化频道文件下载
        SDK->>TS: ftinitdownload<br/>中文注释：提交目标频道和文件路径
        TS-->>SDK: FileDownloadInfo<br/>中文注释：返回 host、port 和传输 key
        SDK-->>UI: downloadInfo<br/>中文注释：初始化成功后才能建立数据连接
        UI->>SDK: DialFileTransfer(host, port, key)<br/>中文注释：建立独立 TCP 文件连接
        SDK->>TCP: TCP connect<br/>中文注释：连接服务器文件传输端口
        UI->>SDK: DownloadFileData(host, info, writer)<br/>中文注释：指定本地 Writer 接收文件
        TS->>TCP: 下载字节流<br/>中文注释：服务器持续发送文件内容
        TCP->>SDK: 文件字节流<br/>中文注释：SDK 从 tcp 读取下载数据
        SDK->>IO: 写入本地 Writer<br/>中文注释：保存或消费下载内容
    end
```

---

## 三、事件依赖

### 文件传输前置依赖矩阵

| 操作或事件 | 必须依赖 | 建议依赖 | 依赖失败时的处理 |
| --- | --- | --- | --- |
| `DialFileTransfer` | 上传或下载初始化结果 | 初始化信息尚未过期 | 不得跳过初始化直接拨号 |
| `UploadFileData` | 上传信息、Reader、有效 TCP 条件 | 文件大小与声明一致 | 中止任务并展示传输错误 |
| `DownloadFileData` | 下载信息、Writer、有效 TCP 条件 | 本地空间和写权限可用 | 中止任务并清理不完整结果 |

### 事件依赖图（文件传输）

```mermaid
flowchart TD
    READY --> FTINIT[文件传输初始化<br/>请求上传或下载连接信息]
    FTINIT --> FTDIAL[DialFileTransfer<br/>依赖 host、port 和 key 建立 TCP]
    FTDIAL --> FTDATA[上传或下载数据<br/>依赖已初始化的文件连接]
```

### 命令响应与事件事实的区别

```mermaid
flowchart LR
    INTENT[用户意图<br/>上传或下载文件] --> COMMAND[客户端请求<br/>FileTransferInit]
    COMMAND --> RESPONSE{命令响应<br/>判断服务器是否接受请求}
    RESPONSE -- 失败 --> FAILED[请求失败<br/>展示错误原因]
    RESPONSE -- 成功 --> INFO[获得传输参数<br/>host、port、key]
    INFO --> DIAL[建立 TCP 连接<br/>DialFileTransfer]
    DIAL --> TRANSFER[数据传输<br/>Upload/DownloadFileData]
```

**关键区分：**

- `FileTransferInitUpload/Download` 成功：只获得传输参数；文件内容仍依赖后续 TCP 连接和数据传输。
- 文件传输严格遵守"初始化 → TCP 连接 → 数据传输"三个阶段，不能跳过。

### 权威性划分

| 数据 | 推荐权威来源 | 原因 |
| --- | --- | --- |
| 文件传输进度 | SDK 内部文件状态事件 | `notifystartupload`、`notifystartdownload`、`notifystatusfiletransfer` |

### 统一实现原则（文件传输相关）

- **文件传输严格遵守"初始化 → TCP 连接 → 数据传输"。** 三个阶段不能跳过。
