Skip to main content

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::io;
8
9/// Error type for fetch operations
10#[derive(Debug, thiserror::Error)]
11pub enum FetchError {
12    /// Network error from reqwest
13    #[error("network error: {0}")]
14    Reqwest(#[from] reqwest::Error),
15    /// Database error from sqlx
16    #[error("db error: {0}")]
17    Sqlx(#[from] sqlx::Error),
18    /// Error during parsing
19    #[error("parser error: {0}")]
20    Parser(String),
21}
22
23/// Error type for authentication operations
24#[derive(Debug, thiserror::Error)]
25pub enum AuthError {
26    /// Network error from reqwest
27    #[error("network error: {0}")]
28    Network(#[from] reqwest::Error),
29    /// I/O error
30    #[error("io error: {0}")]
31    Io(#[from] io::Error),
32    /// JSON serialization or deserialization error
33    #[error("json error: {0}")]
34    Json(#[from] serde_json::Error),
35    /// Other unspecified error
36    #[error("other error: {0}")]
37    Other(String),
38    /// Invalid credentials error
39    #[error("bad credentials")]
40    BadCredentials,
41    /// Unexpected HTTP status code
42    #[error("unexpected http status: {0}")]
43    Unexpected(StatusCode),
44    /// Rate limit exceeded error
45    #[error("rate limit exceeded")]
46    RateLimitExceeded,
47}
48
49impl From<Box<dyn std::error::Error + Send + Sync>> for AuthError {
50    #[cold]
51    fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
52        match e.downcast::<reqwest::Error>() {
53            Ok(req) => AuthError::Network(*req),
54            Err(e) => match e.downcast::<serde_json::Error>() {
55                Ok(js) => AuthError::Json(*js),
56                Err(e) => match e.downcast::<std::io::Error>() {
57                    Ok(ioe) => AuthError::Io(*ioe),
58                    Err(other) => AuthError::Other(other.to_string()),
59                },
60            },
61        }
62    }
63}
64
65impl From<Box<dyn std::error::Error>> for AuthError {
66    #[cold]
67    fn from(e: Box<dyn std::error::Error>) -> Self {
68        match e.downcast::<reqwest::Error>() {
69            Ok(req) => AuthError::Network(*req),
70            Err(e) => match e.downcast::<serde_json::Error>() {
71                Ok(js) => AuthError::Json(*js),
72                Err(e) => match e.downcast::<io::Error>() {
73                    Ok(ioe) => AuthError::Io(*ioe),
74                    Err(other) => AuthError::Other(other.to_string()),
75                },
76            },
77        }
78    }
79}
80
81impl From<AppError> for AuthError {
82    #[cold]
83    fn from(e: AppError) -> Self {
84        match e {
85            AppError::Network(e) => AuthError::Network(e),
86            AppError::Io(e) => AuthError::Io(e),
87            AppError::Json(e) => AuthError::Json(e),
88            AppError::Unexpected(s) => AuthError::Unexpected(s),
89            _ => AuthError::Other(e.to_string()),
90        }
91    }
92}
93
94/// General application error type
95#[derive(Debug, thiserror::Error)]
96pub enum AppError {
97    /// Network error from reqwest
98    #[error("network error: {0}")]
99    Network(#[from] reqwest::Error),
100    /// I/O error
101    #[error("io error: {0}")]
102    Io(#[from] io::Error),
103    /// JSON serialization or deserialization error
104    #[error("json error: {0}")]
105    Json(#[from] serde_json::Error),
106    /// Unexpected HTTP status code
107    #[error("unexpected http status: {0}")]
108    Unexpected(StatusCode),
109    /// Database error from sqlx
110    #[error("db error: {0}")]
111    Db(#[from] sqlx::Error),
112    /// Unauthorized access error
113    #[error("unauthorized")]
114    Unauthorized,
115    /// OAuth token expired error (requires token refresh)
116    #[error("oauth token expired")]
117    OAuthTokenExpired,
118    /// Resource not found error
119    #[error("not found")]
120    NotFound,
121    /// API rate limit exceeded
122    #[error("rate limit exceeded")]
123    RateLimitExceeded,
124    /// Error during serialization or deserialization
125    #[error("serialization error: {0}")]
126    SerializationError(String),
127    /// WebSocket communication error
128    #[error("websocket error: {0}")]
129    WebSocketError(String),
130    /// Deserialization error with details
131    #[error("deserialization error: {0}")]
132    Deserialization(String),
133    /// Invalid input error with a description of the constraint violated
134    #[error("invalid input: {0}")]
135    InvalidInput(String),
136    /// Generic error for cases that don't fit other categories
137    #[error("generic error: {0}")]
138    Generic(String),
139}
140
141impl From<AuthError> for AppError {
142    #[cold]
143    fn from(e: AuthError) -> Self {
144        match e {
145            AuthError::Network(e) => AppError::Network(e),
146            AuthError::Io(e) => AppError::Io(e),
147            AuthError::Json(e) => AppError::Json(e),
148            AuthError::BadCredentials => AppError::Unauthorized,
149            AuthError::Unexpected(s) => AppError::Unexpected(s),
150            _ => AppError::Unexpected(StatusCode::INTERNAL_SERVER_ERROR),
151        }
152    }
153}
154
155impl From<Box<dyn std::error::Error>> for AppError {
156    #[cold]
157    fn from(e: Box<dyn std::error::Error>) -> Self {
158        match e.downcast::<reqwest::Error>() {
159            Ok(req) => AppError::Network(*req),
160            Err(e) => match e.downcast::<serde_json::Error>() {
161                Ok(js) => AppError::Json(*js),
162                Err(e) => match e.downcast::<std::io::Error>() {
163                    Ok(ioe) => AppError::Io(*ioe),
164                    Err(_) => AppError::Unexpected(StatusCode::INTERNAL_SERVER_ERROR),
165                },
166            },
167        }
168    }
169}
170
171impl From<String> for AppError {
172    #[cold]
173    fn from(e: String) -> Self {
174        AppError::Generic(e)
175    }
176}
177
178impl From<lightstreamer_rs::utils::LightstreamerError> for AppError {
179    #[cold]
180    fn from(e: lightstreamer_rs::utils::LightstreamerError) -> Self {
181        AppError::WebSocketError(e.to_string())
182    }
183}