Skip to main content

BreakpointDownload

Trait BreakpointDownload 

Source
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

  1. Prepare stage: executor sends HEAD after head_url and merge_head_headers.
  2. Chunk stage: executor sends range GET after merge_range_get_headers.

§Executor integration contract

  • Default implementation uses task-level range_accept as Accept header.
  • range_value is generated by executor and should usually be preserved.
  • DownloadRangeGetCtx::base may already contain an executor-owned If-Match copied 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_head failure 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§

Source

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.

Source

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.

Source

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.

Source

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)
}
Source

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.

Source

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();
}
Source

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());
}
Source

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".

Implementors§