use std::{fmt, io}; use crate::{ checksum::Checksum, model::{DownloadFile, PieceIndex, PieceState}, }; /// Version tag for the simplified control-file format. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct ControlFileVersion { /// Major version component. major: u16, /// Minor version component. minor: u16, } impl ControlFileVersion { /// Current text-first control-file version. pub const CURRENT: Self = Self { major: 1, minor: 0 }; /// Binary-compatible control-file version. pub const BINARY_V1: Self = Self { major: 1, minor: 1 }; /// Builds a version value from explicit major/minor parts. #[must_use] pub(crate) const fn from_parts(major: u16, minor: u16) -> Self { Self { major, minor } } /// Returns the major version component. #[must_use] pub const fn major(self) -> u16 { self.major } /// Returns the minor version component. #[must_use] pub const fn minor(self) -> u16 { self.minor } } /// Normalized control metadata stored by the Rust implementation. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ControlMetadata { /// Version of the serialized control-file format. pub version: ControlFileVersion, /// Files tracked by the control metadata. pub files: Vec, /// Whole-download or file-level checksums. pub checksums: Vec, /// Non-default piece states captured by the downloader. pub piece_states: Vec<(PieceIndex, PieceState)>, /// Number of completed bytes known at serialization time. pub completed_length: u64, /// Number of retry attempts already consumed. pub retry_count: u32, /// Last runtime error, if one was recorded. pub last_error: Option, /// Timestamp for the last runtime error in Unix milliseconds. pub last_error_at_unix_ms: Option, /// Timestamp for the last retry attempt in Unix milliseconds. pub last_retry_at_unix_ms: Option, /// Timestamp for the next scheduled retry in Unix milliseconds. pub next_retry_at_unix_ms: Option, /// Number of consecutive transfer failures, when tracked. pub consecutive_failure_count: Option, /// Number of active download segments, when tracked. pub active_segment_count: Option, /// Timestamp when resume verification last completed. pub resume_verified_at_unix_ms: Option, /// Resume-generation counter used to correlate session state. pub resume_generation: Option, } /// Text control-file representation preserved for diagnostics. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ControlFileTextModel { /// Raw control-file lines. pub lines: Vec, } /// Binary control-file representation preserved for diagnostics. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct ControlFileBinaryModel { /// Four-byte binary magic value. pub magic: [u8; 4], /// Encoded major version component. pub version_major: u16, /// Encoded minor version component. pub version_minor: u16, /// Binary payload after the header. pub payload: Vec, } /// Errors that can occur while reading or writing control files. #[derive(Debug)] pub enum ControlFileError { /// Underlying filesystem I/O error. Io(io::Error), /// Malformed or unsupported control-file contents. Parse(String), /// Upstream binary format variant is unsupported. UnsupportedBinaryCompatibility, } impl fmt::Display for ControlFileError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Io(error) => write!(f, "io error: {error}"), Self::Parse(message) => write!(f, "parse error: {message}"), Self::UnsupportedBinaryCompatibility => { write!(f, "unsupported binary .aria2 control-file format") } } } } impl std::error::Error for ControlFileError {} impl From for ControlFileError { fn from(value: io::Error) -> Self { Self::Io(value) } }