1use thiserror::Error;
4
5#[derive(Error, Debug, Clone)]
7pub enum SdkError {
8 #[error("HTTP error: {0}")]
10 Http(String),
11
12 #[error("MQTT error: {0}")]
14 Mqtt(String),
15
16 #[error("Serialization error: {0}")]
18 Serialization(String),
19
20 #[error("Authentication error: {0}")]
22 Auth(String),
23
24 #[error("Network error: {0}")]
26 Network(String),
27
28 #[error("Configuration error: {0}")]
30 Config(String),
31
32 #[error("Not connected")]
34 NotConnected,
35
36 #[error("Timeout")]
38 Timeout,
39
40 #[error("Other error: {0}")]
42 Other(String),
43}
44
45pub type SdkResult<T> = Result<T, SdkError>;
47
48
49
50impl From<serde_json::Error> for SdkError {
51 fn from(err: serde_json::Error) -> Self {
52 SdkError::Serialization(err.to_string())
53 }
54}
55
56impl From<std::io::Error> for SdkError {
57 fn from(err: std::io::Error) -> Self {
58 SdkError::Network(err.to_string())
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum HttpErrorType {
65 Unauthorized,
67 Forbidden,
69 NotFound,
71 BadRequest,
73 ServerError,
75 NetworkError,
77 Other,
79}
80
81#[derive(Debug, Clone)]
83pub struct HttpError {
84 pub error_type: HttpErrorType,
86 pub status_code: u16,
88 pub message: String,
90 pub requires_relogin: bool,
92}
93
94impl HttpError {
95 pub fn from_error(error: &str, default_message: &str) -> Self {
97 if let Some(colon_pos) = error.find(':') {
99 let code = &error[..colon_pos];
100 let message = error[colon_pos + 1..].trim();
101
102 if code.chars().all(|c| c.is_ascii_uppercase() || c == '_') {
104 match code {
105 "USER_NOT_FOUND" | "USER_DELETED" => {
106 return Self {
107 error_type: HttpErrorType::NotFound,
108 status_code: 404,
109 message: message.to_string(),
110 requires_relogin: true,
111 };
112 }
113 "INVALID_TOKEN" | "TOKEN_EXPIRED" => {
114 return Self {
115 error_type: HttpErrorType::Unauthorized,
116 status_code: 401,
117 message: message.to_string(),
118 requires_relogin: true,
119 };
120 }
121 "UNAUTHORIZED" | "AUTH_FAILED" => {
122 return Self {
123 error_type: HttpErrorType::Unauthorized,
124 status_code: 401,
125 message: message.to_string(),
126 requires_relogin: true,
127 };
128 }
129 "FORBIDDEN" => {
130 return Self {
131 error_type: HttpErrorType::Forbidden,
132 status_code: 403,
133 message: message.to_string(),
134 requires_relogin: false,
135 };
136 }
137 _ => {}
138 }
139 }
140 }
141
142 if error.contains("HTTP 错误: 401") || error.contains("HTTP 401") {
144 Self {
145 error_type: HttpErrorType::Unauthorized,
146 status_code: 401,
147 message: "登录已过期,请重新登录".to_string(),
148 requires_relogin: true,
149 }
150 } else if error.contains("HTTP 错误: 403") || error.contains("HTTP 403") {
151 Self {
152 error_type: HttpErrorType::Forbidden,
153 status_code: 403,
154 message: "无权限访问此资源".to_string(),
155 requires_relogin: false,
156 }
157 } else if error.contains("HTTP 错误: 404") || error.contains("HTTP 404") {
158 Self {
159 error_type: HttpErrorType::NotFound,
160 status_code: 404,
161 message: "资源不存在".to_string(),
162 requires_relogin: false,
163 }
164 } else if error.contains("HTTP 错误: 400") || error.contains("HTTP 400") {
165 Self {
166 error_type: HttpErrorType::BadRequest,
167 status_code: 400,
168 message: "请求参数错误".to_string(),
169 requires_relogin: false,
170 }
171 } else if error.contains("HTTP 错误: 5") || error.contains("HTTP 50") {
172 Self {
173 error_type: HttpErrorType::ServerError,
174 status_code: 500,
175 message: "服务器错误,请稍后重试".to_string(),
176 requires_relogin: false,
177 }
178 } else {
179 Self {
180 error_type: HttpErrorType::Other,
181 status_code: 0,
182 message: if default_message.is_empty() {
183 error.to_string()
184 } else {
185 format!("{}: {}", default_message, error)
186 },
187 requires_relogin: false,
188 }
189 }
190 }
191}