use reqwest::Error as ReqwError;
use reqwest::StatusCode;
use std::error::Error;
use std::fmt::Display;
use std::fmt::{Formatter, Result as FmtResult};
use std::result;
use std::sync::{MutexGuard, PoisonError};
use thiserror::Error;
use tokio_tungstenite::tungstenite::Error as WSError;
use url::ParseError;
#[derive(Debug, Error)]
pub enum AriError {
#[error("serde error: {0}")]
Serde(#[from] serde_json::Error),
#[error("Conversion error: {0}")]
Utf8(#[from] std::string::FromUtf8Error),
#[error("Api Error: {0}")]
Api(ApiError),
#[error("HTTP error: {raw} - body: {body}")]
Http {
raw: ReqwError,
body: String,
},
#[error("URL parse error: {0}")]
UrlParse(ParseError),
#[error("WebSocket error: {0}")]
Websocket(WSError),
#[error("Internal error: {0}")]
Internal(String),
}
impl AriError {
pub fn new(code: StatusCode, content: Option<String>) -> Self {
AriError::Api(ApiError { code, content })
}
}
pub type Result<T> = result::Result<T, AriError>;
#[derive(Debug)]
pub struct ApiError {
pub code: StatusCode,
pub content: Option<String>,
}
impl From<ParseError> for AriError {
fn from(e: ParseError) -> Self {
AriError::UrlParse(e)
}
}
impl From<WSError> for AriError {
fn from(e: WSError) -> Self {
AriError::Websocket(e)
}
}
impl<T: std::fmt::Display> From<tokio::sync::MutexGuard<'_, T>> for AriError {
fn from(e: tokio::sync::MutexGuard<'_, T>) -> Self {
AriError::Internal(format!("{}", e))
}
}
impl<T> From<PoisonError<MutexGuard<'_, T>>> for AriError {
fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
AriError::Internal(format!("{}", e))
}
}
impl Display for ApiError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match &self.content {
Some(content) => write!(f, "API error (status {}): {}", self.code, content),
None => write!(f, "API error (status {})", self.code),
}
}
}
impl Error for ApiError {}