pub trait BreakpointDownload: Send + Sync {
// Provided methods
fn resume_identity(
&self,
_task: &TransferTask,
) -> Result<Option<Vec<u8>>, MeowError> { ... }
fn total_size_hint(&self, _task: &TransferTask) -> Option<u64> { ... }
fn supports_parallel_parts(&self) -> bool { ... }
fn head_url(&self, task: &TransferTask) -> String { ... }
fn range_url(&self, task: &TransferTask) -> String { ... }
fn merge_head_headers(
&self,
_ctx: DownloadHeadCtx<'_>,
) -> Result<(), MeowError> { ... }
fn merge_range_get_headers(
&self,
ctx: DownloadRangeGetCtx<'_>,
) -> Result<(), MeowError> { ... }
fn total_size_from_head(
&self,
headers: &HeaderMap,
) -> Result<u64, MeowError> { ... }
}Expand description
Custom breakpoint download protocol.
Implementors control HEAD/range-GET URL and header semantics, and parse remote total size from HEAD response headers. Executor handles HTTP sending, response validation, file writes, retries, progress, pause/resume, and state.
§Typical call flow
- Prepare stage: executor sends HEAD after
head_urlandmerge_head_headers. - Chunk stage: executor sends range GET after
merge_range_get_headers.
§Executor integration contract
- Default implementation uses task-level
range_acceptasAcceptheader. range_valueis generated by executor and should usually be preserved.DownloadRangeGetCtx::basemay already contain an executor-ownedIf-Matchcopied from the prepared strong ETag. Implementations must preserve that header exactly. Signing protocols must calculate authorization only after all protocol-specific headers have been merged.total_size_from_headfailure terminates prepare stage.
§Examples
use rusty_cat::api::{
BreakpointDownload, DownloadHeadCtx, DownloadRangeGetCtx, MeowError, StandardRangeDownload,
};
#[derive(Default)]
struct MyDownloadProtocol;
impl BreakpointDownload for MyDownloadProtocol {
fn merge_head_headers(&self, _ctx: DownloadHeadCtx<'_>) -> Result<(), MeowError> {
Ok(())
}
fn merge_range_get_headers(&self, ctx: DownloadRangeGetCtx<'_>) -> Result<(), MeowError> {
// Reuse default behavior or customize as needed.
StandardRangeDownload.merge_range_get_headers(ctx)
}
}Provided Methods§
Sourcefn resume_identity(
&self,
_task: &TransferTask,
) -> Result<Option<Vec<u8>>, MeowError>
fn resume_identity( &self, _task: &TransferTask, ) -> Result<Option<Vec<u8>>, MeowError>
Returns stable, protocol-specific bytes that bind a persisted download checkpoint to the effective range-request representation.
The returned bytes are combined with the canonical range URL and the
strong ETag, then persisted only as a domain-separated SHA-256 digest.
They are never logged or written to the sidecar verbatim. Implementors
should include every invariant header or principal/tenant selector that
can change response bytes, while excluding per-part values such as
Range and short-lived signature timestamps.
The conservative default is None, which disables cross-process
checkpoint reuse for a custom protocol. The current transfer still
validates every range response against the strong ETag. Return Some
only when the context is complete and stable across credential refresh.
§Errors
Return MeowError when stable identity context cannot be constructed.
Return Ok(None) when the protocol fundamentally cannot provide one.
Sourcefn total_size_hint(&self, _task: &TransferTask) -> Option<u64>
fn total_size_hint(&self, _task: &TransferTask) -> Option<u64>
Returns known remote total size and skips the HEAD prepare request when present.
This is useful for presigned URL downloads where a GET URL cannot be reused as HEAD, or where the application server already returned object metadata together with the presigned range URL.
Sourcefn supports_parallel_parts(&self) -> bool
fn supports_parallel_parts(&self) -> bool
Whether this download protocol is safe to fetch out of order, so the
executor may run up to max_parts_in_flight range GETs of one file
concurrently and write them at absolute offsets.
Default false keeps every protocol strictly serial. Plain HTTP Range
(RFC 7233) is order-agnostic, so crate::api::StandardRangeDownload
overrides this to true. A custom protocol should return true only if
each range_url/merge_range_get_headers result is independent of any
other chunk’s completion.
Sourcefn head_url(&self, task: &TransferTask) -> String
fn head_url(&self, task: &TransferTask) -> String
Returns full URL for HEAD request.
Default implementation returns TransferTask::url.
§Panics
Implementations should avoid panicking and prefer returning recoverable errors from later merge/parse methods.
§Examples
use rusty_cat::api::{BreakpointDownload, StandardRangeDownload, TransferTask};
fn head_url_for(task: &TransferTask) -> String {
BreakpointDownload::head_url(&StandardRangeDownload, task)
}Sourcefn range_url(&self, task: &TransferTask) -> String
fn range_url(&self, task: &TransferTask) -> String
Returns full URL for range GET requests.
Default implementation returns TransferTask::url. Presigned
protocols can override this when HEAD and GET use different URLs.
Sourcefn merge_head_headers(&self, _ctx: DownloadHeadCtx<'_>) -> Result<(), MeowError>
fn merge_head_headers(&self, _ctx: DownloadHeadCtx<'_>) -> Result<(), MeowError>
Merges protocol-specific headers before sending HEAD request.
Default implementation is no-op.
§Errors
Return MeowError when required HEAD headers cannot be generated
(for example, signing failure or invalid header values).
§Examples
use rusty_cat::api::DownloadHeadCtx;
fn inspect_head_ctx(ctx: &DownloadHeadCtx<'_>) {
let _ = ctx.task.file_name();
let _ = ctx.base.len();
}Sourcefn merge_range_get_headers(
&self,
ctx: DownloadRangeGetCtx<'_>,
) -> Result<(), MeowError>
fn merge_range_get_headers( &self, ctx: DownloadRangeGetCtx<'_>, ) -> Result<(), MeowError>
Merges protocol-specific headers before range GET request.
The executor may pre-populate ctx.base with an If-Match header that
binds every range to the remote generation observed during preparation.
Implementations must not remove, replace, or append another value to that
header. The executor validates this contract before network I/O, allowing
authentication implementations to sign the final conditional headers.
Default implementation sets:
Range: <range_value>Accept: <task.range_accept or application/octet-stream>
§Errors
Return MeowError when protocol-specific range headers cannot be
generated.
§Examples
use rusty_cat::api::DownloadRangeGetCtx;
fn inspect_range_ctx(ctx: &DownloadRangeGetCtx<'_>) {
let _ = (ctx.range_value, ctx.task.url());
}Sourcefn total_size_from_head(&self, headers: &HeaderMap) -> Result<u64, MeowError>
fn total_size_from_head(&self, headers: &HeaderMap) -> Result<u64, MeowError>
Parses total resource size from successful HEAD response headers.
Default implementation requires valid Content-Length > 0.
§Errors
Returns MissingOrInvalidContentLengthFromHead when total size cannot
be parsed from response headers.
§Examples
use reqwest::header::{HeaderMap, HeaderValue, CONTENT_LENGTH};
use rusty_cat::api::{BreakpointDownload, StandardRangeDownload};
let mut headers = HeaderMap::new();
headers.insert(CONTENT_LENGTH, HeaderValue::from_static("1024"));
let total = StandardRangeDownload.total_size_from_head(&headers)?;
assert_eq!(total, 1024);Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".