文件传输与断点续传
文件传输结合了两层协议:P2P 控制消息先约定文件与操作,再由专用的 WebRTC 数据通道传输二进制块。接收方请求缺失的分块,存储层决定哪些数据已经提交,以及完整文件何时可以发布为可用内容。
先交换元数据,再传输字节
正常流程如下:
- 提议发送文件元数据;按内容身份传输时,同时提供内容指纹。
- 接收方接受提议,或复用本地已经验证过的副本。
- 将传输绑定到实际设备会话,打开对应的数据通道。
- 请求缺失分块、接收块数据,再将重建的数据提交到存储。
- 验证完整内容,通过存储服务发布文件。
传输通道使用 transfer 协议标识。通道标签包含文件和通道序号,例如 <fileId>-0。元数据来自控制消息;只有一个通道标签,并不能获得向任意文件写入的权限。
传输注册表把通道绑定到预期文件、传输方向和所属设备会话,并拒绝未知或重复通道。即使重连后的设备 ID 看起来相同,旧会话也不能向新会话的传输注入数据。
请求缺失分块
接收方在传输通道上发送 JSON 控制帧。单个数字请求一个逻辑分块,一对数字请求包含首尾的分块范围:
{
"type": "request-content",
"ranges": [0, [2, 5], 9]
}这表示请求第 0、2、3、4、5、9 块。分块序号对应原始文件的位置,不是压缩流的位置,也不是字节偏移;分块大小由双方约定的文件元数据提供。
另有两种控制帧用于协调暂停和完成:
{
"type": "pause"
}{
"type": "complete"
}线上 complete 消息参与传输协调,但界面不能仅据此认定待写数据、最终内容校验和文件发布已经全部完成。这些步骤属于接收任务与存储的生命周期。
二进制块格式
每个逻辑分块先编码为 raw DEFLATE 流,再切成适合数据通道传输的块。每个二进制块以七字节报头开头:
| 字节偏移 | 字段 | 编码 |
|---|---|---|
| 0–3 | 逻辑分块序号 | 无符号 32 位整数,大端序 |
| 4–5 | 当前压缩分块内的块序号 | 无符号 16 位整数,大端序 |
| 6 | 最后一块标记 | 只能为 0 或 1 |
| 7 起 | 块数据 | 压缩分块的一部分 |
接收方按逻辑分块序号汇集各块,重建压缩分块并解压,之后才写入原始字节。即使压缩级别为零,协议仍使用 raw DEFLATE 格式,不会切换为直接发送无封装的原始文件字节。短于报头或最后一块标记无效的报文会被拒绝。
逻辑分块大小与传输块大小服务于不同目的:前者定义存储和续传单位,后者适配传输限制。发送方通过背压等待通道可用容量,避免把整个文件一次性塞进发送队列。因此,网络已传输进度与存储已提交进度可能不同。
内容身份与校验
当前内容指纹采用版本 1 和 blake3-256 算法,包含文件大小及由 64 个小写十六进制字符组成的摘要。内部内容键的格式为:
v1:blake3-256:<size>:<digest>内容身份独立于文件名、消息 ID、传输任务和分块边界。相同字节改名后,内容指纹不变;同名文件的字节改变后,内容指纹也会改变。因此,不同消息和文件库条目可以引用同一份已验证内容。
对端提供的指纹只是待比较的预期值,不能证明接收方已经检查过本地字节。接收文件需要通过本地内容校验,才能成为完整内容;复用已有副本也必须遵循存储服务的验证规则。
暂停、续传与任务归属
续传范围根据已经提交的分块计算。刚收到、仍在缓冲区中或仅预分配出来的字节,都不算持久化进度。重新打开目录中的未完成文件时,还需要将检查点摘要与实际字节比对,才能复用相应分块。
暂停会停止当前传输,并保留已经提交的数据。来源可用、文件元数据匹配时,后续任务可以只请求缺失分块。取消任务、释放消息引用与删除存储内容有不同效果,不能当成同一种清理操作。
一个文件可以提供给多个设备,但每次传输都有自己的会话和任务归属。旧任务的完成或失败不能覆盖替代任务的状态。房间附件是保存在本地历史中的文件提议,不是存放在信令服务器上的副本:收到元数据不代表已下载字节,获取内容仍需要可用来源。
实现入口
以下路径相对于 apps/web/src/libs/:
| 路径 | 职责 |
|---|---|
domain/transfer/protocol.ts、domain/transfer/packet.ts | 传输控制帧与二进制报文布局 |
domain/transfer/file-sender.ts、domain/transfer/file-receiver.ts | 分块发送、重建与传输生命周期 |
domain/protocol/file-fingerprint.ts | 内容指纹契约 |
application/transfer/transfer-registry.ts | 文件、会话与通道归属 |
application/transfer/file-transfer-service.ts | 传输任务编排 |
infrastructure/vfs/chunk-cache.ts | 已提交数据、校验与完成 |