asterisk_ari/errors.rs
1use reqwest::Error as ReqwError;
2use reqwest::StatusCode;
3use std::error::Error;
4use std::fmt::Display;
5use std::fmt::{Formatter, Result as FmtResult};
6use std::result;
7use std::sync::{MutexGuard, PoisonError};
8use thiserror::Error;
9use tokio_tungstenite::tungstenite::Error as WSError;
10use url::ParseError;
11
12/// Represents various errors that can occur in the ARI client.
13#[derive(Debug, Error)]
14pub enum AriError {
15 /// Error during JSON serialization/deserialization.
16 #[error("serde error: {0}")]
17 Serde(#[from] serde_json::Error),
18 /// Error converting a byte array to a UTF-8 string.
19 #[error("Conversion error: {0}")]
20 Utf8(#[from] std::string::FromUtf8Error),
21 /// API-specific error.
22 #[error("Api Error: {0}")]
23 Api(ApiError),
24 /// General HTTP error.
25 #[error("HTTP error: {raw} - body: {body}")]
26 Http {
27 /// The HTTP error.
28 raw: ReqwError,
29 /// The response body.
30 body: String,
31 },
32 /// URL parsing error.
33 #[error("URL parse error: {0}")]
34 UrlParse(ParseError),
35 /// WebSocket error.
36 #[error("WebSocket error: {0}")]
37 Websocket(WSError),
38 /// Internal error.
39 #[error("Internal error: {0}")]
40 Internal(String),
41}
42
43impl AriError {
44 /// Creates a new `AriError` with the given status code and optional content.
45 ///
46 /// # Arguments
47 ///
48 /// * `code` - The HTTP status code.
49 /// * `content` - Optional content associated with the error.
50 ///
51 /// # Returns
52 ///
53 /// A new instance of `AriError`.
54 pub fn new(code: StatusCode, content: Option<String>) -> Self {
55 AriError::Api(ApiError { code, content })
56 }
57}
58
59/// Result type alias for operations that can return an `AriError`.
60pub type Result<T> = result::Result<T, AriError>;
61
62/// Represents an API-specific error.
63#[derive(Debug)]
64pub struct ApiError {
65 /// The HTTP status code associated with the error.
66 pub code: StatusCode,
67 /// Optional content associated with the error.
68 pub content: Option<String>,
69}
70
71impl From<ParseError> for AriError {
72 /// Converts a `ParseError` into an `AriError`.
73 ///
74 /// # Arguments
75 ///
76 /// * `e` - The `ParseError` to convert.
77 ///
78 /// # Returns
79 ///
80 /// An `AriError` representing the URL parsing error.
81 fn from(e: ParseError) -> Self {
82 AriError::UrlParse(e)
83 }
84}
85
86impl From<WSError> for AriError {
87 /// Converts a `WSError` into an `AriError`.
88 ///
89 /// # Arguments
90 ///
91 /// * `e` - The `WSError` to convert.
92 ///
93 /// # Returns
94 ///
95 /// An `AriError` representing the WebSocket error.
96 fn from(e: WSError) -> Self {
97 AriError::Websocket(e)
98 }
99}
100
101impl<T: std::fmt::Display> From<tokio::sync::MutexGuard<'_, T>> for AriError {
102 /// Converts a `tokio::sync::MutexGuard<'_, T>` into an `AriError`.
103 ///
104 /// # Arguments
105 ///
106 /// * `e` - The `tokio::sync::MutexGuard<'_, T>` to convert.
107 ///
108 /// # Returns
109 ///
110 /// An `AriError` representing the poisoned mutex error.
111 fn from(e: tokio::sync::MutexGuard<'_, T>) -> Self {
112 AriError::Internal(format!("{}", e))
113 }
114}
115
116impl<T> From<PoisonError<MutexGuard<'_, T>>> for AriError {
117 /// Converts a `PoisonError<MutexGuard<'_, T>>` into an `AriError`.
118 ///
119 /// # Arguments
120 ///
121 /// * `e` - The `PoisonError<MutexGuard<'_, T>>` to convert.
122 ///
123 /// # Returns
124 ///
125 /// An `AriError` representing the poisoned mutex error.
126 fn from(e: PoisonError<MutexGuard<'_, T>>) -> Self {
127 AriError::Internal(format!("{}", e))
128 }
129}
130
131impl Display for ApiError {
132 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
133 match &self.content {
134 Some(content) => write!(f, "API error (status {}): {}", self.code, content),
135 None => write!(f, "API error (status {})", self.code),
136 }
137 }
138}
139
140impl Error for ApiError {}