rusty-cat
rusty-cat is an async Rust SDK for resumable file upload and download. It gives applications a compact public facade for building transfer tasks, running those tasks in a background scheduler, receiving progress callbacks, and plugging in protocol-specific implementations such as plain HTTP, Aliyun OSS, Aliyun OSS presigned URLs, Azure Blob Storage, and Azure Blob SAS URLs.
The crate is designed for applications that need reliable large-file transfer without forcing a specific storage backend or database layer. The SDK handles scheduling, chunk dispatch, retry, pause/resume/cancel commands, and progress fan-out. Your application remains responsible for business records, credential management, user permissions, and provider-specific setup.
The recommended public import is:
use *;
Existing module paths still work, but rusty_cat::api::* is the stable, beginner-friendly entry point. Using the facade also makes future refactoring easier because most application code can import SDK types from a single module.
Package, platform, Rust, and license
| Item | Value |
|---|---|
| Crate | rusty-cat |
| Version | 0.1.1 |
| Rust edition | 2021 |
| Runtime | Tokio-based async runtime hosted by an internal scheduler thread |
| HTTP stack | reqwest with rustls-tls |
| Platforms | Linux, macOS, and Windows targets supported by stable Rust, Tokio, and reqwest |
| License | MIT |
| Repository | https://github.com/0barman/rusty-cat |
Badge Markdown
The Crates.io, Docs.rs, and License badge Markdown is shown below. These badges are safe to paste into downstream README files or generated documentation pages:
[](https://crates.io/crates/rusty-cat)
[](https://docs.rs/rusty-cat)
[](LICENSE)
Feature highlights
Capability matrix
| Capability | Supported | Notes |
|---|---|---|
| HTTP resumable upload | Yes | Upload tasks are split into chunks and delegated to a BreakpointUpload implementation. The default style supports multipart/form-data chunk requests, and provider plugins can replace the request logic. |
| HTTP resumable download | Yes | Download tasks use HEAD during preparation and GET with Range headers for chunk transfer through StandardRangeDownload. |
| Aliyun OSS direct upload/download | Yes | Enable aliyun-oss-direct; use AliOssDirectUpload and AliOssDirectDownload when the client process is trusted to hold AccessKey credentials. |
| Aliyun OSS presigned upload/download | Yes | Enable aliyun-oss-presigned; use short-lived presigned part and range URLs generated by your backend. |
| Azure Blob direct upload/download | Yes | Enable azure-blob-direct; use Shared Key-authenticated block upload and range download when the client process is trusted to hold the storage account key. |
| Azure Blob SAS upload/download | Yes | Enable azure-blob-sas; use short-lived SAS URLs generated by your backend. |
| Upload concurrency setting | Yes | MeowConfig::builder().max_upload_concurrency(n) limits the number of upload groups running at the same time. |
| Download concurrency setting | Yes | MeowConfig::builder().max_download_concurrency(n) limits the number of download groups running at the same time. |
| Upload progress | Yes | Per-task progress callbacks passed to MeowClient::try_enqueue(...) receive FileTransferRecord snapshots. |
| Download progress | Yes | The same callback model is used for downloads, so upload and download UI code can share one progress-record handler. |
| Global progress listener | Yes | register_global_progress_listener(...) observes all tasks created by the client, which is useful for dashboards and persistence workers. |
| Global SDK debug logs | Yes | set_debug_log_listener(...) installs a process-global SDK log listener for diagnostics and integration tests. |
| Application-managed persistence | Yes | The SDK intentionally does not persist transfer state in an embedded database, so it can fit server, desktop, mobile, and CLI applications. |
| Custom database adaptation | Yes | Persist records from callbacks/listeners in your own database and rebuild tasks after restart. |
| Callback panic isolation | Yes | User callbacks are isolated from scheduler execution; callbacks should still be fast, non-blocking, and panic-free. |
| Chunk failure retry | Yes | with_max_chunk_retries(...) on upload and download builders controls additional retries after the first failed chunk transfer. |
| Upload prepare retry | Yes | UploadPounceBuilder::with_max_upload_prepare_retries(...) controls additional retries after the first failed upload preparation attempt. |
| Pause/resume/cancel | Yes | Use pause(...), resume(...), and cancel(...) with the returned TaskId. |
| Snapshot diagnostics | Yes | snapshot() returns queued and active scheduler state for monitoring and troubleshooting. |
| Custom HTTP client | Yes | Inject a preconfigured reqwest::Client with MeowConfigBuilder::http_client(...) for proxy, TLS, default headers, or observability integration. |
| Custom upload protocol | Yes | Implement BreakpointUpload to integrate business-specific upload APIs. |
| Custom download protocol | Yes | Implement BreakpointDownload to integrate custom range-download authentication or headers. |
Architecture overview
| Layer | Main types | Responsibility |
|---|---|---|
| Public facade | rusty_cat::api::* |
One import point for client, config, task builders, callbacks, errors, status, logs, and optional providers. |
| Client | MeowClient |
Owns immutable config, lazily starts the executor, submits tasks, controls lifecycle, and manages listeners. |
| Config | MeowConfig, MeowConfigBuilder |
Defines concurrency, queue capacities, HTTP timeout/keepalive, range-download behavior, and optional custom HTTP client. |
| Task builders | UploadPounceBuilder, DownloadPounceBuilder |
Convert simple parameters into executable PounceTask values. |
| Scheduler | Internal executor | Runs background workers, queues tasks, dispatches chunks, retries failures, and emits events. |
| Protocol plugins | BreakpointUpload, BreakpointDownload |
Implement provider-specific signing, presigned URLs, chunk requests, and completion behavior. |
| Observability | FileTransferRecord, TransferSnapshot, Log |
Per-task progress, global progress events, queue snapshots, and debug logs. |
Quick start
Add the crate:
[]
= "0.1.1"
= { = "1", = ["macros", "rt-multi-thread"] }
For OSS providers, enable only what you need. Keeping the feature list small reduces optional dependencies and makes it clearer which cloud integrations your application actually uses:
[]
= { = "0.1.1", = ["aliyun-oss-direct"] }
| Feature | Purpose |
|---|---|
aliyun-oss-direct |
Aliyun OSS direct upload/download with AccessKey credentials and OSS Signature Version 4 signing. |
aliyun-oss-presigned |
Aliyun OSS presigned multipart upload and range download helpers. |
azure-blob-direct |
Azure Blob upload/download with Shared Key authentication. |
azure-blob-sas |
Azure Blob SAS upload/download helpers. |
presigned |
Provider-neutral presigned multipart/range primitives. |
all |
Enables all provider features. Use it for examples, not minimal production builds. |
For a focused comparison of direct credentials versus presigned/SAS URLs, see Provider feature flags: direct vs presigned/SAS.
Complete end-to-end example
This example starts from MeowConfig, creates a MeowClient, registers listeners, builds a task, submits it, waits for the completion/failure signal, inspects a snapshot, and closes the client. It uses an HTTP range download task because that path works without cloud credentials; the same client lifecycle applies to upload tasks and OSS/Azure provider tasks.
use ;
use Duration;
use ;
async
MeowClient API guide
| Function | Use it when | Important notes |
|---|---|---|
MeowClient::new(config) |
Create the SDK entry point. | The executor starts lazily on the first task operation. MeowClient is not Clone because it owns scheduler state; wrap it in Arc<MeowClient> when multiple async tasks or threads need shared access. |
http_client() |
Need a reqwest::Client aligned with SDK config. |
Returns the injected custom client when one was configured; otherwise builds a client from http_timeout and tcp_keepalive. This is useful when protocol code outside the executor must make compatible HTTP calls. |
register_global_progress_listener(listener) |
Observe all task progress records. | Returns a GlobalProgressListenerId. Use this for UI-wide progress aggregation, persistence queues, or monitoring. Keep callback work fast. |
unregister_global_progress_listener(id) |
Remove one global listener. | Returns Ok(false) when the ID does not exist, so cleanup code can call it safely. |
clear_global_listener() |
Remove every global progress listener. | Useful during shutdown, integration-test cleanup, or application logout flows. |
set_debug_log_listener(Some(listener)) |
Receive SDK debug logs. | The listener is process-global rather than client-local. Pass None to clear it before shutdown or when tests need isolation. |
try_enqueue(task, progress_cb, complete_cb).await |
Submit an upload/download task. | This performs asynchronous submission, not synchronous transfer completion. It fails fast when the command queue is full. Store the returned TaskId for pause/resume/cancel operations. |
pause(task_id).await |
Pause a queued or running task. | Sends a command to the scheduler. A paused task can be resumed later with the same TaskId. |
resume(task_id).await |
Continue a paused task. | Keeps the same TaskId and asks the scheduler to continue from available local/remote progress. |
cancel(task_id).await |
Stop a task. | Cancellation is best-effort and may run provider cleanup such as aborting a multipart session. Treat canceled tasks as terminal unless your application deliberately creates a new task. |
snapshot().await |
Inspect queued and active groups. | Useful for dashboards, health checks, and debugging scheduler behavior under concurrency. |
close().await |
Shut down. | Mandatory for clean shutdown: cancels in-flight work, flushes Paused events, drains callbacks, and joins the scheduler thread. Do not rely on Drop for production shutdown. |
is_closed() |
Check whether the client is closed. | A successfully closed client cannot be reopened; create a new MeowClient if you need to submit more work. |
There is no public enqueue(...) method in the current API. Use try_enqueue(...); the name is intentional because enqueue uses fail-fast backpressure. If your application submits many tasks at once, increase command_queue_capacity or retry CommandSendFailed with your own backoff policy.
Configuration parameters
MeowConfig and MeowConfigBuilder
Start with MeowConfig::default() for a safe baseline or use MeowConfig::builder() for validated customization. The configuration is immutable after the client is created, which prevents accidental runtime changes from affecting tasks already in the scheduler.
| Parameter | Default | Constraint | Description |
|---|---|---|---|
max_upload_concurrency |
2 |
>= 1 |
Maximum upload groups processed concurrently. |
max_download_concurrency |
2 |
>= 1 |
Maximum download groups processed concurrently. |
breakpoint_download_http.range_accept |
application/octet-stream |
Valid header value | Default Accept header for range download chunks. |
http_client |
None |
Reusable reqwest::Client |
Optional custom HTTP client for proxy, TLS, default headers, or observability. |
http_timeout |
5s |
Positive duration | Per-request timeout for internally built HTTP clients. |
tcp_keepalive |
30s |
Positive duration | TCP keepalive for internally built HTTP clients. |
command_queue_capacity |
128 |
>= 1 |
Queue for enqueue, pause, resume, cancel, snapshot, and close commands. |
worker_event_queue_capacity |
256 |
>= 1 |
Queue for progress/state events. |
| Builder/accessor | Description |
|---|---|
MeowConfig::builder() |
Creates a builder initialized with defaults. |
max_upload_concurrency(n) / max_upload_concurrency() |
Sets/reads upload concurrency. Recommended range: 1..=64. |
max_download_concurrency(n) / max_download_concurrency() |
Sets/reads download concurrency. Recommended range: 1..=64. |
http_client(client) |
Injects a custom reqwest::Client for proxy, TLS, headers, or observability. |
http_timeout(duration) / http_timeout() |
Sets/reads HTTP timeout. Typical range: 3s..=60s. |
tcp_keepalive(duration) / tcp_keepalive() |
Sets/reads TCP keepalive. Typical range: 15s..=120s. |
command_queue_capacity(n) / command_queue_capacity() |
Sets/reads control queue capacity. |
worker_event_queue_capacity(n) / worker_event_queue_capacity() |
Sets/reads worker event queue capacity. |
breakpoint_download_http(config) / breakpoint_download_http() |
Sets/reads range-download HTTP behavior. |
build() |
Validates constraints and returns MeowConfig. |
UploadPounceBuilder
| Method | Required? | Description |
|---|---|---|
UploadPounceBuilder::new(file_name, file_path, chunk_size) |
Yes | Creates a file-backed upload task. chunk_size == 0 is normalized to the SDK default. |
UploadPounceBuilder::from_bytes(file_name, bytes, chunk_size) |
Alternative | Creates an in-memory upload task. The Vec<u8> is moved into bytes::Bytes. |
with_url(url) |
Usually yes | Sets target upload URL. For direct OSS/Azure, this is the final object/blob URL. For presigned flows, it is commonly the first part URL or logical target URL. |
with_file_path(path) |
Optional | Replaces the local file source. |
with_bytes(bytes) |
Optional | Replaces the source with in-memory bytes. |
with_method(method) |
Optional | Sets HTTP method for default/custom upload requests. Default is POST. |
with_headers(headers) |
Optional | Replaces base request headers. |
with_breakpoint_upload(upload) |
Optional | Sets a per-task custom BreakpointUpload, such as Aliyun/Azure direct or presigned upload. |
with_max_chunk_retries(retries) |
Optional | Sets additional retries after the first failed chunk attempt. 0 disables chunk retry. Default is 3. |
with_max_upload_prepare_retries(retries) |
Optional | Sets additional retries after the first failed upload prepare attempt. Default is 3. |
build() |
Yes | Reads file metadata for file-backed uploads and returns PounceTask; may return std::io::Error. |
Beginner tips:
- Use a
chunk_sizebetween1 MiBand8 MiBfor common object storage workloads unless your provider requires a different size. Very small chunks increase request overhead; very large chunks reduce retry granularity. - Put provider protocol objects in
Arcand pass them towith_breakpoint_upload(...)because the executor can move transfer work across async tasks. - For restart recovery, persist enough business metadata in your own database to rebuild the same logical task later, including local path, remote URL/object key, direction, chunk size, and provider type.
DownloadPounceBuilder
| Method | Required? | Description |
|---|---|---|
DownloadPounceBuilder::new(file_name, file_path, chunk_size, url) |
Yes | Creates a range-download task. The SDK uses HEAD for prepare and GET with Range for chunks. |
with_url(url) |
Optional | Replaces the remote download URL. |
with_file_path(path) |
Optional | Replaces the local output path. |
with_headers(headers) |
Optional | Replaces base request headers for HEAD and range GET. |
with_client_file_sign(sign) |
Optional | Sets a client-defined file signature shown in progress records. Useful for database keys. |
with_breakpoint_download(download) |
Optional | Sets a per-task custom BreakpointDownload, such as Aliyun/Azure direct or presigned range download. |
with_breakpoint_download_http(config) |
Optional | Overrides per-task range download HTTP behavior. |
with_max_chunk_retries(retries) |
Optional | Sets additional retries after the first failed range chunk attempt. 0 disables chunk retry. Default is 3. |
build() |
Yes | Returns PounceTask. Validation happens during enqueue/runtime. |
Download HTTP methods are intentionally not configurable. Resumable HTTP download depends on standard HEAD and GET range behavior. If a gateway or provider needs a non-standard method, implement BreakpointDownload and inject it with with_breakpoint_download(...).
OSS upload/download developer guides
OSS and Blob workflows are provider-specific, so detailed beginner guides live in separate documents. The SDK does not persist your keys, secrets, account keys, tokens, presigned URLs, or SAS URLs in a built-in database or credential store. Some values are held in memory while executing tasks. You must provide them from your application or trusted backend, and you should avoid logging them in progress callbacks or debug listeners.
If you are deciding which provider feature to enable first, start with Provider feature flags: direct vs presigned/SAS.
| Guide | Feature flag | Example source |
|---|---|---|
| Aliyun OSS direct upload/download | aliyun-oss-direct |
examples/aliyun_oss_direct_chunk_transfer.rs |
| Aliyun OSS presigned upload/download | aliyun-oss-presigned |
examples/aliyun_oss_presigned_chunk_transfer.rs |
| Azure Blob direct upload/download | azure-blob-direct |
examples/azure_blob_direct_chunk_transfer.rs |
| Azure Blob SAS upload/download | azure-blob-sas |
examples/azure_blob_sas_chunk_transfer.rs |
Persistence and custom database integration
rusty-cat intentionally has no built-in database. This keeps the SDK small and lets you choose SQLite, PostgreSQL, Redis, a mobile database, or an existing business persistence layer. The SDK emits progress records and terminal states; your application decides how those records map to durable business state.
Recommended pattern:
- Create your own transfer table with fields such as business file ID, local path, remote URL/object key, direction, chunk size, provider, status, progress, and credential reference.
- Register per-task and/or global progress callbacks.
- In callbacks, persist
FileTransferRecordvalues or forward them to a persistence worker. Do not perform slow database writes directly on the callback path; prefer batching or sending records to your own worker queue. - On process restart, query unfinished rows and rebuild equivalent
PounceTaskvalues. - Call
try_enqueue(...)again. Provider protocols can resume from local/remote checkpoint information when the same logical task is recreated correctly.
Never persist raw cloud secrets unless your security model explicitly allows it. Prefer storing a reference to a backend-owned credential or generating fresh short-lived presigned/SAS URLs.
Examples
| Example | What it demonstrates |
|---|---|
| examples/http_local_chunk_transfer.rs | Local plain HTTP range download and custom binary upload protocol. |
| examples/aliyun_oss_direct_chunk_transfer.rs | Aliyun OSS direct upload/download with AccessKey signing. |
| examples/aliyun_oss_direct_custom_chunk_transfer.rs | Aliyun OSS direct custom chunk transfer. |
| examples/aliyun_oss_presigned_chunk_transfer.rs | Aliyun OSS presigned multipart upload and range download. |
| examples/azure_blob_direct_chunk_transfer.rs | Azure Blob direct upload/download with Shared Key. |
| examples/azure_blob_direct_custom_chunk_transfer.rs | Azure Blob direct custom chunk transfer. |
| examples/azure_blob_sas_chunk_transfer.rs | Azure Blob upload/download with SAS URLs. |
Shutdown checklist
- Keep callbacks short and non-blocking.
- Store every returned
TaskIdif you plan to pause, resume, cancel, or inspect a task. - Use
snapshot()for runtime diagnostics. - Always call
close().awaitduring shutdown. - Recreate a new
MeowClientafter a successfulclose()if you need to submit more work.