1use crate::constant::{error_info, ResCode};
6use salvo::prelude::*;
7use serde::Serialize;
8use thiserror::Error;
9
10#[derive(Error, Debug)]
12pub enum CoolError {
13 #[error("{0}")]
15 Core(String),
16
17 #[error("{0}")]
19 Validate(String),
20
21 #[error("{0}")]
23 Comm(String),
24
25 #[error("{0}")]
27 Unauthorized(String),
28
29 #[error("{0}")]
31 Forbidden(String),
32
33 #[error("{0}")]
35 NotFound(String),
36
37 #[error("数据库错误: {0}")]
39 Database(#[from] sea_orm::DbErr),
40
41 #[error("JSON 错误: {0}")]
43 Json(#[from] serde_json::Error),
44
45 #[error("Redis 错误: {0}")]
47 Redis(#[from] redis::RedisError),
48
49 #[error("JWT 错误: {0}")]
51 Jwt(#[from] jsonwebtoken::errors::Error),
52
53 #[error("{0}")]
55 Other(#[from] anyhow::Error),
56}
57
58impl CoolError {
59 pub fn core<S: Into<String>>(msg: S) -> Self {
61 Self::Core(msg.into())
62 }
63
64 pub fn validate<S: Into<String>>(msg: S) -> Self {
66 Self::Validate(msg.into())
67 }
68
69 pub fn comm<S: Into<String>>(msg: S) -> Self {
71 Self::Comm(msg.into())
72 }
73
74 pub fn unauthorized() -> Self {
76 Self::Unauthorized(error_info::UNAUTHORIZED.to_string())
77 }
78
79 pub fn forbidden() -> Self {
81 Self::Forbidden(error_info::FORBIDDEN.to_string())
82 }
83
84 pub fn not_found() -> Self {
86 Self::NotFound(error_info::NOT_FOUND.to_string())
87 }
88
89 pub fn no_entity() -> Self {
91 Self::Core(error_info::NO_ENTITY.to_string())
92 }
93
94 pub fn no_id() -> Self {
96 Self::Validate(error_info::NO_ID.to_string())
97 }
98
99 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 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
128pub type CoolResult<T> = Result<T, CoolError>;
130
131#[derive(Debug, Clone, Serialize)]
133pub struct CoolResponse<T: Serialize> {
134 pub code: i32,
136 pub message: String,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub data: Option<T>,
141}
142
143impl<T: Serialize> CoolResponse<T> {
144 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 pub fn ok_empty() -> CoolResponse<()> {
155 CoolResponse {
156 code: ResCode::Success.code(),
157 message: "success".to_string(),
158 data: None,
159 }
160 }
161
162 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 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#[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#[derive(Debug, Clone, Serialize)]
195pub struct PageResult<T: Serialize> {
196 pub list: Vec<T>,
198 pub pagination: Pagination,
200}
201
202#[derive(Debug, Clone, Serialize)]
204pub struct Pagination {
205 pub page: u64,
207 pub size: u64,
209 pub total: u64,
211}
212
213impl<T: Serialize> PageResult<T> {
214 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}