use super::code::ErrorCode;
use super::localized::LocalizedError;
use thiserror::Error;
use std::collections::HashMap;
#[derive(Error, Debug, Clone)]
pub enum FlareError {
#[error("错误 [{code}] {reason}", code = .code.as_str())]
Localized {
code: ErrorCode,
reason: String,
details: Option<String>,
params: Option<HashMap<String, String>>,
timestamp: chrono::DateTime<chrono::Utc>,
},
#[error("系统错误: {0}")]
System(String),
#[error("IO 错误: {0}")]
Io(String),
}
impl FlareError {
pub fn localized(code: ErrorCode, reason: impl Into<String>) -> Self {
FlareError::Localized {
code,
reason: reason.into(),
details: None,
params: None,
timestamp: chrono::Utc::now(),
}
}
pub fn system(msg: impl Into<String>) -> Self {
FlareError::System(msg.into())
}
pub fn io(msg: impl Into<String>) -> Self {
FlareError::Io(msg.into())
}
pub fn connection_failed(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::ConnectionFailed, reason)
}
pub fn connection_timeout(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::ConnectionTimeout, reason)
}
pub fn connection_closed(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::ConnectionClosed, reason)
}
pub fn authentication_failed(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::AuthenticationFailed, reason)
}
pub fn authentication_expired(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::AuthenticationExpired, reason)
}
pub fn protocol_error(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::ProtocolError, reason)
}
pub fn message_format_error(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::MessageFormatError, reason)
}
pub fn message_send_failed(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::MessageSendFailed, reason)
}
pub fn user_not_found(user_id: impl Into<String>) -> Self {
let mut params = HashMap::new();
params.insert("user_id".to_string(), user_id.into());
Self::Localized {
code: ErrorCode::UserNotFound,
reason: "用户不存在".to_string(),
details: None,
params: Some(params),
timestamp: chrono::Utc::now(),
}
}
pub fn user_offline(user_id: impl Into<String>) -> Self {
let mut params = HashMap::new();
params.insert("user_id".to_string(), user_id.into());
Self::Localized {
code: ErrorCode::UserOffline,
reason: "用户离线".to_string(),
details: None,
params: Some(params),
timestamp: chrono::Utc::now(),
}
}
pub fn serialization_error(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::SerializationError, reason)
}
pub fn deserialization_error(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::DeserializationError, reason)
}
pub fn encoding_error(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::EncodingError, reason)
}
pub fn general_error(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::GeneralError, reason)
}
pub fn timeout(reason: impl Into<String>) -> Self {
Self::localized(ErrorCode::OperationTimeout, reason)
}
pub fn as_localized(&self) -> Option<LocalizedError> {
match self {
FlareError::Localized { code, reason, details, params, timestamp } => {
Some(LocalizedError {
code: *code,
reason: reason.clone(),
details: details.clone(),
params: params.clone(),
timestamp: *timestamp,
})
}
_ => None,
}
}
pub fn code(&self) -> Option<ErrorCode> {
match self {
FlareError::Localized { code, .. } => Some(*code),
_ => None,
}
}
pub fn reason(&self) -> &str {
match self {
FlareError::Localized { reason, .. } => reason,
FlareError::System(msg) => msg,
FlareError::Io(msg) => msg,
}
}
pub fn to_localized(self) -> LocalizedError {
match self {
FlareError::Localized { code, reason, details, params, timestamp } => {
LocalizedError {
code,
reason,
details,
params,
timestamp,
}
}
FlareError::System(msg) => LocalizedError::new(ErrorCode::InternalError, msg),
FlareError::Io(msg) => LocalizedError::new(ErrorCode::NetworkError, msg),
}
}
pub fn is_retryable(&self) -> bool {
self.code()
.map(|code| code.is_retryable())
.unwrap_or(false)
}
}
pub type ClientError = FlareError;
pub type ServerError = FlareError;
pub type Result<T> = std::result::Result<T, FlareError>;