1use thiserror::Error;
2
3#[derive(Error, Debug)]
5pub enum ConnectError {
6 #[error("HTTP request failed: {0}")]
7 Reqwest(String),
8
9 #[error("Failed to parse JSON: {0}")]
10 Json(String),
11
12 #[error("Failed to decode Base64: {0}")]
13 Base64(String),
14
15 #[error("JWT processing failed: {0}")]
16 Jwt(String),
17
18 #[error("System time error: {0}")]
19 Time(String),
20
21 #[error("Missing token or unexpected response: {0}")]
22 Token(String),
23
24 #[error("Provider API Error ({code}): {message}")]
25 ProviderApiError { code: String, message: String },
26
27 #[error("Provider specific error: {0}")]
28 Provider(String),
29
30 #[error("Invalid CSRF state: {0}")]
31 InvalidState(String),
32}
33
34impl From<reqwest::Error> for ConnectError {
35 fn from(err: reqwest::Error) -> Self {
36 ConnectError::Reqwest(err.to_string())
37 }
38}
39
40impl From<serde_json::Error> for ConnectError {
41 fn from(err: serde_json::Error) -> Self {
42 ConnectError::Json(err.to_string())
43 }
44}
45
46impl From<base64::DecodeError> for ConnectError {
47 fn from(err: base64::DecodeError) -> Self {
48 ConnectError::Base64(err.to_string())
49 }
50}
51
52impl From<jsonwebtoken::errors::Error> for ConnectError {
53 fn from(err: jsonwebtoken::errors::Error) -> Self {
54 ConnectError::Jwt(err.to_string())
55 }
56}
57
58impl From<std::time::SystemTimeError> for ConnectError {
59 fn from(err: std::time::SystemTimeError) -> Self {
60 ConnectError::Time(err.to_string())
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn test_reqwest_error_conversion() {
70 let err = reqwest::Client::new()
71 .get("htt p://invalid")
72 .build()
73 .unwrap_err();
74 let connect_err: ConnectError = err.into();
75 match connect_err {
76 ConnectError::Reqwest(_) => (),
77 _ => panic!("Expected ConnectError::Reqwest"),
78 }
79 }
80
81 #[test]
82 fn test_serde_json_error_conversion() {
83 let err: serde_json::Error =
84 serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
85 let connect_err: ConnectError = err.into();
86 match connect_err {
87 ConnectError::Json(_) => (),
88 _ => panic!("Expected ConnectError::Json"),
89 }
90 }
91
92 #[test]
93 fn test_base64_error_conversion() {
94 use base64::Engine;
95 let err = base64::engine::general_purpose::STANDARD
96 .decode("invalid!base64")
97 .unwrap_err();
98 let connect_err: ConnectError = err.into();
99 match connect_err {
100 ConnectError::Base64(_) => (),
101 _ => panic!("Expected ConnectError::Base64"),
102 }
103 }
104
105 #[test]
106 fn test_jwt_error_conversion() {
107 let err = jsonwebtoken::decode_header("invalid.jwt.header").unwrap_err();
108 let connect_err: ConnectError = err.into();
109 match connect_err {
110 ConnectError::Jwt(_) => (),
111 _ => panic!("Expected ConnectError::Jwt"),
112 }
113 }
114
115 #[test]
116 fn test_time_error_conversion() {
117 let err = std::time::SystemTime::UNIX_EPOCH
118 .duration_since(std::time::SystemTime::now())
119 .unwrap_err();
120 let connect_err: ConnectError = err.into();
121 match connect_err {
122 ConnectError::Time(_) => (),
123 _ => panic!("Expected ConnectError::Time"),
124 }
125 }
126}