use thiserror::Error;
#[derive(Error, Debug, Clone)]
pub enum SdkError {
#[error("HTTP error: {0}")]
Http(String),
#[error("MQTT error: {0}")]
Mqtt(String),
#[error("Serialization error: {0}")]
Serialization(String),
#[error("Authentication error: {0}")]
Auth(String),
#[error("Network error: {0}")]
Network(String),
#[error("Configuration error: {0}")]
Config(String),
#[error("Not connected")]
NotConnected,
#[error("Timeout")]
Timeout,
#[error("Other error: {0}")]
Other(String),
}
pub type SdkResult<T> = Result<T, SdkError>;
impl From<serde_json::Error> for SdkError {
fn from(err: serde_json::Error) -> Self {
SdkError::Serialization(err.to_string())
}
}
impl From<std::io::Error> for SdkError {
fn from(err: std::io::Error) -> Self {
SdkError::Network(err.to_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HttpErrorType {
Unauthorized,
Forbidden,
NotFound,
BadRequest,
ServerError,
NetworkError,
Other,
}
#[derive(Debug, Clone)]
pub struct HttpError {
pub error_type: HttpErrorType,
pub status_code: u16,
pub message: String,
pub requires_relogin: bool,
}
impl HttpError {
pub fn from_error(error: &str, default_message: &str) -> Self {
if let Some(colon_pos) = error.find(':') {
let code = &error[..colon_pos];
let message = error[colon_pos + 1..].trim();
if code.chars().all(|c| c.is_ascii_uppercase() || c == '_') {
match code {
"USER_NOT_FOUND" | "USER_DELETED" => {
return Self {
error_type: HttpErrorType::NotFound,
status_code: 404,
message: message.to_string(),
requires_relogin: true,
};
}
"INVALID_TOKEN" | "TOKEN_EXPIRED" => {
return Self {
error_type: HttpErrorType::Unauthorized,
status_code: 401,
message: message.to_string(),
requires_relogin: true,
};
}
"UNAUTHORIZED" | "AUTH_FAILED" => {
return Self {
error_type: HttpErrorType::Unauthorized,
status_code: 401,
message: message.to_string(),
requires_relogin: true,
};
}
"FORBIDDEN" => {
return Self {
error_type: HttpErrorType::Forbidden,
status_code: 403,
message: message.to_string(),
requires_relogin: false,
};
}
_ => {}
}
}
}
if error.contains("HTTP 错误: 401") || error.contains("HTTP 401") {
Self {
error_type: HttpErrorType::Unauthorized,
status_code: 401,
message: "登录已过期,请重新登录".to_string(),
requires_relogin: true,
}
} else if error.contains("HTTP 错误: 403") || error.contains("HTTP 403") {
Self {
error_type: HttpErrorType::Forbidden,
status_code: 403,
message: "无权限访问此资源".to_string(),
requires_relogin: false,
}
} else if error.contains("HTTP 错误: 404") || error.contains("HTTP 404") {
Self {
error_type: HttpErrorType::NotFound,
status_code: 404,
message: "资源不存在".to_string(),
requires_relogin: false,
}
} else if error.contains("HTTP 错误: 400") || error.contains("HTTP 400") {
Self {
error_type: HttpErrorType::BadRequest,
status_code: 400,
message: "请求参数错误".to_string(),
requires_relogin: false,
}
} else if error.contains("HTTP 错误: 5") || error.contains("HTTP 50") {
Self {
error_type: HttpErrorType::ServerError,
status_code: 500,
message: "服务器错误,请稍后重试".to_string(),
requires_relogin: false,
}
} else {
Self {
error_type: HttpErrorType::Other,
status_code: 0,
message: if default_message.is_empty() {
error.to_string()
} else {
format!("{}: {}", default_message, error)
},
requires_relogin: false,
}
}
}
}