use std::time::Duration;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("{reason}")]
InvalidUrl {
url: String,
reason: String,
},
#[error("page load timed out after {}s", timeout.as_secs())]
Timeout {
url: String,
timeout: Duration,
},
#[error("address not allowed: {0}")]
AddressNotAllowed(String),
#[error("engine error: {0}")]
Engine(String),
#[error("JavaScript evaluation failed: {0}")]
JavaScript(String),
#[error("screenshot capture failed: {0}")]
Screenshot(String),
#[error(transparent)]
Extract(#[from] crate::extract::ExtractError),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("invalid glob pattern: {0}")]
InvalidGlob(#[from] globset::Error),
}
impl Error {
#[must_use]
pub fn is_timeout(&self) -> bool {
matches!(self, Self::Timeout { .. })
}
#[must_use]
pub fn is_network(&self) -> bool {
matches!(self, Self::Timeout { .. } | Self::AddressNotAllowed(_))
}
#[must_use]
pub fn url(&self) -> Option<&str> {
match self {
Self::InvalidUrl { url, .. } | Self::Timeout { url, .. } | Self::AddressNotAllowed(url) => Some(url),
_ => None,
}
}
}
#[allow(clippy::used_underscore_items)]
const _: () = {
fn _assert<T: Send + Sync>() {}
fn _check() {
_assert::<Error>();
}
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn timeout_is_timeout() {
let err = Error::Timeout {
url: "https://example.com".into(),
timeout: Duration::from_secs(30),
};
assert!(err.is_timeout());
assert!(err.is_network());
assert_eq!(err.url(), Some("https://example.com"));
}
#[test]
fn address_not_allowed_is_network() {
let err = Error::AddressNotAllowed("127.0.0.1".into());
assert!(!err.is_timeout());
assert!(err.is_network());
assert_eq!(err.url(), Some("127.0.0.1"));
}
#[test]
fn invalid_url_has_url() {
let err = Error::InvalidUrl {
url: "bad://url".into(),
reason: "scheme not allowed".into(),
};
assert!(!err.is_timeout());
assert!(!err.is_network());
assert_eq!(err.url(), Some("bad://url"));
}
#[test]
fn engine_error_has_no_url() {
let err = Error::Engine("crashed".into());
assert!(!err.is_timeout());
assert!(err.url().is_none());
}
}