use crate::constant::{error_info, ResCode};
use salvo::prelude::*;
use serde::Serialize;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CoolError {
#[error("{0}")]
Core(String),
#[error("{0}")]
Validate(String),
#[error("{0}")]
Comm(String),
#[error("{0}")]
Unauthorized(String),
#[error("{0}")]
Forbidden(String),
#[error("{0}")]
NotFound(String),
#[error("数据库错误: {0}")]
Database(#[from] sea_orm::DbErr),
#[error("JSON 错误: {0}")]
Json(#[from] serde_json::Error),
#[error("Redis 错误: {0}")]
Redis(#[from] redis::RedisError),
#[error("JWT 错误: {0}")]
Jwt(#[from] jsonwebtoken::errors::Error),
#[error("{0}")]
Other(#[from] anyhow::Error),
}
impl CoolError {
pub fn core<S: Into<String>>(msg: S) -> Self {
Self::Core(msg.into())
}
pub fn validate<S: Into<String>>(msg: S) -> Self {
Self::Validate(msg.into())
}
pub fn comm<S: Into<String>>(msg: S) -> Self {
Self::Comm(msg.into())
}
pub fn unauthorized() -> Self {
Self::Unauthorized(error_info::UNAUTHORIZED.to_string())
}
pub fn forbidden() -> Self {
Self::Forbidden(error_info::FORBIDDEN.to_string())
}
pub fn not_found() -> Self {
Self::NotFound(error_info::NOT_FOUND.to_string())
}
pub fn no_entity() -> Self {
Self::Core(error_info::NO_ENTITY.to_string())
}
pub fn no_id() -> Self {
Self::Validate(error_info::NO_ID.to_string())
}
pub fn code(&self) -> ResCode {
match self {
Self::Core(_) => ResCode::CoreError,
Self::Validate(_) => ResCode::ValidateFail,
Self::Comm(_) => ResCode::CommError,
Self::Unauthorized(_) => ResCode::Unauthorized,
Self::Forbidden(_) => ResCode::Forbidden,
Self::NotFound(_) => ResCode::NotFound,
Self::Database(_) => ResCode::CoreError,
Self::Json(_) => ResCode::ValidateFail,
Self::Redis(_) => ResCode::CoreError,
Self::Jwt(_) => ResCode::Unauthorized,
Self::Other(_) => ResCode::Fail,
}
}
pub fn status_code(&self) -> StatusCode {
match self {
Self::Unauthorized(_) | Self::Jwt(_) => StatusCode::UNAUTHORIZED,
Self::Forbidden(_) => StatusCode::FORBIDDEN,
Self::NotFound(_) => StatusCode::NOT_FOUND,
Self::Validate(_) | Self::Json(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
pub type CoolResult<T> = Result<T, CoolError>;
#[derive(Debug, Clone, Serialize)]
pub struct CoolResponse<T: Serialize> {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<T>,
}
impl<T: Serialize> CoolResponse<T> {
pub fn ok(data: T) -> Self {
Self {
code: ResCode::Success.code(),
message: "success".to_string(),
data: Some(data),
}
}
pub fn ok_empty() -> CoolResponse<()> {
CoolResponse {
code: ResCode::Success.code(),
message: "success".to_string(),
data: None,
}
}
pub fn fail<S: Into<String>>(msg: S) -> CoolResponse<()> {
CoolResponse {
code: ResCode::Fail.code(),
message: msg.into(),
data: None,
}
}
pub fn from_error(err: &CoolError) -> CoolResponse<()> {
CoolResponse {
code: err.code().code(),
message: err.to_string(),
data: None,
}
}
}
#[async_trait]
impl Writer for CoolError {
async fn write(mut self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) {
let status = self.status_code();
let response = CoolResponse::<()>::from_error(&self);
res.status_code(status);
res.render(Json(response));
}
}
#[derive(Debug, Clone, Serialize)]
pub struct PageResult<T: Serialize> {
pub list: Vec<T>,
pub pagination: Pagination,
}
#[derive(Debug, Clone, Serialize)]
pub struct Pagination {
pub page: u64,
pub size: u64,
pub total: u64,
}
impl<T: Serialize> PageResult<T> {
pub fn new(list: Vec<T>, page: u64, size: u64, total: u64) -> Self {
Self {
list,
pagination: Pagination { page, size, total },
}
}
}