use std::time::Duration;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Configuration error: {0}")]
Config(String),
#[error("JWT error: {0}")]
Jwt(String),
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
#[error("Request error: {0}")]
Request(String),
#[error("API error: {message}")]
Api {
message: String,
status: u16,
body: Option<String>,
},
#[error("Rate limited, retry after {retry_after:?}")]
RateLimited {
retry_after: Option<Duration>,
},
#[error("Parse error: {message}")]
Parse {
message: String,
body: Option<String>,
},
#[error("Authentication error: {0}")]
Auth(String),
#[error("URL error: {0}")]
Url(#[from] url::ParseError),
#[error("WebSocket error: {0}")]
WebSocket(String),
}
impl Error {
pub fn config(msg: impl Into<String>) -> Self {
Self::Config(msg.into())
}
pub fn jwt(msg: impl Into<String>) -> Self {
Self::Jwt(msg.into())
}
pub fn request(msg: impl Into<String>) -> Self {
Self::Request(msg.into())
}
pub fn api(status: u16, message: impl Into<String>, body: Option<String>) -> Self {
Self::Api {
message: message.into(),
status,
body,
}
}
pub fn parse(message: impl Into<String>, body: Option<String>) -> Self {
Self::Parse {
message: message.into(),
body,
}
}
pub fn auth(msg: impl Into<String>) -> Self {
Self::Auth(msg.into())
}
pub fn websocket(msg: impl Into<String>) -> Self {
Self::WebSocket(msg.into())
}
pub fn is_rate_limited(&self) -> bool {
matches!(self, Self::RateLimited { .. })
}
pub fn is_retryable(&self) -> bool {
match self {
Self::RateLimited { .. } => true,
Self::Http(e) => e.is_timeout() || e.is_connect(),
Self::Api { status, .. } => *status >= 500,
_ => false,
}
}
}