ig_client/
error.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 12/5/25
5******************************************************************************/
6use reqwest::StatusCode;
7use std::fmt::{Display, Formatter};
8use std::{fmt, io};
9
10/// Error type for fetch operations
11#[derive(Debug)]
12pub enum FetchError {
13    /// Network error from reqwest
14    Reqwest(reqwest::Error),
15    /// Database error from sqlx
16    Sqlx(sqlx::Error),
17    /// Error during parsing
18    Parser(String),
19}
20
21impl Display for FetchError {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            FetchError::Reqwest(e) => write!(f, "network error: {e}"),
25            FetchError::Sqlx(e) => write!(f, "db error: {e}"),
26            FetchError::Parser(msg) => write!(f, "parser error: {msg}"),
27        }
28    }
29}
30
31impl std::error::Error for FetchError {}
32
33impl From<reqwest::Error> for FetchError {
34    fn from(err: reqwest::Error) -> Self {
35        FetchError::Reqwest(err)
36    }
37}
38
39impl From<sqlx::Error> for FetchError {
40    fn from(err: sqlx::Error) -> Self {
41        FetchError::Sqlx(err)
42    }
43}
44
45/// Error type for authentication operations
46#[derive(Debug)]
47pub enum AuthError {
48    /// Network error from reqwest
49    Network(reqwest::Error),
50    /// I/O error
51    Io(io::Error),
52    /// JSON serialization or deserialization error
53    Json(serde_json::Error),
54    /// Other unspecified error
55    Other(String),
56    /// Invalid credentials error
57    BadCredentials,
58    /// Unexpected HTTP status code
59    Unexpected(StatusCode),
60    /// Rate limit exceeded error
61    RateLimitExceeded,
62}
63
64impl Display for AuthError {
65    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
66        match self {
67            AuthError::Network(e) => write!(f, "network error: {e}"),
68            AuthError::Io(e) => write!(f, "io error: {e}"),
69            AuthError::Json(e) => write!(f, "json error: {e}"),
70            AuthError::Other(msg) => write!(f, "other error: {msg}"),
71            AuthError::BadCredentials => write!(f, "bad credentials"),
72            AuthError::Unexpected(s) => write!(f, "unexpected http status: {s}"),
73            AuthError::RateLimitExceeded => write!(f, "rate limit exceeded"),
74        }
75    }
76}
77
78impl std::error::Error for AuthError {}
79
80impl From<reqwest::Error> for AuthError {
81    fn from(e: reqwest::Error) -> Self {
82        AuthError::Network(e)
83    }
84}
85impl From<Box<dyn std::error::Error + Send + Sync>> for AuthError {
86    fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
87        match e.downcast::<reqwest::Error>() {
88            Ok(req) => AuthError::Network(*req),
89            Err(e) => match e.downcast::<serde_json::Error>() {
90                Ok(js) => AuthError::Json(*js),
91                Err(e) => match e.downcast::<std::io::Error>() {
92                    Ok(ioe) => AuthError::Io(*ioe),
93                    Err(other) => AuthError::Other(other.to_string()),
94                },
95            },
96        }
97    }
98}
99impl From<Box<dyn std::error::Error>> for AuthError {
100    fn from(e: Box<dyn std::error::Error>) -> Self {
101        match e.downcast::<reqwest::Error>() {
102            Ok(req) => AuthError::Network(*req),
103            Err(e) => match e.downcast::<serde_json::Error>() {
104                Ok(js) => AuthError::Json(*js),
105                Err(e) => match e.downcast::<io::Error>() {
106                    Ok(ioe) => AuthError::Io(*ioe),
107                    Err(other) => AuthError::Other(other.to_string()),
108                },
109            },
110        }
111    }
112}
113impl From<AppError> for AuthError {
114    fn from(e: AppError) -> Self {
115        match e {
116            AppError::Network(e) => AuthError::Network(e),
117            AppError::Io(e) => AuthError::Io(e),
118            AppError::Json(e) => AuthError::Json(e),
119            AppError::Unexpected(s) => AuthError::Unexpected(s),
120            _ => AuthError::Other("unknown error".to_string()),
121        }
122    }
123}
124
125/// General application error type
126#[derive(Debug)]
127pub enum AppError {
128    /// Network error from reqwest
129    Network(reqwest::Error),
130    /// I/O error
131    Io(io::Error),
132    /// JSON serialization or deserialization error
133    Json(serde_json::Error),
134    /// Unexpected HTTP status code
135    Unexpected(StatusCode),
136    /// Database error from sqlx
137    Db(sqlx::Error),
138    /// Unauthorized access error
139    Unauthorized,
140    /// OAuth token expired error (requires token refresh)
141    OAuthTokenExpired,
142    /// Resource not found error
143    NotFound,
144    /// API rate limit exceeded
145    RateLimitExceeded,
146    /// Error during serialization or deserialization
147    SerializationError(String),
148    /// WebSocket communication error
149    WebSocketError(String),
150    /// Deserialization error with details
151    Deserialization(String),
152    /// Represents an error type for invalid input.
153    ///
154    /// This enum variant is used to indicate that invalid input has been provided,
155    /// typically taking the form of a string that describes the nature of the issue.
156    ///
157    /// # Variants
158    /// * `InvalidInput(String)`
159    ///   - Contains a `String` value that provides more details about why the input
160    ///     was considered invalid, such as specific formatting issues or constraints
161    ///     that were violated.
162    ///
163    InvalidInput(String),
164    /// Generic error for cases that don't fit into other specific error categories.
165    /// Contains a descriptive error message.
166    Generic(String),
167}
168
169impl Display for AppError {
170    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
171        match self {
172            AppError::Network(e) => write!(f, "network error: {e}"),
173            AppError::Io(e) => write!(f, "io error: {e}"),
174            AppError::Json(e) => write!(f, "json error: {e}"),
175            AppError::Unexpected(s) => write!(f, "unexpected http status: {s}"),
176            AppError::Db(e) => write!(f, "db error: {e}"),
177            AppError::Unauthorized => write!(f, "unauthorized"),
178            AppError::OAuthTokenExpired => write!(f, "oauth token expired"),
179            AppError::NotFound => write!(f, "not found"),
180            AppError::RateLimitExceeded => write!(f, "rate limit exceeded"),
181            AppError::SerializationError(s) => write!(f, "serialization error: {s}"),
182            AppError::WebSocketError(s) => write!(f, "websocket error: {s}"),
183            AppError::Deserialization(s) => write!(f, "deserialization error: {s}"),
184            AppError::InvalidInput(s) => write!(f, "invalid input: {s}"),
185            AppError::Generic(s) => write!(f, "generic error: {s}"),
186        }
187    }
188}
189
190impl std::error::Error for AppError {}
191
192impl From<reqwest::Error> for AppError {
193    fn from(e: reqwest::Error) -> Self {
194        AppError::Network(e)
195    }
196}
197impl From<io::Error> for AppError {
198    fn from(e: io::Error) -> Self {
199        AppError::Io(e)
200    }
201}
202impl From<serde_json::Error> for AppError {
203    fn from(e: serde_json::Error) -> Self {
204        AppError::Json(e)
205    }
206}
207impl From<sqlx::Error> for AppError {
208    fn from(e: sqlx::Error) -> Self {
209        AppError::Db(e)
210    }
211}
212impl From<AuthError> for AppError {
213    fn from(e: AuthError) -> Self {
214        match e {
215            AuthError::Network(e) => AppError::Network(e),
216            AuthError::Io(e) => AppError::Io(e),
217            AuthError::Json(e) => AppError::Json(e),
218            AuthError::BadCredentials => AppError::Unauthorized,
219            AuthError::Unexpected(s) => AppError::Unexpected(s),
220            _ => AppError::Unexpected(StatusCode::INTERNAL_SERVER_ERROR),
221        }
222    }
223}
224
225impl From<Box<dyn std::error::Error>> for AppError {
226    fn from(e: Box<dyn std::error::Error>) -> Self {
227        match e.downcast::<reqwest::Error>() {
228            Ok(req) => AppError::Network(*req),
229            Err(e) => match e.downcast::<serde_json::Error>() {
230                Ok(js) => AppError::Json(*js),
231                Err(e) => match e.downcast::<std::io::Error>() {
232                    Ok(ioe) => AppError::Io(*ioe),
233                    Err(_) => AppError::Unexpected(StatusCode::INTERNAL_SERVER_ERROR),
234                },
235            },
236        }
237    }
238}
239impl From<String> for AppError {
240    fn from(e: String) -> Self {
241        AppError::Generic(e)
242    }
243}