use thiserror::Error;
#[derive(Debug, Error)]
pub enum XurlError {
#[error("HTTP Error: {0}")]
Http(String),
#[error("IO Error: {0}")]
Io(String),
#[error("Invalid Method: Invalid HTTP method: {0}")]
InvalidMethod(String),
#[error("{body}")]
Api {
status: u16,
body: String,
},
#[error("{0}")]
Validation(String),
#[error("JSON Error: {0}")]
Json(String),
#[error("Auth Error: {0}")]
Auth(String),
#[error("Token Store Error: {0}")]
TokenStore(String),
}
#[allow(dead_code)] impl XurlError {
pub fn api(status: u16, body: impl Into<String>) -> Self {
Self::Api {
status,
body: body.into(),
}
}
pub fn validation(body: impl Into<String>) -> Self {
Self::Validation(body.into())
}
pub fn auth(message: impl Into<String>) -> Self {
Self::Auth(message.into())
}
pub fn auth_with_cause(message: &str, cause: &dyn std::fmt::Display) -> Self {
Self::Auth(format!("{message} (cause: {cause})"))
}
pub fn token_store(message: impl Into<String>) -> Self {
Self::TokenStore(message.into())
}
#[must_use]
pub fn is_api(&self) -> bool {
matches!(self, Self::Api { .. })
}
#[must_use]
pub fn is_validation(&self) -> bool {
matches!(self, Self::Validation(_))
}
}
impl From<reqwest::Error> for XurlError {
fn from(err: reqwest::Error) -> Self {
Self::Http(err.to_string())
}
}
impl From<std::io::Error> for XurlError {
fn from(err: std::io::Error) -> Self {
Self::Io(err.to_string())
}
}
impl From<serde_json::Error> for XurlError {
fn from(err: serde_json::Error) -> Self {
Self::Json(err.to_string())
}
}
impl From<serde_yaml::Error> for XurlError {
fn from(err: serde_yaml::Error) -> Self {
Self::Json(err.to_string())
}
}
impl From<url::ParseError> for XurlError {
fn from(err: url::ParseError) -> Self {
Self::Http(err.to_string())
}
}
pub type Result<T> = std::result::Result<T, XurlError>;
#[allow(dead_code)] pub const EXIT_SUCCESS: i32 = 0;
#[allow(dead_code)] pub const EXIT_GENERAL_ERROR: i32 = 1;
#[allow(dead_code)] pub const EXIT_AUTH_REQUIRED: i32 = 2;
#[allow(dead_code)] pub const EXIT_RATE_LIMITED: i32 = 3;
#[allow(dead_code)] pub const EXIT_NOT_FOUND: i32 = 4;
#[allow(dead_code)] pub const EXIT_NETWORK_ERROR: i32 = 5;
#[allow(dead_code)] #[must_use]
pub fn exit_code_for_error(e: &XurlError) -> i32 {
match e {
XurlError::Auth(_) | XurlError::TokenStore(_) => EXIT_AUTH_REQUIRED,
XurlError::Api { status: 401, .. } => EXIT_AUTH_REQUIRED,
XurlError::Api { status: 429, .. } => EXIT_RATE_LIMITED,
XurlError::Api { status: 404, .. } => EXIT_NOT_FOUND,
XurlError::Http(msg) if msg.contains("401") || msg.contains("Unauthorized") => {
EXIT_AUTH_REQUIRED
}
XurlError::Http(msg) if msg.contains("429") => EXIT_RATE_LIMITED,
XurlError::Http(msg) if msg.contains("404") => EXIT_NOT_FOUND,
XurlError::Io(_) => EXIT_NETWORK_ERROR,
XurlError::Validation(_) => EXIT_GENERAL_ERROR,
_ => EXIT_GENERAL_ERROR,
}
}