#[derive(Debug, thiserror::Error)]
pub enum FetchError {
#[error("network error: {0}")]
Network(String),
#[error("request timed out after {0:?}")]
Timeout(std::time::Duration),
#[error("HTTP {status}: {body}")]
StatusCode {
status: u16,
body: String,
},
#[error("serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("circuit breaker is open; requests temporarily blocked")]
CircuitOpen,
#[error("middleware error: {0}")]
Middleware(String),
#[error("build error: {0}")]
BuildError(String),
#[error("header error: {0}")]
HeaderError(String),
}
impl From<reqwest::Error> for FetchError {
fn from(err: reqwest::Error) -> Self {
if err.is_timeout() {
FetchError::Timeout(std::time::Duration::ZERO)
} else {
FetchError::Network(err.to_string())
}
}
}
impl From<reqwest_middleware::Error> for FetchError {
fn from(err: reqwest_middleware::Error) -> Self {
match err {
reqwest_middleware::Error::Middleware(e) => {
let e = match e.downcast::<FetchError>() {
Ok(fetch_err) => return fetch_err,
Err(e) => e,
};
let e = match e.downcast::<reqwest_retry::RetryError>() {
Ok(retry_err) => {
let inner = match retry_err {
reqwest_retry::RetryError::Error(inner) => inner,
reqwest_retry::RetryError::WithRetries { err, .. } => err,
};
return FetchError::from(inner);
}
Err(e) => e,
};
FetchError::Middleware(e.to_string())
}
reqwest_middleware::Error::Reqwest(e) => FetchError::from(e),
}
}
}