1use super::traits::ErrorSeverity;
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum ErrorCode {
15 Success = 0,
18
19 BadRequest = 400,
22 Unauthorized = 401,
24 Forbidden = 403,
26 NotFound = 404,
28 MethodNotAllowed = 405,
30 Conflict = 409,
32 TooManyRequests = 429,
34
35 InternalServerError = 500,
38 BadGateway = 502,
40 ServiceUnavailable = 503,
42 GatewayTimeout = 504,
44
45 AppTicketInvalid = 10012,
48 AppStatusException = 10013,
50 AppPermissionDenied = 19001,
52 AccessTokenInvalid = 99991671,
54 AccessTokenFormatInvalid = 99991661,
56 AppAccessTokenInvalid = 99991664,
58 TenantAccessTokenInvalid = 99991663,
60 SsoTokenInvalid = 99991670,
62 PermissionMissing = 99991672,
64 AccessTokenNoPermission = 99991676,
66 AccessTokenExpiredV2 = 99991677,
68
69 UserSessionInvalid = 99991641,
72 UserSessionNotFound = 99991642,
74 UserSessionTimeout = 99991645,
76 UserIdentityInvalid = 99991669,
78 UserTypeNotSupportedV2 = 99991674,
80 UserIdentityMismatch = 99991675,
82 UserIdInvalid = 99992351,
84 OpenIdInvalid = 99992352,
86 UnionIdInvalid = 99992353,
88
89 AppNotInstalled = 10003,
92 UserNotFound = 60001,
94 UserStatusException = 60002,
96 DepartmentNotFound = 60003,
98 ChatNotFound = 70001,
100 ChatTypeNotSupported = 70002,
102 MessageNotFound = 80001,
104 MessageTypeNotSupported = 80002,
106 FileNotFound = 90001,
108 FileSizeExceeded = 90002,
110 FileTypeNotSupported = 90003,
112
113 CalendarNotFound = 110001,
116 EventNotFound = 110002,
118 EventConflict = 110003,
120 DocumentNotFound = 120001,
122 DocumentPermissionDenied = 120002,
124 DocumentLocked = 120003,
126 SheetNotFound = 120011,
128 TableNotFound = 120021,
130
131 NetworkTimeout = 999001,
134 NetworkConnectionFailed = 999002,
136 DnsResolutionFailed = 999003,
138 SslCertificateError = 999004,
140 ConnectionRefused = 999005,
142
143 SerializationError = 999010,
146 DataFormatError = 999011,
148 EncodingError = 999012,
150
151 AuthenticationFailed = 999020,
154 PermissionDenied = 999021,
156 TokenExpired = 999022,
158 InvalidSignature = 999023,
160
161 ValidationError = 999030,
164 MissingRequiredParameter = 999031,
166 InvalidParameterFormat = 999032,
168 ParameterOutOfRange = 999033,
170
171 BusinessError = 999040,
174 OperationNotSupported = 999041,
176 ResourceConflict = 999042,
178
179 InternalError = 999050,
182 ConfigurationError = 999051,
184 ResourceExhausted = 999052,
186
187 RateLimitExceeded = 999060,
190
191 CacheMiss = 999070,
194 CacheServiceUnavailable = 999071,
196
197 SecurityPolicyViolation = 999080,
200 AccessDenied = 999081,
202
203 Unknown = 999999,
206}
207
208impl ErrorCode {
209 pub fn from_code(code: i32) -> Self {
211 match code {
212 c if (200..=299).contains(&c) => Self::Success,
213 0 => Self::Success,
214
215 400 => Self::BadRequest,
217 401 => Self::Unauthorized,
218 403 => Self::Forbidden,
219 404 => Self::NotFound,
220 405 => Self::MethodNotAllowed,
221 409 => Self::Conflict,
222 429 => Self::TooManyRequests,
223
224 500 => Self::InternalServerError,
226 502 => Self::BadGateway,
227 503 => Self::ServiceUnavailable,
228 504 => Self::GatewayTimeout,
229
230 10003 => Self::AppNotInstalled,
232 10012 => Self::AppTicketInvalid,
233 10013 => Self::AppStatusException,
234 19001 => Self::AppPermissionDenied,
235 60001 => Self::UserNotFound,
236 60002 => Self::UserStatusException,
237 60003 => Self::DepartmentNotFound,
238 70001 => Self::ChatNotFound,
239 70002 => Self::ChatTypeNotSupported,
240 80001 => Self::MessageNotFound,
241 80002 => Self::MessageTypeNotSupported,
242 90001 => Self::FileNotFound,
243 90002 => Self::FileSizeExceeded,
244 90003 => Self::FileTypeNotSupported,
245 110001 => Self::CalendarNotFound,
246 110002 => Self::EventNotFound,
247 110003 => Self::EventConflict,
248 120001 => Self::DocumentNotFound,
249 120002 => Self::DocumentPermissionDenied,
250 120003 => Self::DocumentLocked,
251 120011 => Self::SheetNotFound,
252 120021 => Self::TableNotFound,
253 99991661 => Self::AccessTokenFormatInvalid,
254 99991671 => Self::AccessTokenInvalid,
255 99991664 => Self::AppAccessTokenInvalid,
256 99991663 => Self::TenantAccessTokenInvalid,
257 99991670 => Self::SsoTokenInvalid,
258 99991672 => Self::PermissionMissing,
259 99991676 => Self::AccessTokenNoPermission,
260 99991677 => Self::AccessTokenExpiredV2,
261 99991641 => Self::UserSessionInvalid,
262 99991642 => Self::UserSessionNotFound,
263 99991645 => Self::UserSessionTimeout,
264 99991669 => Self::UserIdentityInvalid,
265 99991674 => Self::UserTypeNotSupportedV2,
266 99991675 => Self::UserIdentityMismatch,
267 99992351 => Self::UserIdInvalid,
268 99992352 => Self::OpenIdInvalid,
269 99992353 => Self::UnionIdInvalid,
270
271 999001 => Self::NetworkTimeout,
273 999002 => Self::NetworkConnectionFailed,
274 999003 => Self::DnsResolutionFailed,
275 999004 => Self::SslCertificateError,
276 999005 => Self::ConnectionRefused,
277
278 999010 => Self::SerializationError,
280 999011 => Self::DataFormatError,
281 999012 => Self::EncodingError,
282
283 999020 => Self::AuthenticationFailed,
285 999021 => Self::PermissionDenied,
286 999022 => Self::TokenExpired,
287 999023 => Self::InvalidSignature,
288
289 999030 => Self::ValidationError,
291 999031 => Self::MissingRequiredParameter,
292 999032 => Self::InvalidParameterFormat,
293 999033 => Self::ParameterOutOfRange,
294
295 999040 => Self::BusinessError,
297 999041 => Self::OperationNotSupported,
298 999042 => Self::ResourceConflict,
299
300 999050 => Self::InternalError,
302 999051 => Self::ConfigurationError,
303 999052 => Self::ResourceExhausted,
304
305 999060 => Self::RateLimitExceeded,
307
308 999070 => Self::CacheMiss,
310 999071 => Self::CacheServiceUnavailable,
311
312 999080 => Self::SecurityPolicyViolation,
314 999081 => Self::AccessDenied,
315
316 _ => Self::Unknown,
317 }
318 }
319
320 pub fn as_code(&self) -> i32 {
322 *self as i32
323 }
324
325 pub fn description(&self) -> &'static str {
327 match self {
328 Self::Success => "操作成功",
329
330 Self::BadRequest => "请求参数错误",
332 Self::Unauthorized => "未认证",
333 Self::Forbidden => "禁止访问",
334 Self::NotFound => "资源不存在",
335 Self::MethodNotAllowed => "方法不允许",
336 Self::Conflict => "请求冲突",
337 Self::TooManyRequests => "请求频率过高",
338
339 Self::InternalServerError => "内部服务器错误",
341 Self::BadGateway => "网关错误",
342 Self::ServiceUnavailable => "服务不可用",
343 Self::GatewayTimeout => "网关超时",
344
345 Self::AppNotInstalled => "应用未安装",
347 Self::AppTicketInvalid => "应用票据无效",
348 Self::AppStatusException => "应用状态异常",
349 Self::AppPermissionDenied => "应用权限不足",
350 Self::UserNotFound => "用户不存在",
351 Self::UserStatusException => "用户状态异常",
352 Self::DepartmentNotFound => "部门不存在",
353 Self::ChatNotFound => "群组不存在",
354 Self::ChatTypeNotSupported => "群组类型不支持",
355 Self::MessageNotFound => "消息不存在",
356 Self::MessageTypeNotSupported => "消息类型不支持",
357 Self::FileNotFound => "文件不存在",
358 Self::FileSizeExceeded => "文件大小超限",
359 Self::FileTypeNotSupported => "文件类型不支持",
360 Self::CalendarNotFound => "日历不存在",
361 Self::EventNotFound => "日程不存在",
362 Self::EventConflict => "日程冲突",
363 Self::DocumentNotFound => "文档不存在",
364 Self::DocumentPermissionDenied => "文档权限不足",
365 Self::DocumentLocked => "文档已锁定",
366 Self::SheetNotFound => "工作表不存在",
367 Self::TableNotFound => "表格不存在",
368 Self::AccessTokenFormatInvalid => "访问令牌格式错误",
369 Self::AccessTokenInvalid => "访问令牌无效",
370 Self::AppAccessTokenInvalid => "应用访问令牌无效",
371 Self::TenantAccessTokenInvalid => "租户访问令牌无效",
372 Self::SsoTokenInvalid => "SSO 访问令牌无效",
373 Self::PermissionMissing => "缺少所需权限",
374 Self::AccessTokenNoPermission => "访问令牌权限不足",
375 Self::AccessTokenExpiredV2 => "访问令牌已过期",
376 Self::UserSessionInvalid => "用户会话已失效",
377 Self::UserSessionNotFound => "用户会话不存在",
378 Self::UserSessionTimeout => "用户会话超时",
379 Self::UserIdentityInvalid => "用户身份解析失败",
380 Self::UserTypeNotSupportedV2 => "用户类型不支持",
381 Self::UserIdentityMismatch => "用户身份不匹配",
382 Self::UserIdInvalid => "用户ID非法",
383 Self::OpenIdInvalid => "OpenID 非法",
384 Self::UnionIdInvalid => "UnionID 非法",
385
386 Self::NetworkTimeout => "网络连接超时",
388 Self::NetworkConnectionFailed => "网络连接失败",
389 Self::DnsResolutionFailed => "DNS解析失败",
390 Self::SslCertificateError => "SSL证书错误",
391 Self::ConnectionRefused => "连接被拒绝",
392
393 Self::SerializationError => "JSON解析错误",
395 Self::DataFormatError => "数据格式错误",
396 Self::EncodingError => "编码错误",
397
398 Self::AuthenticationFailed => "身份验证失败",
400 Self::PermissionDenied => "权限被拒绝",
401 Self::TokenExpired => "令牌已过期",
402 Self::InvalidSignature => "无效签名",
403
404 Self::ValidationError => "参数验证失败",
406 Self::MissingRequiredParameter => "缺少必需参数",
407 Self::InvalidParameterFormat => "参数格式错误",
408 Self::ParameterOutOfRange => "参数值超出范围",
409
410 Self::BusinessError => "业务逻辑错误",
412 Self::OperationNotSupported => "操作不被支持",
413 Self::ResourceConflict => "资源状态冲突",
414
415 Self::InternalError => "系统内部错误",
417 Self::ConfigurationError => "配置错误",
418 Self::ResourceExhausted => "资源耗尽",
419
420 Self::RateLimitExceeded => "请求频率限制",
422
423 Self::CacheMiss => "缓存未命中",
425 Self::CacheServiceUnavailable => "缓存服务不可用",
426
427 Self::SecurityPolicyViolation => "安全策略违规",
429 Self::AccessDenied => "访问被拒绝",
430
431 Self::Unknown => "未知错误",
432 }
433 }
434
435 pub fn detailed_description(&self) -> &'static str {
437 match self {
438 Self::Success => "请求已成功处理",
439
440 Self::BadRequest => "请求参数格式错误或缺少必需参数,请检查请求内容",
441 Self::Unauthorized => "身份验证失败,请检查访问令牌是否有效",
442 Self::Forbidden => "权限不足,无法访问请求的资源",
443 Self::NotFound => "请求的资源不存在或已被删除",
444 Self::MethodNotAllowed => "当前API不支持此HTTP方法",
445 Self::Conflict => "请求与当前资源状态冲突,请检查资源状态",
446 Self::TooManyRequests => "请求频率超过限制,请降低请求频率后重试",
447
448 Self::InternalServerError => "服务器内部错误,请稍后重试或联系技术支持",
449 Self::BadGateway => "网关服务器错误,请检查网络连接或稍后重试",
450 Self::ServiceUnavailable => "服务暂时不可用,请稍后重试",
451 Self::GatewayTimeout => "网关超时,请稍后重试",
452
453 Self::AppNotInstalled => "应用未安装到当前企业,请在飞书管理后台安装应用",
454 Self::AppTicketInvalid => "应用票据已失效,SDK会自动重新申请",
455 Self::AppStatusException => "应用状态异常,请检查应用是否正常启用",
456 Self::AppPermissionDenied => "应用缺少执行此操作的权限,请在开发者后台配置相应权限",
457 Self::UserNotFound => "指定的用户不存在,请检查用户ID是否正确",
458 Self::UserStatusException => "用户状态异常,可能已被禁用或删除",
459 Self::DepartmentNotFound => "指定的部门不存在,请检查部门ID是否正确",
460 Self::ChatNotFound => "指定的群组不存在或机器人未加入该群组",
461 Self::ChatTypeNotSupported => "当前群组类型不支持此操作",
462 Self::MessageNotFound => "指定的消息不存在或已被删除",
463 Self::MessageTypeNotSupported => "不支持的消息类型",
464 Self::FileNotFound => "指定的文件不存在或已被删除",
465 Self::FileSizeExceeded => "文件大小超出限制,请压缩后重试",
466 Self::FileTypeNotSupported => "不支持的文件类型",
467 Self::CalendarNotFound => "指定的日历不存在",
468 Self::EventNotFound => "指定的日程不存在或已被删除",
469 Self::EventConflict => "日程时间冲突,请选择其他时间",
470 Self::DocumentNotFound => "指定的文档不存在或已被删除",
471 Self::DocumentPermissionDenied => "文档权限不足,请联系文档所有者授权",
472 Self::DocumentLocked => "文档已被其他用户锁定,请稍后再试",
473 Self::SheetNotFound => "指定的工作表不存在",
474 Self::TableNotFound => "指定的表格不存在",
475 Self::AccessTokenFormatInvalid => "访问令牌格式或内容无效,请重新获取或检查传参",
476 Self::AccessTokenInvalid => "用户访问令牌无效或失效,需要重新获取用户授权",
477 Self::AppAccessTokenInvalid => "应用访问令牌无效,请检查应用ID和密钥配置",
478 Self::TenantAccessTokenInvalid => "租户访问令牌无效,请检查应用是否正确安装到企业",
479 Self::SsoTokenInvalid => "SSO 访问令牌无效,请重新登录或检查 SSO 配置",
480 Self::PermissionMissing => "缺少所需权限,请在开发者后台开通对应权限范围",
481 Self::AccessTokenNoPermission => "访问令牌权限不足,请重新授权所需 scope",
482 Self::AccessTokenExpiredV2 => "访问令牌已过期,需要重新获取",
483 Self::UserSessionInvalid => "用户会话失效,请重新登录或刷新会话",
484 Self::UserSessionNotFound => "未找到有效用户会话,请重新登录",
485 Self::UserSessionTimeout => "用户会话已超时,请重新登录",
486 Self::UserIdentityInvalid => "用户身份解析失败,请检查传入的身份标识",
487 Self::UserTypeNotSupportedV2 => "当前用户类型不支持该操作",
488 Self::UserIdentityMismatch => "用户身份不匹配,请检查 user_id/open_id 组合",
489 Self::UserIdInvalid => "用户ID非法,请检查参数格式",
490 Self::OpenIdInvalid => "OpenID 非法,请检查参数格式",
491 Self::UnionIdInvalid => "UnionID 非法,请检查参数格式",
492
493 Self::NetworkTimeout => "网络请求超时,请检查网络连接或增加超时时间",
494 Self::NetworkConnectionFailed => "网络连接失败,请检查网络设置和服务器状态",
495 Self::DnsResolutionFailed => "DNS解析失败,请检查域名设置或网络配置",
496 Self::SslCertificateError => "SSL证书验证失败,请检查证书配置或系统时间",
497 Self::ConnectionRefused => "连接被拒绝,请检查服务器状态和防火墙设置",
498
499 Self::SerializationError => "JSON序列化或反序列化失败,请检查数据格式",
500 Self::DataFormatError => "数据格式不正确,请检查输入数据结构",
501 Self::EncodingError => "数据编码错误,请检查字符编码设置",
502
503 Self::AuthenticationFailed => "身份验证失败,请检查凭据是否正确",
504 Self::PermissionDenied => "权限不足,无法执行此操作",
505 Self::TokenExpired => "访问令牌已过期,需要重新获取",
506 Self::InvalidSignature => "签名验证失败,请检查签名算法和密钥",
507
508 Self::ValidationError => "输入数据验证失败,请检查数据格式和内容",
509 Self::MissingRequiredParameter => "缺少必需的参数,请检查请求参数完整性",
510 Self::InvalidParameterFormat => "参数格式不正确,请按照要求格式提供参数",
511 Self::ParameterOutOfRange => "参数值超出允许范围,请检查参数值是否有效",
512
513 Self::BusinessError => "业务逻辑处理失败,请检查操作条件和业务规则",
514 Self::OperationNotSupported => "当前操作不被支持,请检查API文档或使用替代方法",
515 Self::ResourceConflict => "资源状态冲突,请检查资源当前状态或等待后重试",
516
517 Self::InternalError => "系统内部错误,请联系技术支持",
518 Self::ConfigurationError => "系统配置错误,请检查配置文件或环境变量",
519 Self::ResourceExhausted => "系统资源耗尽,请稍后重试或增加资源配额",
520
521 Self::RateLimitExceeded => "请求频率超过限制,请降低请求频率后重试",
522
523 Self::CacheMiss => "缓存中未找到数据,将从数据源获取",
524 Self::CacheServiceUnavailable => "缓存服务不可用,将直接访问数据源",
525
526 Self::SecurityPolicyViolation => "操作违反安全策略,请检查操作权限和安全设置",
527 Self::AccessDenied => "访问被拒绝,请检查访问权限和身份验证",
528
529 Self::Unknown => "未知错误,请联系技术支持获取帮助",
530 }
531 }
532
533 pub fn is_success(&self) -> bool {
535 matches!(self, Self::Success)
536 }
537
538 pub fn is_client_error(&self) -> bool {
540 let code = *self as i32;
541 (400..=499).contains(&code) && code != 429
542 }
543
544 pub fn is_server_error(&self) -> bool {
546 let code = *self as i32;
547 (500..=599).contains(&code)
548 }
549
550 pub fn is_network_error(&self) -> bool {
552 matches!(
553 self,
554 Self::NetworkTimeout
555 | Self::NetworkConnectionFailed
556 | Self::DnsResolutionFailed
557 | Self::SslCertificateError
558 | Self::ConnectionRefused
559 )
560 }
561
562 pub fn is_auth_error(&self) -> bool {
564 matches!(
565 self,
566 Self::Unauthorized
567 | Self::AccessTokenFormatInvalid
568 | Self::AccessTokenInvalid
569 | Self::AppAccessTokenInvalid
570 | Self::TenantAccessTokenInvalid
571 | Self::SsoTokenInvalid
572 | Self::AuthenticationFailed
573 | Self::TokenExpired
574 | Self::AccessTokenExpiredV2
575 | Self::InvalidSignature
576 | Self::UserSessionInvalid
577 | Self::UserSessionNotFound
578 | Self::UserSessionTimeout
579 | Self::UserIdentityInvalid
580 | Self::UserTypeNotSupportedV2
581 | Self::UserIdentityMismatch
582 | Self::UserIdInvalid
583 | Self::OpenIdInvalid
584 | Self::UnionIdInvalid
585 )
586 }
587
588 pub fn is_permission_error(&self) -> bool {
590 matches!(
591 self,
592 Self::Forbidden
593 | Self::AppPermissionDenied
594 | Self::DocumentPermissionDenied
595 | Self::PermissionDenied
596 | Self::PermissionMissing
597 | Self::AccessTokenNoPermission
598 | Self::AccessDenied
599 )
600 }
601
602 pub fn is_retryable(&self) -> bool {
604 match self {
605 Self::Success => false,
606 Self::TooManyRequests => true,
607 Self::InternalServerError => true,
608 Self::BadGateway => true,
609 Self::ServiceUnavailable => true,
610 Self::GatewayTimeout => true,
611 Self::NetworkTimeout => true,
612 Self::NetworkConnectionFailed => true,
613 Self::ConnectionRefused => true,
614 Self::CacheServiceUnavailable => true,
615 Self::RateLimitExceeded => true,
616 _ => false,
617 }
618 }
619
620 pub fn suggested_retry_delay(&self) -> Option<u64> {
622 match self {
623 Self::TooManyRequests => Some(60),
624 Self::InternalServerError => Some(5),
625 Self::BadGateway => Some(3),
626 Self::ServiceUnavailable => Some(10),
627 Self::GatewayTimeout => Some(5),
628 Self::NetworkTimeout => Some(3),
629 Self::NetworkConnectionFailed => Some(5),
630 Self::ConnectionRefused => Some(10),
631 Self::RateLimitExceeded => Some(30),
632 _ => None,
633 }
634 }
635
636 pub fn http_status(&self) -> Option<u16> {
638 let code = *self as i32;
639 if (100..=599).contains(&code) {
640 Some(code as u16)
641 } else {
642 None
643 }
644 }
645
646 pub fn from_http_status(status: u16) -> Self {
648 Self::from_code(status as i32)
649 }
650
651 pub fn from_feishu_code(code: i32) -> Option<Self> {
653 match code {
654 99991661 => Some(Self::AccessTokenFormatInvalid),
655 99991663 => Some(Self::TenantAccessTokenInvalid),
656 99991664 => Some(Self::AppAccessTokenInvalid),
657 99991670 => Some(Self::SsoTokenInvalid),
658 99991671 => Some(Self::AccessTokenInvalid),
659 99991672 => Some(Self::PermissionMissing),
660 99991676 => Some(Self::AccessTokenNoPermission),
661 99991677 => Some(Self::AccessTokenExpiredV2),
662 99991641 => Some(Self::UserSessionInvalid),
663 99991642 => Some(Self::UserSessionNotFound),
664 99991645 => Some(Self::UserSessionTimeout),
665 99991669 => Some(Self::UserIdentityInvalid),
666 99991674 => Some(Self::UserTypeNotSupportedV2),
667 99991675 => Some(Self::UserIdentityMismatch),
668 99992351 => Some(Self::UserIdInvalid),
669 99992352 => Some(Self::OpenIdInvalid),
670 99992353 => Some(Self::UnionIdInvalid),
671 _ => None,
672 }
673 }
674
675 pub fn for_error_type(error_type: &str) -> Self {
681 match error_type {
682 "Network" | "network" => Self::NetworkConnectionFailed,
684
685 "Authentication" | "authentication" => Self::AuthenticationFailed,
687 "TokenExpired" | "token_expired" => Self::TokenExpired,
688
689 "Permission" | "permission" => Self::PermissionDenied,
691 "Forbidden" | "forbidden" => Self::Forbidden,
692
693 "Validation" | "validation" => Self::ValidationError,
695 "ApiError" | "api_error" => Self::BusinessError,
696
697 "Configuration" | "configuration" => Self::ConfigurationError,
699
700 "Serialization" | "serialization" => Self::SerializationError,
702
703 "Internal" | "internal" => Self::InternalError,
705 "Unknown" | "unknown" => Self::Unknown,
706
707 "BadRequest" | "bad_request" => Self::BadRequest,
709 "Unauthorized" | "unauthorized" => Self::Unauthorized,
710 "NotFound" | "not_found" => Self::NotFound,
711 "Conflict" | "conflict" => Self::Conflict,
712 "TooManyRequests" | "too_many_requests" => Self::TooManyRequests,
713 "InternalServerError" | "internal_server_error" => Self::InternalServerError,
714 "ServiceUnavailable" | "service_unavailable" => Self::ServiceUnavailable,
715
716 _ => Self::Unknown,
718 }
719 }
720
721 pub fn network() -> Self {
723 Self::NetworkConnectionFailed
724 }
725
726 pub fn authentication() -> Self {
728 Self::AuthenticationFailed
729 }
730
731 pub fn permission() -> Self {
733 Self::PermissionDenied
734 }
735
736 pub fn validation() -> Self {
738 Self::ValidationError
739 }
740
741 pub fn configuration() -> Self {
743 Self::ConfigurationError
744 }
745
746 pub fn internal() -> Self {
748 Self::InternalError
749 }
750
751 pub fn serialization() -> Self {
753 Self::SerializationError
754 }
755
756 pub fn unknown() -> Self {
758 Self::Unknown
759 }
760
761 pub fn from_message(message: &str) -> Self {
765 let msg_lower = message.to_lowercase();
766
767 if msg_lower.contains("network")
769 || msg_lower.contains("connection")
770 || msg_lower.contains("timeout")
771 || msg_lower.contains("dns")
772 {
773 return Self::NetworkConnectionFailed;
774 }
775
776 if msg_lower.contains("auth")
778 || msg_lower.contains("token")
779 || msg_lower.contains("unauthorized")
780 {
781 return Self::AuthenticationFailed;
782 }
783
784 if msg_lower.contains("permission")
786 || msg_lower.contains("forbidden")
787 || msg_lower.contains("access denied")
788 {
789 return Self::PermissionDenied;
790 }
791
792 if msg_lower.contains("invalid")
794 || msg_lower.contains("validation")
795 || msg_lower.contains("parameter")
796 {
797 return Self::ValidationError;
798 }
799
800 if msg_lower.contains("config") || msg_lower.contains("setting") {
802 return Self::ConfigurationError;
803 }
804
805 if msg_lower.contains("json")
807 || msg_lower.contains("serialize")
808 || msg_lower.contains("parse")
809 {
810 return Self::SerializationError;
811 }
812
813 if msg_lower.contains("not found") || msg_lower.contains("missing") {
815 return Self::NotFound;
816 }
817
818 if msg_lower.contains("unavailable") || msg_lower.contains("service") {
820 return Self::ServiceUnavailable;
821 }
822
823 Self::Unknown
824 }
825
826 pub fn should_retry(&self, attempt: u32) -> bool {
830 if !self.is_retryable() {
831 return false;
832 }
833
834 match self {
835 Self::TooManyRequests | Self::RateLimitExceeded => attempt < 5,
837 Self::NetworkTimeout | Self::NetworkConnectionFailed => attempt < 3,
838 Self::InternalServerError | Self::BadGateway | Self::GatewayTimeout => attempt < 2,
839 _ => attempt < 3,
840 }
841 }
842
843 pub fn exponential_backoff_delay(&self, attempt: u32) -> Option<u64> {
847 if !self.should_retry(attempt) {
848 return None;
849 }
850
851 let base_delay = self.suggested_retry_delay().unwrap_or(1);
852 let max_delay = match self {
853 Self::TooManyRequests => 300, Self::RateLimitExceeded => 180, _ => 60, };
857
858 let delay = base_delay * 2u64.pow(attempt.saturating_sub(1));
860 Some(delay.min(max_delay))
861 }
862
863 pub fn severity(&self) -> ErrorSeverity {
865 match self {
866 Self::Success => ErrorSeverity::Info,
867
868 Self::BadRequest
870 | Self::Forbidden
871 | Self::NotFound
872 | Self::MethodNotAllowed
873 | Self::Conflict
874 | Self::ValidationError
875 | Self::MissingRequiredParameter
876 | Self::InvalidParameterFormat
877 | Self::ParameterOutOfRange => ErrorSeverity::Warning,
878
879 Self::Unauthorized
881 | Self::AccessTokenInvalid
882 | Self::AppAccessTokenInvalid
883 | Self::TenantAccessTokenInvalid
884 | Self::AuthenticationFailed
885 | Self::TokenExpired
886 | Self::PermissionDenied
887 | Self::AccessDenied => ErrorSeverity::Error,
888
889 Self::InternalServerError
891 | Self::BadGateway
892 | Self::ServiceUnavailable
893 | Self::GatewayTimeout
894 | Self::NetworkTimeout
895 | Self::NetworkConnectionFailed
896 | Self::DnsResolutionFailed
897 | Self::SslCertificateError
898 | Self::ConnectionRefused
899 | Self::InternalError
900 | Self::ConfigurationError
901 | Self::ResourceExhausted => ErrorSeverity::Critical,
902
903 _ => ErrorSeverity::Error,
905 }
906 }
907
908 pub fn recovery_suggestion(&self) -> &'static str {
910 match self {
911 Self::BadRequest => "请检查请求参数是否正确",
912 Self::Unauthorized => "请重新进行身份验证",
913 Self::Forbidden => "请联系管理员获取相应权限",
914 Self::NotFound => "请确认资源是否存在",
915 Self::TooManyRequests => "请降低请求频率后重试",
916 Self::NetworkConnectionFailed => "请检查网络连接",
917 Self::TokenExpired => "请重新获取访问令牌",
918 Self::ServiceUnavailable => "服务暂时不可用,请稍后重试",
919 Self::InternalServerError => "系统内部错误,请联系技术支持",
920 Self::ValidationError => "请检查输入参数格式",
921 Self::ConfigurationError => "请检查系统配置",
922 Self::Unknown => "发生未知错误,请联系技术支持",
923 _ => "请稍后重试,如问题持续请联系技术支持",
924 }
925 }
926
927 pub fn is_user_error(&self) -> bool {
929 matches!(
930 self,
931 Self::BadRequest
932 | Self::Unauthorized
933 | Self::Forbidden
934 | Self::ValidationError
935 | Self::MissingRequiredParameter
936 | Self::InvalidParameterFormat
937 | Self::ParameterOutOfRange
938 | Self::AccessTokenInvalid
939 | Self::TokenExpired
940 )
941 }
942
943 pub fn is_system_error(&self) -> bool {
945 matches!(
946 self,
947 Self::InternalServerError
948 | Self::BadGateway
949 | Self::ServiceUnavailable
950 | Self::GatewayTimeout
951 | Self::NetworkTimeout
952 | Self::NetworkConnectionFailed
953 | Self::DnsResolutionFailed
954 | Self::SslCertificateError
955 | Self::ConnectionRefused
956 | Self::InternalError
957 | Self::ConfigurationError
958 | Self::ResourceExhausted
959 )
960 }
961
962 pub fn log_level(&self) -> &'static str {
964 match self.severity() {
965 ErrorSeverity::Info => "info",
966 ErrorSeverity::Warning => "warn",
967 ErrorSeverity::Error => "error",
968 ErrorSeverity::Critical => "error",
969 }
970 }
971}
972
973impl fmt::Display for ErrorCode {
974 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
975 write!(f, "{} ({})", self.description(), self.as_code())
976 }
977}
978
979#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
981pub enum ErrorCategory {
982 Success,
984 Authentication,
986 Permission,
988 Parameter,
990 Resource,
992 Server,
994 Network,
996 Business,
998 System,
1000 RateLimit,
1002 Other,
1004}
1005
1006impl ErrorCode {
1007 pub fn category(&self) -> ErrorCategory {
1009 match self {
1010 Self::Success => ErrorCategory::Success,
1011
1012 Self::Unauthorized
1014 | Self::AppTicketInvalid
1015 | Self::AccessTokenFormatInvalid
1016 | Self::AccessTokenInvalid
1017 | Self::AppAccessTokenInvalid
1018 | Self::TenantAccessTokenInvalid
1019 | Self::SsoTokenInvalid
1020 | Self::AuthenticationFailed
1021 | Self::TokenExpired
1022 | Self::AccessTokenExpiredV2
1023 | Self::InvalidSignature
1024 | Self::UserSessionInvalid
1025 | Self::UserSessionNotFound
1026 | Self::UserSessionTimeout
1027 | Self::UserIdentityInvalid
1028 | Self::UserTypeNotSupportedV2
1029 | Self::UserIdentityMismatch
1030 | Self::UserIdInvalid
1031 | Self::OpenIdInvalid
1032 | Self::UnionIdInvalid => ErrorCategory::Authentication,
1033
1034 Self::Forbidden
1036 | Self::AppPermissionDenied
1037 | Self::DocumentPermissionDenied
1038 | Self::PermissionDenied
1039 | Self::PermissionMissing
1040 | Self::AccessTokenNoPermission
1041 | Self::AccessDenied
1042 | Self::SecurityPolicyViolation => ErrorCategory::Permission,
1043
1044 Self::BadRequest
1046 | Self::ValidationError
1047 | Self::MissingRequiredParameter
1048 | Self::InvalidParameterFormat
1049 | Self::ParameterOutOfRange
1050 | Self::ChatTypeNotSupported
1051 | Self::MessageTypeNotSupported
1052 | Self::FileTypeNotSupported => ErrorCategory::Parameter,
1053
1054 Self::NotFound
1056 | Self::AppNotInstalled
1057 | Self::UserNotFound
1058 | Self::UserStatusException
1059 | Self::DepartmentNotFound
1060 | Self::ChatNotFound
1061 | Self::MessageNotFound
1062 | Self::FileNotFound
1063 | Self::FileSizeExceeded
1064 | Self::CalendarNotFound
1065 | Self::EventNotFound
1066 | Self::DocumentNotFound
1067 | Self::DocumentLocked
1068 | Self::SheetNotFound
1069 | Self::TableNotFound => ErrorCategory::Resource,
1070
1071 Self::InternalServerError
1073 | Self::BadGateway
1074 | Self::ServiceUnavailable
1075 | Self::GatewayTimeout
1076 | Self::AppStatusException
1077 | Self::InternalError
1078 | Self::CacheServiceUnavailable => ErrorCategory::Server,
1079
1080 Self::NetworkTimeout
1082 | Self::NetworkConnectionFailed
1083 | Self::DnsResolutionFailed
1084 | Self::SslCertificateError
1085 | Self::ConnectionRefused => ErrorCategory::Network,
1086
1087 Self::Conflict
1089 | Self::EventConflict
1090 | Self::BusinessError
1091 | Self::OperationNotSupported
1092 | Self::ResourceConflict => ErrorCategory::Business,
1093
1094 Self::MethodNotAllowed
1096 | Self::SerializationError
1097 | Self::DataFormatError
1098 | Self::EncodingError
1099 | Self::ConfigurationError
1100 | Self::ResourceExhausted => ErrorCategory::System,
1101
1102 Self::TooManyRequests | Self::RateLimitExceeded => ErrorCategory::RateLimit,
1104
1105 _ => ErrorCategory::Other,
1107 }
1108 }
1109}
1110
1111#[cfg(test)]
1112mod tests {
1113 use super::*;
1114
1115 #[test]
1116 fn test_error_code_conversion() {
1117 assert_eq!(ErrorCode::from_code(0), ErrorCode::Success);
1118 assert_eq!(ErrorCode::from_code(404), ErrorCode::NotFound);
1119 assert_eq!(ErrorCode::from_code(999999), ErrorCode::Unknown);
1120 }
1121
1122 #[test]
1123 fn test_error_code_properties() {
1124 let not_found = ErrorCode::NotFound;
1125 assert_eq!(not_found.as_code(), 404);
1126 assert_eq!(not_found.description(), "资源不存在");
1127 assert!(not_found.is_client_error());
1128 assert!(!not_found.is_server_error());
1129 assert!(!not_found.is_retryable());
1130
1131 let timeout = ErrorCode::NetworkTimeout;
1132 assert!(timeout.is_network_error());
1133 assert!(timeout.is_retryable());
1134 assert_eq!(timeout.suggested_retry_delay(), Some(3));
1135 }
1136
1137 #[test]
1138 fn test_http_status_conversion() {
1139 assert_eq!(ErrorCode::from_http_status(200), ErrorCode::Success);
1140 assert_eq!(ErrorCode::from_http_status(404), ErrorCode::NotFound);
1141 assert_eq!(
1142 ErrorCode::from_http_status(500),
1143 ErrorCode::InternalServerError
1144 );
1145 }
1146
1147 #[test]
1148 fn test_error_categories() {
1149 let auth_error = ErrorCode::Unauthorized;
1150 assert_eq!(auth_error.category(), ErrorCategory::Authentication);
1151
1152 let perm_error = ErrorCode::Forbidden;
1153 assert_eq!(perm_error.category(), ErrorCategory::Permission);
1154
1155 let net_error = ErrorCode::NetworkTimeout;
1156 assert_eq!(net_error.category(), ErrorCategory::Network);
1157 }
1158
1159 #[test]
1160 fn test_error_code_display() {
1161 let error = ErrorCode::AccessTokenInvalid;
1162 let display = format!("{}", error);
1163 assert!(display.contains("访问令牌无效"));
1164 assert!(display.contains("99991671"));
1165 }
1166
1167 #[test]
1168 fn test_new_error_code_methods() {
1169 assert_eq!(ErrorCode::network(), ErrorCode::NetworkConnectionFailed);
1171 assert_eq!(ErrorCode::authentication(), ErrorCode::AuthenticationFailed);
1172 assert_eq!(ErrorCode::permission(), ErrorCode::PermissionDenied);
1173 assert_eq!(ErrorCode::validation(), ErrorCode::ValidationError);
1174 assert_eq!(ErrorCode::configuration(), ErrorCode::ConfigurationError);
1175 assert_eq!(ErrorCode::internal(), ErrorCode::InternalError);
1176 assert_eq!(ErrorCode::serialization(), ErrorCode::SerializationError);
1177 assert_eq!(ErrorCode::unknown(), ErrorCode::Unknown);
1178 }
1179
1180 #[test]
1181 fn test_for_error_type() {
1182 assert_eq!(
1183 ErrorCode::for_error_type("Network"),
1184 ErrorCode::NetworkConnectionFailed
1185 );
1186 assert_eq!(
1187 ErrorCode::for_error_type("authentication"),
1188 ErrorCode::AuthenticationFailed
1189 );
1190 assert_eq!(
1191 ErrorCode::for_error_type("Validation"),
1192 ErrorCode::ValidationError
1193 );
1194 assert_eq!(
1195 ErrorCode::for_error_type("unknown_type"),
1196 ErrorCode::Unknown
1197 );
1198 }
1199
1200 #[test]
1201 fn test_from_message() {
1202 assert_eq!(
1203 ErrorCode::from_message("Network connection failed"),
1204 ErrorCode::NetworkConnectionFailed
1205 );
1206 assert_eq!(
1207 ErrorCode::from_message("Authentication token invalid"),
1208 ErrorCode::AuthenticationFailed
1209 );
1210 assert_eq!(
1211 ErrorCode::from_message("Permission denied"),
1212 ErrorCode::PermissionDenied
1213 );
1214 assert_eq!(
1215 ErrorCode::from_message("Invalid parameter"),
1216 ErrorCode::ValidationError
1217 );
1218 assert_eq!(
1219 ErrorCode::from_message("JSON parse error"),
1220 ErrorCode::SerializationError
1221 );
1222 assert_eq!(
1223 ErrorCode::from_message("Unknown error occurred"),
1224 ErrorCode::Unknown
1225 );
1226 }
1227
1228 #[test]
1229 fn test_retry_logic() {
1230 let retryable_error = ErrorCode::NetworkTimeout;
1231 assert!(retryable_error.should_retry(0));
1232 assert!(retryable_error.should_retry(1));
1233 assert!(!retryable_error.should_retry(3)); let non_retryable_error = ErrorCode::BadRequest;
1236 assert!(!non_retryable_error.should_retry(0));
1237
1238 let delay = retryable_error.exponential_backoff_delay(2);
1240 assert!(delay.is_some());
1241 assert!(delay.unwrap() > 1); }
1243
1244 #[test]
1245 fn test_error_severity() {
1246 assert_eq!(ErrorCode::Success.severity(), ErrorSeverity::Info);
1247 assert_eq!(ErrorCode::BadRequest.severity(), ErrorSeverity::Warning);
1248 assert_eq!(ErrorCode::Unauthorized.severity(), ErrorSeverity::Error);
1249 assert_eq!(
1250 ErrorCode::InternalServerError.severity(),
1251 ErrorSeverity::Critical
1252 );
1253 }
1254
1255 #[test]
1256 fn test_recovery_suggestions() {
1257 let suggestion = ErrorCode::NetworkConnectionFailed.recovery_suggestion();
1258 assert!(suggestion.contains("网络"));
1259
1260 let suggestion = ErrorCode::TokenExpired.recovery_suggestion();
1261 assert!(suggestion.contains("令牌"));
1262
1263 let suggestion = ErrorCode::ValidationError.recovery_suggestion();
1264 assert!(suggestion.contains("参数"));
1265 }
1266
1267 #[test]
1268 fn test_user_vs_system_errors() {
1269 assert!(ErrorCode::BadRequest.is_user_error());
1271 assert!(ErrorCode::Unauthorized.is_user_error());
1272 assert!(ErrorCode::ValidationError.is_user_error());
1273
1274 assert!(ErrorCode::InternalServerError.is_system_error());
1276 assert!(ErrorCode::NetworkTimeout.is_system_error());
1277 assert!(ErrorCode::ServiceUnavailable.is_system_error());
1278
1279 assert!(!ErrorCode::BadRequest.is_system_error());
1281 assert!(!ErrorCode::InternalServerError.is_user_error());
1282 }
1283
1284 #[test]
1285 fn test_log_levels() {
1286 assert_eq!(ErrorCode::Success.log_level(), "info");
1287 assert_eq!(ErrorCode::BadRequest.log_level(), "warn");
1288 assert_eq!(ErrorCode::Unauthorized.log_level(), "error");
1289 assert_eq!(ErrorCode::InternalServerError.log_level(), "error");
1290 }
1291}
1292
1293#[cfg(test)]
1294mod severity_tests {
1295 use super::*;
1296
1297 #[test]
1298 fn test_error_severity_basic() {
1299 assert_eq!(ErrorSeverity::Info.as_level(), 0);
1300 assert_eq!(ErrorSeverity::Warning.as_level(), 1);
1301 assert_eq!(ErrorSeverity::Error.as_level(), 2);
1302 assert_eq!(ErrorSeverity::Critical.as_level(), 3);
1303 }
1304
1305 #[test]
1306 fn test_error_severity_ordering() {
1307 assert!(ErrorSeverity::Info < ErrorSeverity::Warning);
1308 assert!(ErrorSeverity::Warning < ErrorSeverity::Error);
1309 assert!(ErrorSeverity::Error < ErrorSeverity::Critical);
1310 }
1311
1312 #[test]
1313 fn test_error_severity_from_level() {
1314 assert_eq!(ErrorSeverity::from_level(0), ErrorSeverity::Info);
1315 assert_eq!(ErrorSeverity::from_level(1), ErrorSeverity::Warning);
1316 assert_eq!(ErrorSeverity::from_level(2), ErrorSeverity::Error);
1317 assert_eq!(ErrorSeverity::from_level(3), ErrorSeverity::Critical);
1318 assert_eq!(ErrorSeverity::from_level(99), ErrorSeverity::Error); }
1320
1321 #[test]
1322 fn test_error_severity_properties() {
1323 assert!(!ErrorSeverity::Info.requires_immediate_action());
1324 assert!(!ErrorSeverity::Warning.requires_immediate_action());
1325 assert!(ErrorSeverity::Error.requires_immediate_action());
1326 assert!(ErrorSeverity::Critical.requires_immediate_action());
1327
1328 assert!(!ErrorSeverity::Info.requires_user_intervention());
1329 assert!(!ErrorSeverity::Warning.requires_user_intervention());
1330 assert!(ErrorSeverity::Error.requires_user_intervention());
1331 assert!(ErrorSeverity::Critical.requires_user_intervention());
1332
1333 assert!(ErrorSeverity::Info.is_auto_recoverable());
1334 assert!(ErrorSeverity::Warning.is_auto_recoverable());
1335 assert!(!ErrorSeverity::Error.is_auto_recoverable());
1336 assert!(!ErrorSeverity::Critical.is_auto_recoverable());
1337 }
1338
1339 #[test]
1340 fn test_error_severity_display() {
1341 assert_eq!(format!("{}", ErrorSeverity::Info), "信息");
1342 assert_eq!(format!("{}", ErrorSeverity::Warning), "警告");
1343 assert_eq!(format!("{}", ErrorSeverity::Error), "错误");
1344 assert_eq!(format!("{}", ErrorSeverity::Critical), "严重错误");
1345 }
1346}