BT 做种功能完整实现 — Issue 提案
基准:upstream/main (zerx-lab/FluxDown),当前完全没有 BT 做种能力。
BT 下载完成后直接断开所有 peer 连接,不参与上传分享。
关联上游 issue:#42 希望添加上传限制 — 用户反馈"没有限制上传速度,家用宽带容易跑满影响其他设备",做种功能的上传限速直接覆盖此需求。
一、为什么需要做种功能
1.1 当前行为
BT 下载完成后的流程:
下载完成 → pause torrent(断开所有 peer) → 清理 staging 目录 → 任务标记为"已完成"
这是一个纯下载器的行为模型。对 BT 协议而言,pause 意味着:
- 停止向 tracker/DHT announce
- 关闭所有 peer 连接
- 不再上传任何数据
- 不响应其他 peer 的 piece 请求
1.2 对标产品
| 客户端 |
完成后的行为 |
| qBittorrent |
默认继续做种,支持分享率/时间/不活跃三重限制 |
| Transmission |
持续做种,支持全局和单种分享率控制 |
| aria2 |
--seed-ratio / --seed-time 参数控制 |
| FluxDown(当前) |
不做种 |
1.3 用户价值
- BT 生态贡献:下载者同时也是上传者,维持 torrent 健康度
- 私有 tracker 准入:许多私有 tracker 要求最低分享率,不做种会被 ban
- 下载加速:做种期间保持 DHT/tracker 连接,后续添加同类种子时 peer 发现更快
- 用户控制感:可设置分享率/时间限制,自动管理做种生命周期
二、完整功能需求
2.1 做种状态模型
参考 qBittorrent 的成熟状态模型,引入以下任务状态:
下载中 → 校验中(新增) → 做种中(新增) → 已完成(含停止做种)
↘ 做种暂停(新增)
| 状态 |
含义 |
UI 表现 |
| 下载中 |
正在下载数据 |
进度条 + 下载速度 |
| 校验中 (新增) |
BT 完成后的 piece hash 校验 |
进度条 100% + "校验中"标签 |
| 做种中 (新增) |
正在上传给 peers |
进度条 100% + 上传速度 + 做种时长 |
| 做种暂停 (新增) |
用户或系统暂停了做种 |
可恢复 |
| 已完成 |
做种已停止,任务归档 |
绿色完成标记 |
| 已暂停 |
用户手动暂停下载 |
— |
| 排队中 |
等待空闲下载槽位 |
— |
| 错误 |
下载/校验失败 |
— |
| 文件丢失 |
已完成任务的文件被外部删除 |
— |
2.2 做种限制条件
默认规则:总分享率 ≥ 1.0 或 做种时间 ≥ 72 小时,满足任一即停止做种。用户可在设置中自由开启/关闭每个条件,条件之间可选"且/或"逻辑。
| 条件 |
默认值 |
说明 |
| 总分享率达到 |
1.0(关闭) |
uploaded_bytes / downloaded_bytes,含下载阶段的上传 |
| 做种后分享率达到 |
—(关闭) |
(uploaded_bytes - uploaded_at_completion) / downloaded_bytes |
| 达到总做种时间 |
72 小时(开启) |
首次进入做种开始计时 |
| 达到不活跃做种时间 |
30 分钟(关闭) |
上传速度为 0 的持续时长 |
默认逻辑:总做种时间 ≥ 72h OR 总分享率 ≥ 1.0(用户可改为 AND)。
2.3 达到限制后的动作
默认动作:停止做种,任务转入已完成状态。
可选动作(未来扩展):
2.4 全局速度限制联动
全局下载速度限制同步应用于 BT 上传。 当前的独立上传限速字段 bt_upload_speed_limit_kbps 移除,BT 上传速率跟随全局 speed_limit_bytes。这样做的好处:
- 用户不需要在两个地方设置速度限制
- 避免了"下载限速但上传不限速"的半限速状态
- 降低设置页复杂度
2.5 任务列表速度显示
BT 类型的任务条目,速度区域同时显示上传和下载速度:
- 下载中:显示 ↓ 下载速度;如有上传则同时显示 ↑ 上传速度
- 做种中:显示 ↑ 上传速度
- 无对应速度时自动隐藏该行,不显示 "—"
三、需要改动的模块
3.1 Rust 引擎层
3.1.1 新增 SeedingManager — native/engine/src/bt_seeding.rs
独立的做种生命周期管理器,不嵌入 SharedBtSession:
- 注册/注销 seeder(任务 ID → torrent handle 映射)
- 评估做种限制(分享率、时间、不活跃时间)
- 记录每次做种的起始上传量(用于"做种后分享率"计算)
- 支持"达到限制后动作"的策略模式
- 维持做种会话记录(用于重启恢复)
3.1.2 改造完成路径 — native/engine/src/bt_downloader.rs
BT 下载完成后的行为变更:
Before: finished → verify pieces → pause torrent → clean staging → done
After: finished → verify pieces → clean staging → register seeder → keep alive
校验阶段:
- 校验期间任务状态设为"校验中"(新增状态码),UI 展示
校验中 标签
- 校验进度可量化:
hashed_pieces / total_pieces
- 校验失败(phantom pieces)→ 自动重试下载受损 pieces
做种阶段:
- 校验通过后,torrent handle 保持活跃,注册到 SeedingManager
- staging 目录在进入做种前清理(handle 指向最终文件路径)
- 任务状态从"校验中" → "做种中"
3.1.3 扩展下载管理器 — native/engine/src/download_manager.rs
- 定时器(30s)评估做种限制,触发停止/暂停动作
- 全局速度限制联动 BT 上传:
set_speed_limit() 同时调用 set_download_bps 和 set_upload_bps
- 暂停做种:
pause_seeding(task_id) → bt.pause_task() + seeding_status = paused
- 恢复做种:
resume_seeding(task_id) → bt.unpause_task() + register_seeder()
- 停止做种:
stop_seeding(task_id) → bt.pause_task() + 任务转入已完成
- 应用重启时恢复做种:扫描
seeding_status = active 的任务,重新 add_torrent 并注册 seeder
- 会话保护:有活跃 seeder 时不释放 BT session
3.1.4 DB Schema 扩展 — native/engine/src/db.rs
tasks 表新增列:
| 列名 |
类型 |
默认值 |
说明 |
uploaded_bytes |
BIGINT |
0 |
累计已上传字节数 |
seeding_status |
INTEGER |
0 |
做种状态(0=none, 1=seeding, 2=ratio_reached, 3=time_reached, 4=inactive_reached, 5=user_stopped, 6=user_paused, 7=max_tasks, 8=task_deleted) |
seeding_message |
TEXT |
'' |
停止原因的文本说明 |
3.2 信号层 — native/hub/src/signals/mod.rs
TaskProgress 信号新增字段:
| 字段 |
类型 |
说明 |
uploaded_bytes |
i64 |
已上传字节数 |
upload_speed_bps |
i64 |
实时上传速率 |
seeding_status |
i32 |
做种状态码 |
seeding_message |
String |
做种状态说明 |
checking_progress |
f64 |
校验进度(0.0~1.0,仅校验中状态有效) |
ControlTask 新增 action:
5 = 停止做种
6 = 暂停做种
7 = 恢复做种
3.3 Flutter UI 层
3.3.1 任务列表 (task_list_item.dart)
- BT 任务的速度区域:同时显示 ↑ 上传速度和 ↓ 下载速度,无数据时自动隐藏
- 做种中状态显示绿色"做种中"标签及上传速度
- 校验中状态显示"校验中 n/m pieces"标签
- 做种暂停显示琥珀色标签
3.3.2 详情面板 (detail_panel.dart)
- 做种中:速度行切换为上传速度
- 新增做种信息区:已上传量、分享率、做种时长、做种限制进度
- 校验中:显示校验进度
- 做种控制按钮:停止做种 / 暂停做种
3.3.3 侧边栏 (sidebar.dart + download_controller.dart)
- 新增 "做种中" 状态 Tab,独立计数
- 做种中 Tab 仅统计
seeding_status == active 的任务
- "已完成" Tab 不再包含做种中的任务
3.3.4 设置页 (settings_page.dart)
BT 设置区重构做种限制 UI:
- 移除独立的 "BT 上传速度限制" 输入框(由全局速度限制覆盖)
- 改为条件开关模式:
☐ 总分享率达到 [1.0]
☐ 做种后分享率达到 [2.0]
☐ 达到总做种时间 [72] 小时
☐ 达到不活跃做种时间 [30] 分钟
条件逻辑:[且 / 或 ▼]
- 默认:仅"达到总做种时间 72h"开启,条件逻辑为"或"
- 每个条件可独立开启/关闭
- 新增 "达到限制后" 动作选择:停止做种 / 暂停做种 / 删除任务(默认停止做种)
3.3.5 下载任务模型 (download_task.dart)
- 新增
SeedingStatus 枚举
- 新增
uploadedBytes、uploadSpeedBps、seedingStatus、seedingMessage、seedingStartedAt、checkingProgress 字段
isSeeding、isChecking 计算属性
seedRatio 分享率计算
seedingDuration 做种时长
3.3.6 国际化 (translations.dart)
新增翻译 key(中/英):
- 侧边栏 Tab:做种中 / Seeding
- 状态标签:做种中、校验中、做种暂停
- 详情面板:已上传、分享率、做种时间、校验进度
- 设置页:做种限制标题、各类条件标签、条件逻辑选择
- 通知:做种停止通知文案
3.4 Server 模式 (无头服务器)
native/server/src/actor.rs 同步所有 engine 层变更:做种定时评估、配置热更新。
3.5 aria2 JSON-RPC API (native/api/)
tellStatus 响应新增字段:
uploadLength(aria2 标准)
uploadSpeed(aria2 标准)
seedRatio(自定义扩展)
seedingStatus(自定义扩展)
四、实现方案
4.1 整体架构
┌─────────────────────────────────────────────────────────┐
│ Flutter UI │
│ 任务列表(双速显示) 详情面板(做种指标) 设置(条件开关) │
│ 侧边栏(做种Tab) 通知(做种停止) │
├─────────────────────────────────────────────────────────┤
│ Rinf 信号层 (hub/signals) │
│ TaskProgress(扩展字段) ControlTask(新增action) │
├─────────────────────────────────────────────────────────┤
│ Engine 层 │
│ ┌───────────────┐ ┌────────────────────────────┐ │
│ │ SeedingManager│ │ DownloadManager │ │
│ │ · register │ │ · tick_seeding_eval (30s) │ │
│ │ · unregister │ │ · pause/stop/resume_seeding │ │
│ │ · eval_limits │ │ · 全局限速联动BT上传 │ │
│ │ · evict_lru │ │ · 重启恢复做种 │ │
│ └───────────────┘ └────────────────────────────┘ │
│ ┌────────────────────────────────────────────────┐ │
│ │ SharedBtSession │ │
│ │ · 保持 handle 活跃(做种期间不释放) │ │
│ │ · 校验完成 → 注册 seeder │ │
│ └────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ DB (SQLite / PostgreSQL) │
│ tasks: uploaded_bytes, seeding_status, seeding_message │
│ 新增: seeding_sessions (做种历史) │
└─────────────────────────────────────────────────────────┘
4.2 分阶段实施
第一阶段:核心能力(必须)
-
DB Schema + 数据模型
- 新增列和 DB 读写 API
- 引擎模型扩展(TaskInfo 等)
- 信号扩展
-
SeedingManager + 完成路径改造
- 从零实现 SeedingManager
- BT 下载完成后进入做种(不 pause)
- 校验阶段中间状态暴露
- 定时评估分享率/时间限制
- 达到限制自动停止做种
max_seeding_tasks 限制强制执行(FIFO 逐出)
- 做种暂停/恢复/停止控制
-
全局速度限制联动 BT 上传
set_speed_limit() 同时限制下载和上传
- 移除 BT 设置中独立的上传限速输入框
-
重启恢复做种
- 启动时扫描
seeding_status = active 的 completed 任务
- 重新 add_torrent(利用 fastresume 跳过重复下载)
- 注册 seeder
第二阶段:UI 与交互
-
任务列表双速显示 + 做种状态
- BT 条目同时显示 ↑↓ 速度
- 做种中/校验中/做种暂停状态标签
- 无速度自动隐藏对应行
-
详情面板做种指标
- 做种中切换为上传速度
- 已上传量、分享率、做种时长
- 限制进度条(分享率进度、时间进度)
-
侧边栏新增"做种中" Tab
- 独立计数和筛选
- "已完成" Tab 不再包含做种任务
-
设置页做种限制条件开关
- 条件开关 + 且/或逻辑
- 默认:总做种时间 ≥ 72h
- 达到限制后动作选择
第三阶段:完善与健壮性
-
aria2 API 暴露做种字段
-
做种停止桌面通知
-
做种会话历史记录
- 新增
seeding_sessions 表
- 每次做种的起止时间和上传量
-
集成测试
4.3 关键设计决策
| 决策 |
选择 |
理由 |
| 分享率默认模式 |
总分享率 |
与 qBittorrent 一致,用户直觉 |
| 默认限制条件 |
总做种时间 ≥ 72h OR 总分享率 ≥ 1.0 |
兼顾贡献和用户便利 |
| 条件逻辑 |
用户可选 且/或 |
灵活性 |
| 达到限制默认动作 |
停止做种 |
最符合"限制"语义 |
| 上传限速 |
合并到全局速度限制 |
减少概念重叠,简化设置 |
| 校验态 |
新增独立中间状态 |
解决"99%卡住"的用户困惑 |
| 不活跃做种限制 |
支持但不默认开启 |
对热门种子过早停止 |
| 重启恢复做种 |
尝试恢复,失败则重置状态 |
不因重启静默丢失做种 |
五、预期效果
5.1 用户可见变化
- BT 下载完成后自动做种,不再直接停止
- 任务列表 BT 条目同时显示上传和下载速度,直观了解双向流量
- 侧边栏新增"做种中" Tab,一键筛选正在上传的任务
- 详情面板展示做种指标:已上传、分享率、做种时长、限制进度
- 设置页做种条件可自由组合,且/或逻辑切换
- "校验中"状态显示,不再误以为"卡在 99%"
- 做种停止时收到桌面通知
- 通过 aria2 API 可查询做种状态(外部客户端兼容)
5.2 行为变化
| 场景 |
当前 |
实现后 |
| BT 下载完成 |
直接停止,断开所有 peer |
进入做种,保持上传 |
| 全局限速设置 |
只限下载 |
同时限制下载和上传 |
| 应用重启 |
— |
自动恢复做种(如果之前在做种) |
| 分享率达到限制 |
— |
自动停止做种并通知 |
| 做种时间达到限制 |
— |
自动停止做种并通知 |
| 手动停止做种 |
— |
停止上传,转入已完成 |
| 手动暂停做种 |
— |
暂停上传,可恢复 |
六、风险评估
6.1 技术风险
| 风险 |
概率 |
影响 |
缓解措施 |
| librqbit 不支持"已完成文件的 re-add 跳过下载" |
中 |
重启恢复做种需重新校验所有 pieces |
依赖 fastresume .bitv 文件;若无则走降级路径(重置 seeding_status) |
| 做种期间 BT session 被 invalidate(配置变更触发) |
中 |
活跃做种全部中断 |
invalidate_bt_session 前检查 has_seeders(),等待做种结束或强制通知用户 |
| 大量做种任务导致文件句柄耗尽 |
低 |
Windows 上可能触发 ERROR_SHARING_VIOLATION |
限制 max_seeding_tasks 默认值(如 10),复用 librqbit 的 defer_writes_up_to 减少常开句柄 |
| 做种上传占用带宽影响下载体验 |
中 |
用户下载速度变慢 |
全局限速联动,用户可降低全局限速;未来可按 QoS 分配 |
| 重启批量恢复做种导致启动慢 |
低 |
多任务同时 add_torrent 延迟 |
限制 concurrent_init_limit(已有 3),串行恢复做种 |
6.2 产品风险
| 风险 |
概率 |
影响 |
缓解措施 |
| 用户不理解"为什么下载完了任务还在" |
中 |
困惑,可能误报 bug |
默认做种时间 72h 后自动停止;UI 明确标注"做种中";首次做种可弹 tooltip 说明 |
| 私有 tracker 用户被多记下载量 |
低 |
分享率异常 |
使用 librqbit 的 uploaded_bytes 统计,不做额外计算 |
| 默认不开启分享率限制,可能永远不做种停止 |
低 |
磁盘空间浪费 |
默认开启 72h 时间限制 |
| 全局限速联动与用户现有设置冲突 |
中 |
已有 BT 上传限速设置的用户需重新配置 |
迁移现有 bt_upload_speed_limit_kbps 值到全局 speed_limit_bytes |
6.3 兼容性风险
| 风险 |
说明 |
缓解措施 |
| DB 升级兼容 |
新增列对旧库无影响(add_column_if_missing) |
现有机制已覆盖 |
| 信号向后兼容 |
TaskProgress 新增字段需要 Dart 侧同步更新 |
所有字段带 #[serde(default)],旧版 Dart 忽略未知字段 |
| aria2 API 兼容 |
新增字段对齐 aria2 规范 |
uploadLength/uploadSpeed 为标准 aria2 字段;seedRatio/seedingStatus 为自定义扩展 |
七、不做的事情(明确范围边界)
- 不做 Super Seeding(BEP-16):初始分发优化,小众场景
- 不做私有 tracker passkey 支持:需额外认证机制
- 不做 tracker scrape 协议:获取 swarm 统计,与做种核心流程无关
- 不做做种任务的优先级与带宽分配:复杂度高,先保持平等分配
- 不做 DHT announce 状态可视化:内部机制,用户无需感知
- 不做文件完整性定期校验:可手动重新校验,自动化收益有限
BT 做种功能完整实现 — Issue 提案
一、为什么需要做种功能
1.1 当前行为
BT 下载完成后的流程:
这是一个纯下载器的行为模型。对 BT 协议而言,
pause意味着:1.2 对标产品
--seed-ratio/--seed-time参数控制1.3 用户价值
二、完整功能需求
2.1 做种状态模型
参考 qBittorrent 的成熟状态模型,引入以下任务状态:
2.2 做种限制条件
默认规则:总分享率 ≥ 1.0 或 做种时间 ≥ 72 小时,满足任一即停止做种。用户可在设置中自由开启/关闭每个条件,条件之间可选"且/或"逻辑。
uploaded_bytes / downloaded_bytes,含下载阶段的上传(uploaded_bytes - uploaded_at_completion) / downloaded_bytes默认逻辑:
总做种时间 ≥ 72h OR 总分享率 ≥ 1.0(用户可改为 AND)。2.3 达到限制后的动作
默认动作:停止做种,任务转入已完成状态。
可选动作(未来扩展):
2.4 全局速度限制联动
全局下载速度限制同步应用于 BT 上传。 当前的独立上传限速字段
bt_upload_speed_limit_kbps移除,BT 上传速率跟随全局speed_limit_bytes。这样做的好处:2.5 任务列表速度显示
BT 类型的任务条目,速度区域同时显示上传和下载速度:
三、需要改动的模块
3.1 Rust 引擎层
3.1.1 新增
SeedingManager—native/engine/src/bt_seeding.rs独立的做种生命周期管理器,不嵌入
SharedBtSession:3.1.2 改造完成路径 —
native/engine/src/bt_downloader.rsBT 下载完成后的行为变更:
校验阶段:
校验中标签hashed_pieces / total_pieces做种阶段:
3.1.3 扩展下载管理器 —
native/engine/src/download_manager.rsset_speed_limit()同时调用set_download_bps和set_upload_bpspause_seeding(task_id)→bt.pause_task()+seeding_status = pausedresume_seeding(task_id)→bt.unpause_task()+register_seeder()stop_seeding(task_id)→bt.pause_task()+ 任务转入已完成seeding_status = active的任务,重新 add_torrent 并注册 seeder3.1.4 DB Schema 扩展 —
native/engine/src/db.rstasks表新增列:uploaded_bytesseeding_statusseeding_message3.2 信号层 —
native/hub/src/signals/mod.rsTaskProgress信号新增字段:uploaded_bytesupload_speed_bpsseeding_statusseeding_messagechecking_progressControlTask新增 action:5= 停止做种6= 暂停做种7= 恢复做种3.3 Flutter UI 层
3.3.1 任务列表 (
task_list_item.dart)3.3.2 详情面板 (
detail_panel.dart)3.3.3 侧边栏 (
sidebar.dart+download_controller.dart)seeding_status == active的任务3.3.4 设置页 (
settings_page.dart)BT 设置区重构做种限制 UI:
3.3.5 下载任务模型 (
download_task.dart)SeedingStatus枚举uploadedBytes、uploadSpeedBps、seedingStatus、seedingMessage、seedingStartedAt、checkingProgress字段isSeeding、isChecking计算属性seedRatio分享率计算seedingDuration做种时长3.3.6 国际化 (
translations.dart)新增翻译 key(中/英):
3.4 Server 模式 (无头服务器)
native/server/src/actor.rs同步所有 engine 层变更:做种定时评估、配置热更新。3.5 aria2 JSON-RPC API (
native/api/)tellStatus响应新增字段:uploadLength(aria2 标准)uploadSpeed(aria2 标准)seedRatio(自定义扩展)seedingStatus(自定义扩展)四、实现方案
4.1 整体架构
4.2 分阶段实施
第一阶段:核心能力(必须)
DB Schema + 数据模型
SeedingManager + 完成路径改造
max_seeding_tasks限制强制执行(FIFO 逐出)全局速度限制联动 BT 上传
set_speed_limit()同时限制下载和上传重启恢复做种
seeding_status = active的 completed 任务第二阶段:UI 与交互
任务列表双速显示 + 做种状态
详情面板做种指标
侧边栏新增"做种中" Tab
设置页做种限制条件开关
第三阶段:完善与健壮性
aria2 API 暴露做种字段
tellStatus返回上传量和做种状态做种停止桌面通知
做种会话历史记录
seeding_sessions表集成测试
4.3 关键设计决策
五、预期效果
5.1 用户可见变化
5.2 行为变化
六、风险评估
6.1 技术风险
.bitv文件;若无则走降级路径(重置 seeding_status)invalidate_bt_session前检查has_seeders(),等待做种结束或强制通知用户max_seeding_tasks默认值(如 10),复用 librqbit 的defer_writes_up_to减少常开句柄concurrent_init_limit(已有 3),串行恢复做种6.2 产品风险
uploaded_bytes统计,不做额外计算bt_upload_speed_limit_kbps值到全局speed_limit_bytes6.3 兼容性风险
add_column_if_missing)TaskProgress新增字段需要 Dart 侧同步更新#[serde(default)],旧版 Dart 忽略未知字段uploadLength/uploadSpeed为标准 aria2 字段;seedRatio/seedingStatus为自定义扩展七、不做的事情(明确范围边界)