use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("dns resolution failed for '{target}': {reason}")]
Dns {
target: String,
reason: String,
},
#[error("network error for '{target}': {reason}")]
Network {
target: String,
reason: String,
},
#[error("tls handshake failed for '{target}': {message}")]
Tls {
target: String,
message: String,
},
#[error("timeout after {timeout_secs}s for '{target}' during {stage}")]
Timeout {
target: String,
stage: String,
timeout_secs: u64,
},
#[error("{provider} rate limited: retry after {retry_after_secs}s")]
RateLimit {
provider: String,
retry_after_secs: u64,
},
#[error("configuration error: {message}")]
Configuration {
message: String,
},
#[error("scanner '{scanner}' failed: {message}")]
Scanner {
scanner: &'static str,
message: String,
},
#[error("parse error: {message}")]
Parse {
message: String,
},
#[error("proxy connection to '{proxy}' failed: {message}")]
Proxy {
proxy: String,
message: String,
},
#[error("{provider} auth failed: {message}")]
Auth {
provider: String,
message: String,
},
}
impl Error {
#[must_use]
pub fn is_retryable(&self) -> bool {
matches!(
self,
Self::Network { .. } | Self::Timeout { .. } | Self::RateLimit { .. } | Self::Dns { .. }
)
}
#[must_use]
pub fn is_configuration(&self) -> bool {
matches!(self, Self::Configuration { .. } | Self::Auth { .. })
}
pub fn from_reqwest(target: &str, err: crate::reqwest::Error, timeout_secs: u64) -> Self {
if err.is_timeout() {
Self::Timeout {
target: target.to_string(),
stage: "http".to_string(),
timeout_secs,
}
} else if err.is_connect() {
Self::Network {
target: target.to_string(),
reason: err.to_string(),
}
} else {
Self::Network {
target: target.to_string(),
reason: err.to_string(),
}
}
}
}