Skip to main content

DownloadState

Struct DownloadState 

Source
pub struct DownloadState {
    pub config_path: PathBuf,
    /* private fields */
}
Expand description

On-disk state for an in-progress download, backing resume support.

DownloadState pairs a PartialDownloadStateInner (the persisted config, whose fields may be absent if the .fd file predates them) with the path of the .fd file and a dirty flag. It is the bridge between a saved .fd file and a fresh crate::PartialConfig handed to crate::resume: DownloadState::merge_config folds the loaded progress into the new request so a resumed download continues from the correct byte offset instead of restarting from zero.

DownloadState derefs to PartialDownloadStateInner, so the saved url, etag, last_modified, config and size are reachable directly.

The inner state is wrapped in an Arc<Mutex<PartialDownloadStateInner>> to provide a single source of truth shared between the engine loop, the internal progress reporter, and any other readers/writers.

DownloadState is cheaply Cloneable: the clone shares the same inner state and the same dirty flag (both behind Arc), so a download driver can hand a clone to a background task that performs the periodic disk persist without blocking the engine event loop.

Fields§

§config_path: PathBuf

Implementations§

Source§

impl DownloadState

Source

pub fn lock_inner(&self) -> MutexGuard<'_, PartialDownloadStateInner>

Returns a reference to the shared inner state, locked for reading. Prefer this over the previous Deref-based field access.

Source

pub fn share_inner(&self) -> Arc<Mutex<PartialDownloadStateInner>> ⓘ

Returns a clone of the shared Arc<Mutex<PartialDownloadStateInner>>, for sharing the authoritative state with other tasks (e.g. the internal progress reporter).

Source

pub fn new( url: &Url, url_info: &UrlInfo, config: &PartialConfig, config_path: &Path, ) -> Self

Build a fresh, dirty download state from the initial prefetch metadata.

url and url_info come from the prefetch step, config is the caller-provided PartialConfig, and config_path is where the .fd file will be written. The returned state is marked dirty so the first DownloadState::store persists it.

Source

pub async fn load(config_path: &Path) -> Result<Self, StateError>

Load a download state from disk.

§Errors

Returns an error if the file cannot be read or deserialized.

Source

pub async fn store(&self) -> Result<(), StateError>

Persist the download state to disk.

This serializes a snapshot of the shared inner state and atomically replaces the .fd file. It does not consult or clear the dirty flag; callers decide when to persist (typically via DownloadState::take_dirty on a fixed cadence, off the engine event loop). Safe to call from a background task because the heavy safe_replace (disk write + fsync) runs after the inner lock is released.

§Errors

Returns an error if serializing or writing the state fails.

Source

pub fn take_dirty(&self) -> bool

Consume the dirty flag (swap to clean) and report whether it was dirty.

Used by the engine loop on a fixed cadence: a true return means “a persist is due, hand the work to a background task”. Because the flag is an Arc<AtomicBool> shared with any clones, the background task and the loop observe the same flag.

Source

pub fn mark_dirty(&self)

Mark the state dirty so the next persist cycle rewrites the .fd.

Call this when a mutation lands (e.g. progress or identity changed) and when a background DownloadState::store fails and should be retried.

Source

pub fn update<F: FnOnce(&mut PartialDownloadStateInner) -> R, R>( &self, cb: F, ) -> R

Apply a mutation to the inner partial state and mark it dirty.

Any change made through cb (e.g. updating etag/last_modified or the nested config) schedules the next DownloadState::store.

Source

pub fn validate(&self, info: &UrlInfo) -> Result<(), StateError>

Check whether the server-side file is still the same one this state was saved for, so a resumed download continues from the correct offset.

The comparison requires the recorded size to match and (unless both sides are missing identity headers) the FileId (etag + last_modified) to be equal. Resumable downloads also require the server to support range requests.

§Errors
Source

pub fn get_progress(&self) -> Vec<ProgressEntry> ⓘ

Return the list of byte ranges already written to the .part file.

This is the authoritative on-disk progress. It is empty for a brand new download and grows as DownloadState::merge_progress is called.

Source

pub fn get_elapsed(&self) -> Duration

Total active download time accumulated so far, across all prior resume runs. Duration::ZERO when nothing has been recorded yet.

Source

pub fn snapshot(&self) -> ResumeInfo

产出一份只读快照,供 UI 等只读消费者读取进度元数据,而无需持有内部 MutexGuard。

与 DownloadState::lock_inner 不同,这里返回的是拥有所有权的 ResumeInfo, 调用方可以随意读取 url / size / progress / elapsed,不会触及引擎内部的并发原语。

Source

pub fn set_elapsed(&self, elapsed: Duration)

Set the total accumulated active download time (absolute, not additive).

Called by the download driver as time accrues, so the value persisted on the next DownloadState::store reflects the full session. Marks the state dirty.

Source

pub fn merge_progress(&self, range: ProgressEntry)

Merge a freshly-written byte range into the recorded progress.

The progress list is the authoritative set of on-disk ranges; new ranges are merged, de-duplicated and normalized. Marks the state dirty.

Source

pub fn merge_config(&self, partial_config: &PartialConfig)

Fold a freshly-built PartialConfig into this loaded state for resume.

This is the key bridge that preserves download progress across a resume: the ranges already recorded in self.config.downloaded_chunk are merged into partial_config first, so that even if partial_config starts from an empty progress list the resumed download keeps the already-downloaded bytes. partial_config is then layered on top via inherit_from, and the merged result replaces the stored config. Marks the state dirty.

Source

pub fn refresh_identity(&self, url: &Url, info: &UrlInfo)

Refresh the recorded state for a new download session.

Two fields are refreshed on every (re)start of a download:

  1. The durable initial URL. The URL stored in the .fd is the caller’s initial URL — the one passed to download/resume. When the caller supplies a new URL (the Some case) it takes priority and replaces any previously recorded URL, so a later resume(None) still re-resolves the resource the caller actually wants. When the URL is itself read back from the .fd (a resume(None)), this assignment is a no-op.
  2. The content identity headers (etag/last-modified/size), refreshed to the fresh server values from the current prefetch.

The redirect target (info.final_url) is deliberately never persisted: such links are usually temporary signed/CDN URLs that expire, so writing one into the .fd would poison the next resume. The download part targets info.final_url directly for range requests, which also avoids a redirect round-trip on every range request.

Source

pub fn file_id(&self) -> FileId

Reconstruct the identity of the file this state was saved for.

Returns a FileId from the stored etag / last_modified. Missing headers collapse to None, which makes DownloadState::validate treat “no identity on either side” as a match.

Source

pub fn tmp_path(&self) -> PathBuf

Path of the partial (.part) output file paired with this state.

Derived from config_path by swapping the extension to .part.

Source

pub async fn part_shortfall(&self, tmp_path: &Path) -> Option<(u64, u64)>

Measure tmp_path against the progress recorded in this state.

Returns Some((actual_size, recorded_size)) when the file is shorter than the highest recorded offset — the state claims bytes that are not on disk, so resuming from it would leave that span filled with zeros that are never fetched.

Returns None when the file is long enough, is not a regular file, or cannot be inspected; those cases surface later when the sink is built.

Trait Implementations§

Source§

impl Clone for DownloadState

Source§

fn clone(&self) -> DownloadState

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DownloadState

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more