use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("HTTP request failed: {0}")]
Http(#[from] reqwest::Error),
#[error("Request timeout after {duration_ms}ms")]
Timeout {
duration_ms: u64,
},
#[error("All CDN hosts exhausted for {resource}")]
CdnExhausted {
resource: String,
},
#[error("Invalid CDN host: {host}")]
InvalidHost {
host: String,
},
#[error("Invalid content hash: {hash}")]
InvalidHash {
hash: String,
},
#[error("Content not found: {hash}")]
ContentNotFound {
hash: String,
},
#[error("Content verification failed for {hash}: expected {expected}, got {actual}")]
VerificationFailed {
hash: String,
expected: String,
actual: String,
},
#[error("Invalid response from CDN: {reason}")]
InvalidResponse {
reason: String,
},
#[error("Rate limit exceeded: retry after {retry_after_secs} seconds")]
RateLimited {
retry_after_secs: u64,
},
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid URL: {url}")]
InvalidUrl {
url: String,
},
#[error("Content size mismatch: expected {expected} bytes, got {actual} bytes")]
SizeMismatch {
expected: u64,
actual: u64,
},
#[error("CDN server does not support partial content (range requests)")]
PartialContentNotSupported,
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn cdn_exhausted(resource: impl Into<String>) -> Self {
Self::CdnExhausted {
resource: resource.into(),
}
}
pub fn invalid_host(host: impl Into<String>) -> Self {
Self::InvalidHost { host: host.into() }
}
pub fn invalid_hash(hash: impl Into<String>) -> Self {
Self::InvalidHash { hash: hash.into() }
}
pub fn content_not_found(hash: impl Into<String>) -> Self {
Self::ContentNotFound { hash: hash.into() }
}
pub fn verification_failed(
hash: impl Into<String>,
expected: impl Into<String>,
actual: impl Into<String>,
) -> Self {
Self::VerificationFailed {
hash: hash.into(),
expected: expected.into(),
actual: actual.into(),
}
}
pub fn invalid_response(reason: impl Into<String>) -> Self {
Self::InvalidResponse {
reason: reason.into(),
}
}
pub fn rate_limited(retry_after_secs: u64) -> Self {
Self::RateLimited { retry_after_secs }
}
pub fn invalid_url(url: impl Into<String>) -> Self {
Self::InvalidUrl { url: url.into() }
}
pub fn size_mismatch(expected: u64, actual: u64) -> Self {
Self::SizeMismatch { expected, actual }
}
}