1use serde::Serialize;
27use thiserror::Error;
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
31#[repr(i32)]
32pub enum ErrorCode {
33 Success = 1,
35 Failed = 0,
37 NotLogin = -1,
39 UserNotFound = -2,
41 UserDisabled = -3,
43 Forbidden = 403,
45 NotFound = 404,
47 ValidateFailed = 422,
49 PayloadTooLarge = 413,
51 DbError = 500,
53}
54
55impl ErrorCode {
56 pub fn as_i32(self) -> i32 {
58 self as i32
59 }
60
61 pub fn http_status(self) -> u16 {
63 match self {
64 ErrorCode::Success => 200,
65 ErrorCode::Failed => 200,
66 ErrorCode::NotLogin => 401,
67 ErrorCode::UserNotFound => 401,
68 ErrorCode::UserDisabled => 403,
69 ErrorCode::Forbidden => 403,
70 ErrorCode::NotFound => 404,
71 ErrorCode::ValidateFailed => 422,
72 ErrorCode::PayloadTooLarge => 413,
73 ErrorCode::DbError => 500,
74 }
75 }
76}
77
78impl From<i32> for ErrorCode {
79 fn from(code: i32) -> Self {
80 match code {
81 1 => ErrorCode::Success,
82 0 => ErrorCode::Failed,
83 -1 => ErrorCode::NotLogin,
84 -2 => ErrorCode::UserNotFound,
85 -3 => ErrorCode::UserDisabled,
86 403 => ErrorCode::Forbidden,
87 404 => ErrorCode::NotFound,
88 422 => ErrorCode::ValidateFailed,
89 413 => ErrorCode::PayloadTooLarge,
90 500 => ErrorCode::DbError,
91 _ => ErrorCode::Failed,
92 }
93 }
94}
95
96#[derive(Debug, Clone, Error)]
110#[error("[{code}] {msg}")]
111pub struct BaseException {
112 pub code: i32,
114 pub msg: String,
116 pub message_key: Option<String>,
121}
122
123impl BaseException {
124 pub fn new(code: ErrorCode, msg: impl Into<String>) -> Self {
126 Self {
127 code: code.as_i32(),
128 msg: msg.into(),
129 message_key: None,
130 }
131 }
132
133 pub fn with_message_key(mut self, key: impl Into<String>) -> Self {
135 self.message_key = Some(key.into());
136 self
137 }
138
139 pub fn message_key(&self) -> Option<&str> {
141 self.message_key.as_deref()
142 }
143
144 pub fn not_login(msg: impl Into<String>) -> Self {
146 Self::new(ErrorCode::NotLogin, msg)
147 }
148
149 pub fn user_not_found(msg: impl Into<String>) -> Self {
151 Self::new(ErrorCode::UserNotFound, msg)
152 }
153
154 pub fn user_disabled(msg: impl Into<String>) -> Self {
156 Self::new(ErrorCode::UserDisabled, msg)
157 }
158
159 pub fn failed(msg: impl Into<String>) -> Self {
161 Self::new(ErrorCode::Failed, msg)
162 }
163
164 pub fn forbidden(msg: impl Into<String>) -> Self {
166 Self::new(ErrorCode::Forbidden, msg)
167 }
168
169 pub fn not_found(msg: impl Into<String>) -> Self {
171 Self::new(ErrorCode::NotFound, msg)
172 }
173
174 pub fn validate_failed(msg: impl Into<String>) -> Self {
176 Self::new(ErrorCode::ValidateFailed, msg)
177 }
178
179 pub fn db_error(msg: impl Into<String>) -> Self {
181 Self::new(ErrorCode::DbError, msg)
182 }
183
184 pub fn payload_too_large(msg: impl Into<String>) -> Self {
186 Self::new(ErrorCode::PayloadTooLarge, msg)
187 }
188
189 pub fn to_json(&self) -> serde_json::Value {
191 serde_json::json!({
192 "code": self.code,
193 "msg": self.msg,
194 "data": {}
195 })
196 }
197}
198
199impl Default for BaseException {
200 fn default() -> Self {
201 Self {
202 code: ErrorCode::Failed.as_i32(),
203 msg: "invalid parameters".to_string(),
204 message_key: None,
205 }
206 }
207}
208
209#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
219 fn test_error_code_values() {
220 assert_eq!(ErrorCode::Success.as_i32(), 1);
221 assert_eq!(ErrorCode::Failed.as_i32(), 0);
222 assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
223 assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
224 assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
225 assert_eq!(ErrorCode::Forbidden.as_i32(), 403);
226 assert_eq!(ErrorCode::NotFound.as_i32(), 404);
227 assert_eq!(ErrorCode::ValidateFailed.as_i32(), 422);
228 assert_eq!(ErrorCode::DbError.as_i32(), 500);
229 }
230
231 #[test]
233 fn test_from_i32() {
234 assert_eq!(ErrorCode::from(1), ErrorCode::Success);
235 assert_eq!(ErrorCode::from(0), ErrorCode::Failed);
236 assert_eq!(ErrorCode::from(-1), ErrorCode::NotLogin);
237 assert_eq!(ErrorCode::from(-2), ErrorCode::UserNotFound);
238 assert_eq!(ErrorCode::from(-3), ErrorCode::UserDisabled);
239 assert_eq!(ErrorCode::from(999), ErrorCode::Failed); }
241
242 #[test]
244 fn test_http_status() {
245 assert_eq!(ErrorCode::Success.http_status(), 200);
246 assert_eq!(ErrorCode::Failed.http_status(), 200);
247 assert_eq!(ErrorCode::NotLogin.http_status(), 401);
248 assert_eq!(ErrorCode::UserNotFound.http_status(), 401);
249 assert_eq!(ErrorCode::UserDisabled.http_status(), 403);
250 assert_eq!(ErrorCode::Forbidden.http_status(), 403);
251 assert_eq!(ErrorCode::NotFound.http_status(), 404);
252 assert_eq!(ErrorCode::ValidateFailed.http_status(), 422);
253 assert_eq!(ErrorCode::DbError.http_status(), 500);
254 }
255
256 #[test]
258 fn test_default() {
259 let ex = BaseException::default();
260 assert_eq!(ex.code, 0);
261 assert_eq!(ex.msg, "invalid parameters");
262 }
263
264 #[test]
266 fn test_not_login() {
267 let ex = BaseException::not_login("not_login");
268 assert_eq!(ex.code, -1);
269 assert_eq!(ex.msg, "not_login");
270 }
271
272 #[test]
274 fn test_user_not_found() {
275 let ex = BaseException::user_not_found("没有找到用户信息");
276 assert_eq!(ex.code, -2);
277 assert_eq!(ex.msg, "没有找到用户信息");
278 }
279
280 #[test]
282 fn test_user_disabled() {
283 let ex = BaseException::user_disabled("您已离职,无权使用本系统!");
284 assert_eq!(ex.code, -3);
285 assert_eq!(ex.msg, "您已离职,无权使用本系统!");
286 }
287
288 #[test]
290 fn test_failed() {
291 let ex = BaseException::failed("操作失败");
292 assert_eq!(ex.code, 0);
293 assert_eq!(ex.msg, "操作失败");
294 }
295
296 #[test]
298 fn test_to_json() {
299 let ex = BaseException::not_login("not_login");
300 let json = ex.to_json();
301 assert_eq!(json["code"], -1);
302 assert_eq!(json["msg"], "not_login");
303 assert_eq!(json["data"], serde_json::json!({}));
304 }
305
306 #[test]
308 fn test_display() {
309 let ex = BaseException::not_login("not_login");
310 assert_eq!(format!("{}", ex), "[-1] not_login");
311 }
312
313 #[test]
316 fn test_php_error_codes_coverage() {
317 assert_eq!(ErrorCode::Success.as_i32(), 1);
319 assert_eq!(ErrorCode::Failed.as_i32(), 0);
321 assert_eq!(ErrorCode::NotLogin.as_i32(), -1);
323 assert_eq!(ErrorCode::UserNotFound.as_i32(), -2);
325 assert_eq!(ErrorCode::UserDisabled.as_i32(), -3);
327 }
328}