传输恢复这个词容易被误解
“传输恢复”听起来像是一个开关:断了就自动续传,重启了也接着传。在 ConchTerm 的当前阶段,这件事要分两层说清楚,因为它们能承诺的程度差很多。
已经完成的部分
运行期的传输控制和恢复是闭环的:
- 队列与状态机:每个会话默认 2 个并发、全局 4 个并发,支持 queued / running / paused / failed / canceled / completed 等明确状态转换,且转换受
canTransition强制约束。 - 暂停、继续、取消、重试:可以在传输抽屉里对单个任务或批次做这些操作。
- 运行期 offset 续传:上传和下载都先写
.part.<taskId>,完成后原子 rename 到最终路径。只要应用还在运行、会话和授权还在、partial 文件还在、源文件 size/mtime 没变,断线后可以按 offset 继续。 - 冲突预检和批次策略:传输前预检目标冲突,支持
overwrite | skip | rename批次策略。 - 崩溃安全的任务日志:
TransferJournal用原子 JSON 文件记录任务,恢复中心能读取并展示可恢复任务。 - 恢复中心(只读):把活动、可恢复、被阻塞和历史的任务以 display-safe 的 DTO 展示出来。
这些都是现在就能用的能力,不是路线图。
暂时不承诺的部分
诚实说明边界,避免误解:
- 应用重启后的一键 resume 还没接通。 重启后,运行期凭据库和路径授权会被清空,持久化的传输任务缺少会话上下文,主进程也没有接收这些持久化任务的入口。因此恢复中心目前以“pending”标签诚实降级——它告诉你哪些任务可恢复,但需要你手动重新发起,而不是点一下就续传。
- upload 方向的 partial 文件清理还没实现。 如果你在 discard 一个上传任务时选择删除 partial,目前只能清理下载方向的本地 partial;上传 partial 在远端,需要重新建立 SFTP 连接才能 best-effort 删除,这部分随 resume 管道一起做。
- 不计算 checksum。 运行期 offset resume 依赖源文件 size/mtime 校验,不做内容级校验或去重。
这两项是技术债务登记里明确记录的暂缓项,对应 TD-017(resume 生产入口)和 TD-018(upload partial 清理)。它们不是缺陷被隐藏,而是阶段边界。
为什么不直接承诺“重启后自动恢复”
把“重启后自动 resume”做对,需要几件事同时成立:
- 凭据能安全地跨重启恢复(macOS Keychain 持久化已就位)。
- 路径授权能跨重启重建。
- 主进程有一个接收持久化任务、重新绑定会话的入口。
- 源文件变化的校验和 UI 降级路径要清晰。
在把这些都做完、并且经过集成和 E2E 验证之前,声称“重启后自动续传”会误导用户。我们选择先让恢复中心诚实展示状态,等管道接通后再开放一键 resume。
用户现在该怎么做
如果你在传输中断后需要继续:
- 应用还在运行:直接在传输抽屉里重试,能走运行期 offset 续传的就续传。
- 应用已经重启:去恢复中心查看可恢复任务,手动重新发起受影响的传输。
- discard 上传任务后想清理远端 partial:目前需要你手动处理远端
.part文件,因为自动清理尚未实现。
这些操作方式写在这里,是希望你在 dogfood 阶段就能正确预期行为,而不是在出错时才发现边界。