1use std::fmt;
2use thiserror::Error;
3use std::error::Error as StdError;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum TransportErrorCode {
8 ConnectionFailed = -1000,
11 ConnectionClosed = -1001,
13 ConnectionTimeout = -1002,
15
16 MessageTooLarge = -1100,
19 InvalidMessage = -1101,
21 MessageSendFailed = -1102,
23 MessageReceiveFailed = -1103,
25
26 ProtocolError = -1200,
29 HandshakeFailed = -1201,
31
32 SendError = -1300,
35 OpenError = -1301,
37 CloseError = -1302,
39 ReceiveError = -1303,
41 AuthenticationFailed = -1202,
43
44 SessionExpired = -1310,
47 SessionInvalid = -1311,
49 SessionNotFound = -1312,
51
52 WebSocketUpgradeFailed = -1400,
55 WebSocketProtocolError = -1401,
57 WebSocketFrameError = -1402,
59
60 SseConnectionFailed = -1500,
63 SseStreamError = -1501,
65 SseParseError = -1502,
67
68 InternalError = -1900,
71 Timeout = -1901,
73 InvalidState = -1902,
75}
76
77impl fmt::Display for TransportErrorCode {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 match self {
80 Self::ConnectionFailed => write!(f, "Failed to establish connection"),
82 Self::ConnectionClosed => write!(f, "Connection was closed"),
83 Self::ConnectionTimeout => write!(f, "Connection timed out"),
84
85 Self::MessageTooLarge => write!(f, "Message exceeds size limit"),
87 Self::InvalidMessage => write!(f, "Invalid message format"),
88 Self::MessageSendFailed => write!(f, "Failed to send message"),
89 Self::MessageReceiveFailed => write!(f, "Failed to receive message"),
90
91 Self::ProtocolError => write!(f, "Protocol error"),
93 Self::HandshakeFailed => write!(f, "Handshake failed"),
94 Self::AuthenticationFailed => write!(f, "Authentication failed"),
95
96 Self::SessionExpired => write!(f, "Session has expired"),
98 Self::SessionInvalid => write!(f, "Invalid session"),
99 Self::SessionNotFound => write!(f, "Session not found"),
100
101 Self::WebSocketUpgradeFailed => write!(f, "WebSocket upgrade failed"),
103 Self::WebSocketProtocolError => write!(f, "WebSocket protocol error"),
104 Self::WebSocketFrameError => write!(f, "WebSocket frame error"),
105
106 Self::SseConnectionFailed => write!(f, "SSE connection failed"),
108 Self::SseStreamError => write!(f, "SSE stream error"),
109 Self::SseParseError => write!(f, "SSE parse error"),
110
111 Self::InternalError => write!(f, "Internal error"),
113 Self::Timeout => write!(f, "Operation timed out"),
114 Self::InvalidState => write!(f, "Invalid state"),
115 Self::SendError => write!(f, "Send error"),
116 Self::OpenError => write!(f, "Open error"),
117 Self::CloseError => write!(f, "Close error"),
118 Self::ReceiveError => write!(f, "Receive error"),
119 }
120 }
121}
122
123#[derive(Error, Debug)]
125pub enum TransportError {
126 #[error("{code}: {message}")]
127 Transport {
129 code: TransportErrorCode,
131 message: String,
133 #[source]
134 source: Option<Box<dyn StdError + Send + Sync>>,
136 },
137
138 #[error("JSON error: {0}")]
139 Json(#[from] serde_json::Error),
141
142 #[error("I/O error: {0}")]
143 Io(#[from] std::io::Error),
145
146 #[error("WebSocket error: {0}")]
147 WebSocket(#[from] tokio_tungstenite::tungstenite::Error),
149
150 #[error("HTTP error: {0}")]
151 Http(#[from] reqwest::Error),
153
154 #[error("Channel error: {0}")]
155 Channel(String),
157
158 #[error("UTF-8 error: {0}")]
159 Utf8(#[from] std::string::FromUtf8Error),
161
162 #[error("System time error: {0}")]
163 SystemTime(#[from] std::time::SystemTimeError),
165
166 #[error("JWT error: {0}")]
167 Jwt(#[from] jsonwebtoken::errors::Error),
169}
170
171impl<T> From<tokio::sync::mpsc::error::SendError<T>> for TransportError {
172 fn from(err: tokio::sync::mpsc::error::SendError<T>) -> Self {
173 Self::Channel(err.to_string())
174 }
175}
176
177impl<T> From<tokio::sync::broadcast::error::SendError<T>> for TransportError {
178 fn from(err: tokio::sync::broadcast::error::SendError<T>) -> Self {
179 Self::Channel(err.to_string())
180 }
181}
182
183impl From<actix_web::Error> for TransportError {
184 fn from(err: actix_web::Error) -> Self {
185 Self::Transport {
186 code: TransportErrorCode::InternalError,
187 message: err.to_string(),
188 source: None, }
190 }
191}
192
193impl From<tokio::task::JoinError> for TransportError {
194 fn from(err: tokio::task::JoinError) -> Self {
195 Self::Transport {
196 code: TransportErrorCode::InternalError,
197 message: err.to_string(),
198 source: None,
199 }
200 }
201}
202
203impl TransportError {
204 pub fn new(code: TransportErrorCode, message: impl Into<String>) -> Self {
206 Self::Transport {
207 code,
208 message: message.into(),
209 source: None,
210 }
211 }
212
213 pub fn with_source(
215 code: TransportErrorCode,
216 message: impl Into<String>,
217 source: impl Into<Box<dyn StdError + Send + Sync>>,
218 ) -> Self {
219 Self::Transport {
220 code,
221 message: message.into(),
222 source: Some(source.into()),
223 }
224 }
225
226 pub fn code(&self) -> Option<TransportErrorCode> {
228 match self {
229 Self::Transport { code, .. } => Some(*code),
230 _ => None,
231 }
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn test_error_codes() {
241 assert_eq!(TransportErrorCode::ConnectionFailed as i32, -1000);
242 assert_eq!(TransportErrorCode::MessageTooLarge as i32, -1100);
243 assert_eq!(TransportErrorCode::ProtocolError as i32, -1200);
244 assert_eq!(TransportErrorCode::SendError as i32, -1300);
245 assert_eq!(TransportErrorCode::SessionExpired as i32, -1310);
246 }
247
248 #[test]
249 fn test_error_display() {
250 let error = TransportError::new(TransportErrorCode::ConnectionFailed, "Failed to connect");
251 assert_eq!(error.to_string(), "Failed to establish connection: Failed to connect");
252
253 let io_error = std::io::Error::new(std::io::ErrorKind::Other, "IO error");
254 let error = TransportError::with_source(
255 TransportErrorCode::ConnectionFailed,
256 "Failed to connect",
257 Box::new(io_error) as Box<dyn StdError + Send + Sync>,
258 );
259 assert_eq!(error.to_string(), "Failed to establish connection: Failed to connect");
260 }
261
262 #[test]
263 fn test_error_code() {
264 let error = TransportError::new(TransportErrorCode::ConnectionFailed, "Failed to connect");
265 assert_eq!(error.code(), Some(TransportErrorCode::ConnectionFailed));
266
267 let io_error = std::io::Error::new(std::io::ErrorKind::Other, "JSON error");
268 let error = TransportError::Json(serde_json::Error::io(io_error));
269 assert_eq!(error.code(), None);
270 }
271}