use crate::common::response::AppResponse; #[derive(Debug)] pub enum AppErrorType { System, Config, Database, Notfound, Validate, Template, Authorization, Forbidden, } type Cause = Box; #[derive(Debug)] pub enum AppErrorItem { Message(String), Cause(Cause), } #[derive(Debug)] pub struct AppError { pub types: AppErrorType, pub error: AppErrorItem, } impl AppError { pub fn new(types: AppErrorType, error: AppErrorItem) -> Self { Self { types, error } } pub fn from_err(cause: Cause, types: AppErrorType) -> Self { Self::new(types, AppErrorItem::Cause(cause)) } pub fn from_msg(msg: &str, types: AppErrorType) -> Self { Self::new(types, AppErrorItem::Message(msg.to_string())) } pub fn notfound() -> Self { Self::from_msg("不存在的记录", AppErrorType::Notfound) } } impl std::fmt::Display for AppError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let msg = match &self.error { AppErrorItem::Cause(err) => err.to_string(), AppErrorItem::Message(msg) => msg.to_string(), }; write!(f, "{}", msg) } } impl std::error::Error for AppError {} impl From for AppError { fn from(err: config::ConfigError) -> Self { Self::from_err(Box::new(err), AppErrorType::Config) } } impl From for AppError { fn from(err: askama::Error) -> Self { Self::from_err(Box::new(err), AppErrorType::Template) } } impl From for AppError { fn from(err: sea_orm::DbErr) -> Self { Self::from_err(Box::new(err), AppErrorType::Database) } } impl From for AppError { fn from(err: jsonwebtoken::errors::Error) -> Self { Self::from_err(Box::new(err), AppErrorType::Authorization) } } impl From for AppError { fn from(err: validator::ValidationErrors) -> Self { Self::from_err(Box::new(err), AppErrorType::Validate) } } impl axum::response::IntoResponse for AppError { fn into_response(self) -> axum::response::Response { AppResponse::<()>::from_error(self).into_response() } } /// 记录错误 pub fn log_error(handler_name: &str) -> Box AppError> { let handler_name = handler_name.to_string(); Box::new(move |err| { tracing::error!("{}: {:?}", handler_name, err); err }) }