rusty-cat 分片并发下载完全指南(Rust 小白版)
本文面向 刚接触 Rust、想快速把「大文件分片并发下载 + 断点续传」跑起来 的开发者。 每段代码都能直接复制到你的项目里编译运行,需要替换的地方都写了中文注释。 配套阅读:《rusty-cat 分片并发上传完全指南》。
目录
- 下载功能能帮你做什么
- 第一步:加依赖
- 5 分钟跑通第一个下载(完整可运行程序)
- 下载是怎么工作的:HEAD + Range GET
- 开启并发下载——
with_max_parts_in_flight+with_total_size - 并发下载配方(复制即用)
- 下载云存储对象(OSS / Azure)的两种姿势
- 并发下载的断点续传:
.rcdl边车文件 - 进度、暂停、恢复、取消
- 内存占用与参数怎么选
- 错误处理与自动重试
- 常见问题排查表(FAQ)
- 附录:配置项速查表
1. 下载功能能帮你做什么
rusty-cat 的下载能力围绕「大文件的可断点续传下载」:
- 分片下载:用 HTTP
Range请求把一个大文件分成很多小块拉取; - 并发下载:同一个文件的多个 range 分片可以同时拉,把带宽跑满;
- 断点续传:进程被杀、崩溃、重启后能接着下,不用从头再来;
- 进度回调 / 暂停 / 恢复 / 取消:和上传共用同一套心智模型;
- 自动重试 + 退避:网络抖动自动重试,且区分「瞬时错误」(重试)和「硬错误」(快速失败)。
好消息是:下载不需要任何云厂商密钥。只要你有一个能响应 HTTP Range 请求的 URL(公网直链、阿里云预签名 URL、Azure SAS URL 都行),就能用内置的默认下载器跑起来。
一句话记住用法:创建
MeowClient→ 用DownloadPounceBuilder构建下载任务 → 提交 → 收进度 →close()。
2. 第一步:加依赖
最基础的并发下载不需要任何 feature,基础 crate 就够了:
[dependencies]
rusty-cat = "0.2.4"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
只有当你要用「provider 专属的下载协议」(比如用 AccessKey 直接签名去下 OSS 对象)时,才需要开对应 feature:
# 仅当你要用 provider 专属下载协议时才需要:
# rusty-cat = { version = "0.2.4", features = ["aliyun-oss-direct"] } # OSS 直下
# rusty-cat = { version = "0.2.4", features = ["aliyun-oss-presigned"] } # OSS 预签名 range 下载
# rusty-cat = { version = "0.2.4", features = ["azure-blob-direct"] } # Azure 直下
# rusty-cat = { version = "0.2.4", features = ["azure-blob-sas"] } # Azure SAS range 下载
先记住一个关键结论(第 5、7 节会展开):想要「并发」下载,用的是内置默认下载器 + 一个签好名的 GET URL,不需要 provider 下载协议。provider 专属的下载协议只能串行。
3. 5 分钟跑通第一个下载(完整可运行程序)
下面是一个完整的 main.rs,把一个公网文件下载到本地。把 URL 换成你自己的可下载链接,cargo run 即可。
use std::time::Duration;
use rusty_cat::api::{DownloadPounceBuilder, FileTransferRecord, MeowClient, MeowConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// 提示:确保本地保存目录(这里是 ./downloads)已经存在
let config = MeowConfig::builder()
.max_download_concurrency(2) // 同时最多下 2 个「文件」
.http_timeout(Duration::from_secs(30))
.build()?;
let client = MeowClient::new(config);
let task = DownloadPounceBuilder::new(
"example.bin", // 展示用文件名
"./downloads/example.bin", // 本地保存路径
1024 * 1024, // 分片大小 = 1 MiB
"https://example.com/example.bin", // 下载 URL(换成你的)
)
.with_max_chunk_retries(3) // 每片失败最多再重试 3 次
.build();
// enqueue_and_wait:提交并一直等到跑完,最省事
let outcome = client
.enqueue_and_wait(task, |record: FileTransferRecord| {
println!(
"下载进度 {:.1}% 状态 {:?}",
record.progress() * 100.0,
record.status()
);
})
.await?;
println!("下载完成!task_id={}", outcome.task_id);
// 关闭客户端(必须!)
client.close().await?;
Ok(())
}
几个要点:
DownloadPounceBuilder::new的四个参数依次是:展示文件名、本地保存路径、分片大小、下载 URL。- 上面这段是串行下载(没开并发),任何支持
Range的 URL 都能跑。开并发见第 5 节。 enqueue_and_wait成功返回TaskOutcome,失败 / 取消返回Err,用?即可。- 一定要
client.close().await:优雅关闭后台调度、发完缓冲事件。别指望Drop兜底。 - 目标目录要先存在(比如先
std::fs::create_dir_all("./downloads")?)。
4. 下载是怎么工作的:HEAD + Range GET
理解这套机制,能帮你少踩很多坑:
- 准备阶段(prepare):SDK 先发一个
HEAD请求,从响应的Content-Length得知文件总大小,据此把文件切成一格一格的 range 网格。 - 传输阶段:对每一格发
GET请求,带Range: bytes=起-止头,服务端必须返回206 Partial Content。 - 落盘:每个 range 响应体直接写到本地文件的绝对偏移位置。
🖼️ 【配图占位 D1|并发下载数据流(HEAD + 并行 Range GET)】 建议配图:客户端先发一次
HEAD拿到Content-Length(若已with_total_size则跳过这步);随后把文件切成 range 网格,4 条并行箭头表示同时发出的Range GET(各要一段bytes=起-止,服务端回206);每段响应体写入本地预撑文件的对应绝对偏移。图注:各分片完全独立、可乱序、可并发。 临时 ASCII 草图:客户端 ──HEAD──▶ 服务端(拿 Content-Length;有 with_total_size 则跳过) ═══GET bytes=0-2M═════▶ ┐ ═══GET bytes=2M-4M════▶ ├─ 4 段并行,各回 206 ═══GET bytes=4M-6M════▶ │ ═══GET bytes=6M-8M════▶ ┘ ▼ 每段写入本地文件的绝对偏移 本地文件 [__0-2M__][__2M-4M__][__4M-6M__][__6M-8M__]
由此推出两条硬规则:
- 服务端必须支持
Range。如果服务端无视Range、返回了整个文件(200 OK),会被判定为InvalidRange硬错误。 - 下载的 HTTP 方法不可配置(固定
HEAD+GET)。如果某个网关需要非标准动作,就自己实现BreakpointDownload。
关于给
GET加Range头会不会破坏「URL 里带签名」的鉴权(预签名 / SAS):不会。按 RFC 7233,Range 放在请求头里,而预签名 / SAS 的签名只覆盖 URL 和 query 参数、不覆盖任意请求头。所以同一个签好名的 range URL 可以被切成任意多个Range分片、甚至并发拉取。
5. 开启并发下载——with_max_parts_in_flight + with_total_size
和上传一样,两个「并发」是独立的,别搞混:
| 旋钮 | 作用范围 | 默认 | 控制什么 |
|---|---|---|---|
MeowConfig::builder().max_download_concurrency(k) | 整个客户端 | 2 | 同时下 几个文件 |
DownloadPounceBuilder::with_max_parts_in_flight(n) | 单个文件内部 | 1 | 一个文件的 几个 range 分片 同时拉 |
两者相乘:max_download_concurrency(3) 且每个文件 with_max_parts_in_flight(4),则最多 3 × 4 = 12 个 range 请求同时在飞。没有全局上限,请自己控制乘积。
并发下载的三个前置条件(并发闸门)
设了 with_max_parts_in_flight(8) 并不保证 真并发。只有 同时满足以下三条 才走并发路径:
n > 1(0归一化为1);- 文件总大小已知——这是下载最关键的一条,两种方式满足:
- 显式调
with_total_size(总字节数)(推荐,还能顺便跳过HEAD),或 - 让
HEAD探测出来(服务端必须返回正数Content-Length)。
- 显式调
- 下载协议是「并发安全」的。
哪个下载协议支持并发?(上传 / 下载不对称,务必记住)
| 下载协议 | 并发安全? | 说明 |
|---|---|---|
StandardRangeDownload(内置默认) | ✅ 是 | 标准 RFC 7233 Range 请求,每片完全独立、写到绝对偏移 |
AliOssDirectDownload | ❌ 否 | provider 专属协议,只能串行 |
AzureBlobDirectDownload | ❌ 否 | 同上 |
PresignedRangeDownload(OSS 预签名 / Azure SAS) | ❌ 否 | 同上 |
你自己实现的 BreakpointDownload | ❌ 否(默认) | 除非显式声明支持 |
⚠️ 上传和下载不对称! 上传时,四种 provider 上传协议都并发安全;但下载时,唯一并发安全的是内置的
StandardRangeDownload。要并发下载一个 OSS / Azure 对象,做法是:把一个签好名的 GET URL(阿里云预签名 URL、Azure SAS URL、或公网直链)直接喂给默认下载器——也就是不要调
with_breakpoint_download(...)。一旦挂了 provider 下载协议,就会静默变回串行。
另一个致命坑:如果你开了并发(
n > 1)却没让总大小可知——既没调with_total_size,HEAD又拿不到正数Content-Length——那么任务会在准备阶段直接失败(MissingOrInvalidContentLengthFromHead),不会悄悄退回串行。所以对那些不支持HEAD的签名 URL,请务必用with_total_size显式给出总大小。
6. 并发下载配方(复制即用)
这是本文的核心配方:用默认下载器 + 一个签好名的 GET URL,实现并发下载。
use rusty_cat::api::{DownloadPounceBuilder, MeowClient, MeowConfig};
// signed_get_url:阿里云预签名 / Azure SAS / 公网 GET URL
// total_size:文件总字节数(从你的元数据接口 / check 接口拿到)
async fn download_concurrent(
signed_get_url: &str,
total_size: u64,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let client = MeowClient::new(MeowConfig::default());
let task = DownloadPounceBuilder::new(
"movie.mp4",
"./downloads/movie.mp4",
2 * 1024 * 1024, // 2 MiB range 分片
signed_get_url,
)
.with_total_size(total_size) // 条件2:总大小已知,顺便跳过 HEAD
.with_max_parts_in_flight(4) // 条件1:最多 4 个 Range GET 并发
// 千万不要调 .with_breakpoint_download(...),要保持默认的 StandardRangeDownload
.build();
client
.enqueue_and_wait(task, |r| println!("{:.1}%", r.progress() * 100.0))
.await?;
client.close().await?;
Ok(())
}
并发下载的几条关键规则:
- 一定要给总大小。
with_total_size(total)满足前置条件 2,并跳过HEAD(对那些不响应HEAD的预签名 / SAS URL 尤其重要)。 - 服务端必须对
Range返回206。返回200 OK(无视 range)会被判为InvalidRange硬错误。 - 要加 provider 头就用
with_headers(...),绝不要去改 URL。比如某些严格的 Azure 网关要求显式x-ms-version,用with_headers加进去即可,它会同时作用于HEAD和 rangeGET。
⚠️ 稳定 URL 规则(并发下载必读)
StandardRangeDownload 对每一个并发分片都复用同一个固定 URL(task.url()),并且没有 URL 刷新机制。所以:
用于并发下载的预签名 / SAS URL,必须在整个传输(含续传)期间都保持有效。 签发时把有效期设得足够长,覆盖整个下载过程。
(预签名 URL 的自动刷新机制 PresignedDownloadUrlRefresher 只在串行的 PresignedRangeDownload 路径上生效,而并发下载走的不是那条路径。)
别把两个 with_total_size 搞混
DownloadPounceBuilder::with_total_size(total)—— 任务构建器上的方法,就是上面开启并发用的这个。PresignedRangeDownloadPlan::with_total_size(total)—— plan 上的方法,供串行的PresignedRangeDownload协议使用,不会开启并发。
并发下载请用构建器上的那个 + 默认下载器。
7. 下载云存储对象(OSS / Azure)的两种姿势
姿势一(推荐,可并发):默认下载器 + 签名 URL
让你的后端签发一个 OSS 预签名 GET URL 或 Azure SAS URL,然后直接用第 6 节的 download_concurrent。这样既能并发、又不需要在客户端放任何密钥。这是绝大多数场景的首选。
姿势二(串行):provider 专属下载协议
如果你的程序运行在可信服务器上、且想直接用 AccessKey / Shared Key 签名,可以挂 provider 下载协议。注意这些协议只能串行(with_max_parts_in_flight 对它们无效)。每种云的串行下载完整代码放在对应的实战文章里:
| 串行下载方式 | Feature | 完整代码 |
|---|---|---|
阿里云 OSS 直下(AliOssDirectDownload,AccessKey) | aliyun-oss-direct | 阿里云 OSS 直传直下 · 下载方式一 |
阿里云 OSS 预签名 range 下载(PresignedRangeDownload) | aliyun-oss-presigned | 阿里云 OSS 预签名 · 下载方式一 |
Azure Blob 直下(AzureBlobDirectDownload,Shared Key) | azure-blob-direct | Azure Blob 直传直下 · 下载方式一 |
Azure Blob SAS range 下载(PresignedRangeDownload) | azure-blob-sas | Azure Blob SAS · 下载方式一 |
共同套路是:构建对应的 provider 下载协议 → with_breakpoint_download(Arc::new(协议)) → build()。最小上手片段(以 OSS 直下为例):
let protocol = AliOssDirectDownload::new("my-bucket", "AK_ID", "AK_SECRET", "cn-beijing");
let task = DownloadPounceBuilder::new("obj.bin", "./downloads/obj.bin", 1024 * 1024, object_url)
.with_breakpoint_download(Arc::new(protocol)) // 挂 provider 协议 = 串行
.build();
想让上面这些 OSS / Azure 对象并发下载? 别用这一节的 provider 协议,改回第 6 节:让后端签一个 GET URL,用默认下载器 +
with_total_size+with_max_parts_in_flight(4)。各云怎么签 URL 见对应实战文章的「下载方式二(推荐,可并发)」。
8. 并发下载的断点续传:.rcdl 边车文件
串行下载和并发下载的续传机制不一样:
- 串行下载靠文件长度续传:SDK 看到本地半成品文件有
X字节,就请求bytes=X-。不需要边车文件。 - 并发下载把分片乱序写进一个预先撑到最终大小的文件,光看文件长度已经无法判断哪些分片下好了。于是它在目标文件旁边维护一个
<目标文件>.rcdl(resumable download log)边车文件:一张「哪些固定大小、按块对齐的分片已经稳妥落盘」的位图。
🖼️ 【配图占位 D2|.rcdl 边车续传】 建议配图:分三格时间轴。①第一次运行:预撑好的文件被分片写入,
.rcdl位图记录「分片 0/2/3 已落盘、分片 1 缺失」,此时进程被杀。②第二次运行:读.rcdl,只重新拉取缺失的分片 1(已完成分片短路、不发网络请求)。③成功完成:校验文件长度 = total、所有分片齐全后,删除.rcdl。图注:.rcdl故意在取消/失败后保留,只有成功才删。 临时 ASCII 草图:第1次运行 文件[#0✅][#1⬜][#2✅][#3✅] .rcdl 位图: 1011 ← 进程被杀,.rcdl 保留 第2次运行 只补 #1 ─Range GET─▶ #0/#2/#3 短路不下载 成功完成 校验长度=total & 分片齐全 ──▶ 删除 .rcdl
边车什么时候会被复用 vs 丢弃
下次运行时,只有以下每一项都匹配,边车才会被信任、只补下缺失的分片:
| 绑定项 | 必须一致 |
|---|---|
| Range URL 身份 | 同一个 URL(对其做 FNV-1a 哈希,含 host/port/path/query) |
total | 同样的总大小 |
chunk | 同样的分片大小 |
max_parts | 同样的 with_max_parts_in_flight 值 |
| 目标文件 | 其磁盘长度已经等于 total(是预撑好的,没被截断 / 删除) |
只要任何一项变了(换了 URL、对象被重新生成、改了分片大小、改了 max_parts、目标文件被删/截断),旧边车就会被忽略,重新完整下载一遍。所以一个残留的 .rcdl 最坏也只会导致一次安全的重下,绝不会造成数据损坏。
生命周期
- 边车文件故意在取消 / 失败后保留,好让下次运行接着补下缺失分片(已下好的分片会直接短路、不发网络请求);
- 只有在成功完成后才会被删除(SDK 会先校验文件长度等于
total、每个分片都在)。 - 一次性、绝不续传的调用方,可以自己手动删掉它。
跨模式保护:如果目标文件旁边存在
.rcdl,串行下载路径会拒绝运行并返回InvalidTaskState。一个被中断的并发下载不能用串行方式接着下——要么继续用with_max_parts_in_flight(n)(n > 1)续传,要么把边车和半成品文件都删掉、从头开始。
进程重启后如何续传
和上传一样,rusty-cat 不内置数据库,续传要靠你在自己的库里持久化任务信息,重启后重建同一个 PounceTask 再 try_enqueue。对下载来说:
- 持久化:本地路径、下载 URL、分片大小、
max_parts_in_flight、总大小等; - 重启后查出未完成的任务、重建
DownloadPounceBuilder(这五项要和上次完全一致,否则.rcdl会被判失效而重下); - 再次
try_enqueue,并发下载会自动读.rcdl、只补缺失分片。
9. 进度、暂停、恢复、取消
用 try_enqueue 拿细粒度回调 + TaskId
enqueue_and_wait 适合「提交后等到结束」。要做 UI、后台异步跑,用 try_enqueue,它返回 TaskId:
use rusty_cat::api::{
DownloadPounceBuilder, FileTransferRecord, MeowClient, MeowConfig, TaskId, TransferStatus,
};
async fn download_with_callbacks(
url: &str,
total: u64,
) -> Result<TaskId, Box<dyn std::error::Error + Send + Sync>> {
let client = MeowClient::new(MeowConfig::default());
let task = DownloadPounceBuilder::new("f.bin", "./downloads/f.bin", 1024 * 1024, url)
.with_total_size(total)
.with_max_parts_in_flight(4)
.with_client_file_sign("business-file-id-001") // 可选:把业务主键塞进进度记录
.build();
let task_id = client
.try_enqueue(
task,
// 进度回调
move |record: FileTransferRecord| match record.status() {
TransferStatus::Failed(err) => eprintln!("下载失败:{err}"),
TransferStatus::Canceled => println!("已取消"),
_ => println!("进度 {:.1}%", record.progress() * 100.0),
},
// 完成回调(下载的 payload 通常是 None)
move |task_id, _payload| println!("任务 {task_id} 下载完成"),
)
.await?;
Ok(task_id)
}
拿到 TaskId 就能控制任务:
client.pause(task_id).await?; // 暂停
client.resume(task_id).await?; // 从断点继续(TaskId 不变)
client.cancel(task_id).await?; // 取消
并发下的进度行为(和上传一致)
即便分片乱序完成,SDK 只上报「最长连续前缀」的进度(水位线):
- 进度单调递增,绝不回退;
- 靠后的分片先下完、但前面有空洞时,进度会原地不动,直到空洞填上——是正常现象,不是卡死;
- 每次水位线推进只收到一次合并后的进度事件,终态只有一次。
with_client_file_sign(...) 可以把你的业务主键放进 FileTransferRecord,回调里用 record.file_sign() 读出来,方便和数据库对应。
10. 内存占用与参数怎么选
每个在途 range 分片都需要一个缓冲区:
单个文件的峰值下载内存 ≈
n × 分片大小(上限,实际通常更低,因为响应体是边收边写进预撑好的文件的)
整个客户端要对同时在下的文件求和:
客户端峰值内存 ≈ max_download_concurrency × 下载 n × 下载分片大小
+ max_upload_concurrency × 上传 n × 上传分片大小
没有全局内存上限,请自己控制。实用建议:
- 分片大小保持 1–8 MiB。太小请求开销大;太大每次重试要重下更多、且抬高内存下限。
n从 4 开始试,仅在大文件 + 快网时用。带宽跑满后再加n收益很小、内存却翻倍。- 别忘了乘文件级并发:
4个文件 ×n=8×4 MiB= 最多128 MiB缓冲。
11. 错误处理与自动重试
大多数调用返回 Result<_, MeowError>。用 MeowError::code()(稳定 i32 数字码)做分支,用 MeowError::msg() 打日志。不要匹配错误文本。
下载常见错误码:
| 码 | 名称 | 什么时候发生 |
|---|---|---|
102 | ParameterEmpty | 必填项(URL、文件名)为空 |
103 | DuplicateTaskError | 同一个 URL 的下载任务已经在排队 / 运行 / 暂停 |
107 | ClientClosed | 客户端已关闭,请新建 MeowClient |
111 | CommandSendFailed | 命令队列满(快速失败),退避重试或调大 command_queue_capacity |
117 | InvalidTaskState | 状态不允许该操作(如目标旁有 .rcdl 却走串行、或 resume 一个非暂停任务) |
120 | TaskCanceled | 完成前被取消 |
121 | DiskFull | 写下载文件时磁盘满 |
122 | LocalFileRemoved | 传输中本地目标文件被删 |
还有两个下载特有的「硬错误」,它们快速失败、不重试(因为重试也没用):
InvalidRange:服务端对Range返回了200 OK(无视 range),或Content-Range的起始 / 总大小对不上。→ 换一个真正支持206 Partial Content的端点。MissingOrInvalidContentLengthFromHead:开了并发但总大小拿不到(没给with_total_size,HEAD又没返回正数Content-Length)。→ 显式with_total_size(...)。
自动重试
with_max_chunk_retries(n):单个 range 分片首次失败后额外重试的次数(默认3,0关闭),串行 / 并发路径都是按「每片」计。- 预算内只重试瞬时错误(连接重置、超时、消息不完整、HTTP
408/429/5xx),并用指数退避(基准 200ms、上限 5000ms)+ ±20% 抖动等待。硬错误(如403、InvalidRange)快速失败,不消耗预算。
12. 常见问题排查表(FAQ)
| 现象 | 可能原因 | 解决 |
|---|---|---|
设了 n > 1 但还是串行 | 三个前置条件没满足 | 确认 n > 1、用默认下载器、且总大小已知(with_total_size) |
| OSS / Azure 对象无法并发 | 挂了 provider 下载协议(只能串行) | 去掉 with_breakpoint_download(...),用默认下载器 + 签名 GET URL |
| 任务准备阶段直接失败 | 开了并发但总大小拿不到 | 显式 with_total_size(...),或改用能返回 Content-Length 的端点 |
分片报 InvalidRange | 服务端对 Range 回了 200(无视 range) | 指向真正支持 206 Partial Content 的端点 |
| 进度卡住然后突然跳 | 靠后分片先下完、前面有空洞 | 正常现象,进度按连续前缀单调推进,不是卡死 |
串行重下报 InvalidTaskState | 目标旁残留了上次并发中断的 .rcdl | 继续用 with_max_parts_in_flight(n) 续传,或删掉 .rcdl 和半成品文件重来 |
| 续传却从头下 | URL / total / chunk / max_parts / 目标文件长度和上次不一致 | 这五项保持稳定,否则接受完整重下 |
| 签名 URL 传输中途失效 | 并发下载复用一个 URL、无刷新 | 签发时把有效期设得覆盖整个下载(含续传) |
入队大量任务报 CommandSendFailed | 命令队列满(try_enqueue 快速失败) | 调大 command_queue_capacity 或自己退避重试 |
13. 附录:配置项速查表
DownloadPounceBuilder(下载任务)
| 方法 | 必填? | 说明 |
|---|---|---|
new(file_name, file_path, chunk_size, url) | 是 | 创建 range 下载任务;chunk_size == 0 归一化为默认 1 MiB |
with_total_size(size) | 并发要 | 已知总大小,跳过 HEAD;开启并发下载的关键 |
with_max_parts_in_flight(n) | 可选 | 单文件 range 分片并发数,默认 1;仅默认下载器 + 总大小已知时生效 |
with_max_chunk_retries(n) | 可选 | 单片重试次数,默认 3 |
with_url(url) | 可选 | 替换下载 URL |
with_file_path(path) | 可选 | 替换本地保存路径 |
with_headers(headers) | 可选 | 替换 HEAD 和 range GET 的基础请求头(加 provider 头用这个) |
with_client_file_sign(sign) | 可选 | 把业务主键塞进进度记录,回调里用 file_sign() 读 |
with_breakpoint_download(Arc::new(...)) | 可选 | 挂 provider / 自定义下载协议(会变串行) |
with_breakpoint_download_http(cfg) | 可选 | 单任务覆盖 range 下载的 Accept 头 |
build() | 是 | 返回 PounceTask(无错误,校验发生在入队 / 运行时) |
MeowConfig(客户端级配置)
| 参数 | 默认 | 约束 | 说明 |
|---|---|---|---|
max_download_concurrency | 2 | >= 1 | 同时下载的文件数 |
max_upload_concurrency | 2 | >= 1 | 同时上传的文件数 |
http_timeout | 5s | 正数 | 单请求超时 |
tcp_keepalive | 30s | 正数 | TCP keepalive |
command_queue_capacity | 128 | >= 1 | 命令队列容量 |
worker_event_queue_capacity | 256 | >= 1 | 事件队列容量 |
breakpoint_download_http.range_accept | application/octet-stream | 合法头值 | range 下载默认 Accept 头 |
MeowClient(客户端)常用方法
| 方法 | 用途 |
|---|---|
MeowClient::new(config) | 创建客户端(执行器懒启动) |
enqueue_and_wait(task, progress_cb).await | 提交并等到终态,返回 TaskOutcome |
try_enqueue(task, progress_cb, complete_cb).await | 提交任务,返回 TaskId(快速失败,不等完成) |
try_enqueue_paused(task, ..).await | 以暂停态导入,不做任何 IO,之后 resume 才启动 |
pause / resume / cancel (task_id).await | 暂停 / 恢复 / 取消 |
register_global_progress_listener(cb) | 注册观测「所有任务」进度的全局监听器 |
snapshot().await | 查看排队 / 活跃的任务组数量 |
close().await | 关机必调:优雅关闭 |
相关阅读
- 《rusty-cat 分片并发上传完全指南》 —— 四种云上传配方、内存字节上传、自定义上传协议等。
- 官方英文文档:
rusty-cat/docs/concurrent-chunk-transfer.md、rusty-cat/README.md。
本文基于
rusty-cat0.2.4 编写,所有代码片段均经过cargo check编译验证。