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