use std::fmt::Display; use std::num::ParseIntError; use std::time::SystemTimeError; use std::{borrow::Cow, str}; use serde::{Deserialize, Serialize}; use serde_json::Error; use crate::error_code::ErrorCode; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AppError { pub code: ErrorCode, pub message: Cow<'static, str>, } impl AppError { pub fn new(code: ErrorCode, message: impl Into>) -> Self { Self { code, message: message.into(), } } } impl Display for AppError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.message) } } impl std::error::Error for AppError {} #[cfg(feature = "cloud")] impl actix_web::error::ResponseError for AppError { fn status_code(&self) -> actix_web::http::StatusCode { actix_web::http::StatusCode::OK } fn error_response(&self) -> actix_web::HttpResponse { actix_web::HttpResponse::Ok().json(self) } } // impl From for AppError { fn from(err: anyhow::Error) -> Self { match err.downcast_ref::() { None => AppError::new(ErrorCode::Unhandled, err.to_string()), Some(err) => err.clone(), } } } impl From for AppError { fn from(err: gotrue_entity::GoTrueError) -> Self { match (err.code, err.msg.as_str()) { (400, m) if m.starts_with("oauth error") => AppError::new(ErrorCode::OAuthError, err.msg), (401, _) => AppError::new(ErrorCode::OAuthError, err.msg), (422, _) => AppError::new(ErrorCode::InvalidRequestParams, err.msg), _ => AppError::new( ErrorCode::Unhandled, format!( "gotrue error: {}, message: {}, id: {:?}", err.code, err.msg, err.error_id, ), ), } } } #[cfg(feature = "cloud")] impl From for AppError { fn from(err: gotrue_entity::OAuthError) -> Self { AppError::new(ErrorCode::OAuthError, err.to_string()) } } impl From for AppError { fn from(value: ErrorCode) -> Self { AppError::new(value, value.to_string()) } } #[cfg(feature = "cloud")] impl From for AppError { fn from(err: sqlx::types::uuid::Error) -> Self { AppError::new(ErrorCode::Unhandled, format!("uuid error: {}", err)) } } #[cfg(feature = "cloud")] impl From for AppError { fn from(err: sqlx::Error) -> Self { AppError::new(ErrorCode::Unhandled, format!("sqlx error: {}", err)) } } impl From for AppError { fn from(value: reqwest::Error) -> Self { AppError::new(ErrorCode::Unhandled, value.to_string()) } } impl From for AppError { fn from(value: Error) -> Self { AppError::new(ErrorCode::Unhandled, value.to_string()) } } impl From for AppError { fn from(value: opener::OpenError) -> Self { AppError::new(ErrorCode::OpenError, value.to_string()) } } #[cfg(feature = "cloud")] impl From for AppError { fn from(value: validator::ValidationErrors) -> Self { AppError::new(ErrorCode::InvalidRequestParams, value.to_string()) } } impl From for AppError { fn from(value: url::ParseError) -> Self { AppError::new(ErrorCode::InvalidUrl, value.to_string()) } } impl From for AppError { fn from(value: ParseIntError) -> Self { AppError::new(ErrorCode::InvalidUrl, value.to_string()) } } impl From for AppError { fn from(value: SystemTimeError) -> Self { AppError::new(ErrorCode::Unhandled, value.to_string()) } } #[cfg(feature = "cloud")] impl From for AppError { fn from(value: s3::error::S3Error) -> Self { AppError::new(ErrorCode::S3Error, value.to_string()) } }