Skip to main content

cool_core/error/
mod.rs

1//! 异常处理模块
2//!
3//! 对应 TypeScript 版本的 `exception/`
4
5use crate::constant::{error_info, ResCode};
6use salvo::prelude::*;
7use serde::Serialize;
8use thiserror::Error;
9
10/// Cool 框架统一错误类型
11#[derive(Error, Debug)]
12pub enum CoolError {
13    /// 核心异常
14    #[error("{0}")]
15    Core(String),
16
17    /// 验证异常
18    #[error("{0}")]
19    Validate(String),
20
21    /// 通用业务异常
22    #[error("{0}")]
23    Comm(String),
24
25    /// 未授权
26    #[error("{0}")]
27    Unauthorized(String),
28
29    /// 禁止访问
30    #[error("{0}")]
31    Forbidden(String),
32
33    /// 未找到
34    #[error("{0}")]
35    NotFound(String),
36
37    /// 数据库错误
38    #[error("数据库错误: {0}")]
39    Database(#[from] sea_orm::DbErr),
40
41    /// JSON 序列化错误
42    #[error("JSON 错误: {0}")]
43    Json(#[from] serde_json::Error),
44
45    /// Redis 错误
46    #[error("Redis 错误: {0}")]
47    Redis(#[from] redis::RedisError),
48
49    /// JWT 错误
50    #[error("JWT 错误: {0}")]
51    Jwt(#[from] jsonwebtoken::errors::Error),
52
53    /// 其他错误
54    #[error("{0}")]
55    Other(#[from] anyhow::Error),
56}
57
58impl CoolError {
59    /// 创建核心异常
60    pub fn core<S: Into<String>>(msg: S) -> Self {
61        Self::Core(msg.into())
62    }
63
64    /// 创建验证异常
65    pub fn validate<S: Into<String>>(msg: S) -> Self {
66        Self::Validate(msg.into())
67    }
68
69    /// 创建通用异常
70    pub fn comm<S: Into<String>>(msg: S) -> Self {
71        Self::Comm(msg.into())
72    }
73
74    /// 创建未授权异常
75    pub fn unauthorized() -> Self {
76        Self::Unauthorized(error_info::UNAUTHORIZED.to_string())
77    }
78
79    /// 创建禁止访问异常
80    pub fn forbidden() -> Self {
81        Self::Forbidden(error_info::FORBIDDEN.to_string())
82    }
83
84    /// 创建未找到异常
85    pub fn not_found() -> Self {
86        Self::NotFound(error_info::NOT_FOUND.to_string())
87    }
88
89    /// 没有实体异常
90    pub fn no_entity() -> Self {
91        Self::Core(error_info::NO_ENTITY.to_string())
92    }
93
94    /// 没有ID异常
95    pub fn no_id() -> Self {
96        Self::Validate(error_info::NO_ID.to_string())
97    }
98
99    /// 获取错误码
100    pub fn code(&self) -> ResCode {
101        match self {
102            Self::Core(_) => ResCode::CoreError,
103            Self::Validate(_) => ResCode::ValidateFail,
104            Self::Comm(_) => ResCode::CommError,
105            Self::Unauthorized(_) => ResCode::Unauthorized,
106            Self::Forbidden(_) => ResCode::Forbidden,
107            Self::NotFound(_) => ResCode::NotFound,
108            Self::Database(_) => ResCode::CoreError,
109            Self::Json(_) => ResCode::ValidateFail,
110            Self::Redis(_) => ResCode::CoreError,
111            Self::Jwt(_) => ResCode::Unauthorized,
112            Self::Other(_) => ResCode::Fail,
113        }
114    }
115
116    /// 获取 HTTP 状态码
117    pub fn status_code(&self) -> StatusCode {
118        match self {
119            Self::Unauthorized(_) | Self::Jwt(_) => StatusCode::UNAUTHORIZED,
120            Self::Forbidden(_) => StatusCode::FORBIDDEN,
121            Self::NotFound(_) => StatusCode::NOT_FOUND,
122            Self::Validate(_) | Self::Json(_) => StatusCode::BAD_REQUEST,
123            _ => StatusCode::INTERNAL_SERVER_ERROR,
124        }
125    }
126}
127
128/// Cool 框架结果类型
129pub type CoolResult<T> = Result<T, CoolError>;
130
131/// API 响应结构
132#[derive(Debug, Clone, Serialize)]
133pub struct CoolResponse<T: Serialize> {
134    /// 响应码
135    pub code: i32,
136    /// 响应消息
137    pub message: String,
138    /// 响应数据
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub data: Option<T>,
141}
142
143impl<T: Serialize> CoolResponse<T> {
144    /// 成功响应
145    pub fn ok(data: T) -> Self {
146        Self {
147            code: ResCode::Success.code(),
148            message: "success".to_string(),
149            data: Some(data),
150        }
151    }
152
153    /// 成功响应(无数据)
154    pub fn ok_empty() -> CoolResponse<()> {
155        CoolResponse {
156            code: ResCode::Success.code(),
157            message: "success".to_string(),
158            data: None,
159        }
160    }
161
162    /// 失败响应
163    pub fn fail<S: Into<String>>(msg: S) -> CoolResponse<()> {
164        CoolResponse {
165            code: ResCode::Fail.code(),
166            message: msg.into(),
167            data: None,
168        }
169    }
170
171    /// 从错误创建响应
172    pub fn from_error(err: &CoolError) -> CoolResponse<()> {
173        CoolResponse {
174            code: err.code().code(),
175            message: err.to_string(),
176            data: None,
177        }
178    }
179}
180
181/// 实现 Salvo 的错误处理
182#[async_trait]
183impl Writer for CoolError {
184    async fn write(mut self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) {
185        let status = self.status_code();
186        let response = CoolResponse::<()>::from_error(&self);
187
188        res.status_code(status);
189        res.render(Json(response));
190    }
191}
192
193/// 分页响应结构
194#[derive(Debug, Clone, Serialize)]
195pub struct PageResult<T: Serialize> {
196    /// 数据列表
197    pub list: Vec<T>,
198    /// 分页信息
199    pub pagination: Pagination,
200}
201
202/// 分页信息
203#[derive(Debug, Clone, Serialize)]
204pub struct Pagination {
205    /// 当前页
206    pub page: u64,
207    /// 每页条数
208    pub size: u64,
209    /// 总条数
210    pub total: u64,
211}
212
213impl<T: Serialize> PageResult<T> {
214    /// 创建分页结果
215    pub fn new(list: Vec<T>, page: u64, size: u64, total: u64) -> Self {
216        Self {
217            list,
218            pagination: Pagination { page, size, total },
219        }
220    }
221}