Skip to main content

bpi_rs/err/
error.rs

1use serde::Serialize;
2use thiserror::Error;
3
4/// 错误类型分类
5#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
6pub enum ErrorCategory {
7    /// 权限认证类错误
8    Auth,
9    /// 请求参数类错误
10    Request,
11    /// 服务器类错误
12    Server,
13    /// 业务逻辑类错误
14    Business,
15    /// 网络类错误
16    Network,
17    /// 未知错误
18    Unknown,
19}
20
21#[derive(Debug, Error, Serialize)]
22pub enum BpiError {
23    /// 网络请求失败
24    #[error("网络请求失败: {message}")]
25    Network {
26        message: String,
27    },
28
29    /// HTTP状态码错误
30    #[error("HTTP请求失败,状态码: {status}")]
31    Http {
32        status: u16,
33    },
34
35    /// JSON解析失败
36    #[error("数据解析失败: {message}")]
37    Parse {
38        message: String,
39    },
40
41    /// API返回的业务错误
42    #[error("API错误 [{code}]: {message}")]
43    Api {
44        code: i32,
45        message: String,
46        category: ErrorCategory,
47    },
48
49    /// 验证错误
50    #[error("验证失败: {message}")]
51    Authentication {
52        message: String,
53    },
54
55    /// # 参数错误
56    #[error("参数错误 [{field}]: {message}")]
57    InvalidParameter {
58        field: &'static str,
59        message: &'static str,
60    },
61}
62
63impl BpiError {
64    pub fn missing_csrf() -> Self {
65        BpiError::InvalidParameter {
66            field: "csrf",
67            message: "缺少CSRF",
68        }
69    }
70
71    pub fn missing_data() -> Self {
72        BpiError::Parse {
73            message: "数据解析失败, 缺少data字段".to_string(),
74        }
75    }
76
77    pub fn auth_required() -> Self {
78        BpiError::Authentication {
79            message: "需要登录".to_string(),
80        }
81    }
82}
83
84/// 生成Error的From实现
85impl BpiError {
86    /// 根据API错误码创建BpiError
87    pub fn from_code(code: i32) -> Self {
88        let message = super::code::get_error_message(code);
89        let category = super::code::categorize_error(code);
90
91        BpiError::Api {
92            code,
93            message,
94            category,
95        }
96    }
97
98    // 不在错误码表中的API错误
99    pub fn from_code_message(code: i32, message: String) -> Self {
100        let category = super::code::categorize_error(code);
101        BpiError::Api {
102            code,
103            message,
104            category,
105        }
106    }
107
108    /// 从API响应创建BpiError
109    pub fn from_api_response<T>(resp: crate::response::BpiResponse<T>) -> Self {
110        if resp.code == 0 {
111            return BpiError::Api {
112                code: 0,
113                message: "API返回成功状态但被当作错误处理".to_string(),
114                category: ErrorCategory::Unknown,
115            };
116        }
117        Self::from_code(resp.code)
118    }
119}
120
121/// 获取错误属性
122impl BpiError {
123    /// 获取错误码
124    pub fn code(&self) -> Option<i32> {
125        match self {
126            BpiError::Api { code, .. } => Some(*code),
127            _ => None,
128        }
129    }
130
131    /// 获取错误分类
132    pub fn category(&self) -> ErrorCategory {
133        match self {
134            BpiError::Api { category, .. } => category.clone(),
135            BpiError::Network { .. } => ErrorCategory::Network,
136            BpiError::Http { .. } => ErrorCategory::Network,
137            BpiError::Parse { .. } => ErrorCategory::Request,
138            BpiError::InvalidParameter { .. } => ErrorCategory::Request,
139            BpiError::Authentication { .. } => ErrorCategory::Auth,
140        }
141    }
142}
143
144/// 错误创建函数
145impl BpiError {
146    /// 创建网络错误
147    pub fn network(message: impl Into<String>) -> Self {
148        BpiError::Network {
149            message: message.into(),
150        }
151    }
152
153    /// 创建HTTP错误
154    pub fn http(status: u16) -> Self {
155        BpiError::Http { status }
156    }
157
158    /// 创建解析错误
159    pub fn parse(message: impl Into<String>) -> Self {
160        BpiError::Parse {
161            message: message.into(),
162        }
163    }
164
165    /// 创建参数错误
166    pub fn invalid_parameter(field: &'static str, message: &'static str) -> Self {
167        BpiError::InvalidParameter { field, message }
168    }
169
170    pub fn auth(message: impl Into<String>) -> Self {
171        BpiError::Api {
172            code: 401,
173            message: message.into(),
174            category: ErrorCategory::Auth,
175        }
176    }
177}
178
179/// 错误判断
180impl BpiError {
181    /// 判断是否需要用户登录
182    pub fn requires_login(&self) -> bool {
183        matches!(self.code(), Some(-101) | Some(-401))
184    }
185
186    /// 判断是否为权限问题
187    pub fn is_permission_error(&self) -> bool {
188        matches!(self.category(), ErrorCategory::Auth) ||
189            matches!(self.code(), Some(-403) | Some(-4))
190    }
191
192    /// 判断是否需要VIP权限
193    pub fn requires_vip(&self) -> bool {
194        matches!(self.code(), Some(-106) | Some(-650))
195    }
196
197    /// 判断是否为业务逻辑错误
198    pub fn is_business_error(&self) -> bool {
199        matches!(self.category(), ErrorCategory::Business)
200    }
201}