use std::fmt;
pub type Result<T> = std::result::Result<T, ForgeError>;
#[derive(Debug)]
pub enum ForgeError {
Authentication {
message: String,
response: Option<serde_json::Value>,
},
RateLimit {
message: String,
response: Option<serde_json::Value>,
},
InvalidRequest {
message: String,
response: Option<serde_json::Value>,
},
Server {
status_code: u16,
message: String,
response: Option<serde_json::Value>,
},
Network { message: String },
Timeout { message: String },
Stream { message: String },
ModelNotFound {
model: String,
response: Option<serde_json::Value>,
},
Json { message: String },
Config { message: String },
Internal { message: String },
Other { message: String },
}
impl ForgeError {
pub fn status_code(&self) -> Option<u16> {
match self {
Self::Authentication { .. } => Some(401),
Self::RateLimit { .. } => Some(429),
Self::InvalidRequest { .. } => Some(400),
Self::Server { status_code, .. } => Some(*status_code),
Self::ModelNotFound { .. } => Some(404),
_ => None,
}
}
pub fn from_status(
status: u16,
message: impl Into<String>,
response: Option<serde_json::Value>,
) -> Self {
let message = message.into();
match status {
401 => Self::Authentication { message, response },
429 => Self::RateLimit { message, response },
400 => Self::InvalidRequest { message, response },
404 => Self::ModelNotFound {
model: message,
response,
},
500..=599 => Self::Server {
status_code: status,
message,
response,
},
_ => Self::Server {
status_code: status,
message,
response,
},
}
}
pub fn authentication(message: impl Into<String>) -> Self {
Self::Authentication {
message: message.into(),
response: None,
}
}
pub fn rate_limit(message: impl Into<String>) -> Self {
Self::RateLimit {
message: message.into(),
response: None,
}
}
pub fn network(message: impl Into<String>) -> Self {
Self::Network {
message: message.into(),
}
}
pub fn timeout(message: impl Into<String>) -> Self {
Self::Timeout {
message: message.into(),
}
}
pub fn stream(message: impl Into<String>) -> Self {
Self::Stream {
message: message.into(),
}
}
pub fn config(message: impl Into<String>) -> Self {
Self::Config {
message: message.into(),
}
}
pub fn internal(message: impl Into<String>) -> Self {
Self::Internal {
message: message.into(),
}
}
pub fn other(message: impl Into<String>) -> Self {
Self::Other {
message: message.into(),
}
}
}
impl fmt::Display for ForgeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Authentication { message, .. } => write!(f, "[401] {}", message),
Self::RateLimit { message, .. } => write!(f, "[429] {}", message),
Self::InvalidRequest { message, .. } => write!(f, "[400] {}", message),
Self::Server {
status_code,
message,
..
} => write!(f, "[{}] {}", status_code, message),
Self::Network { message } => write!(f, "Network error: {}", message),
Self::Timeout { message } => write!(f, "Timeout: {}", message),
Self::Stream { message } => write!(f, "Stream error: {}", message),
Self::ModelNotFound { model, .. } => write!(f, "[404] Model '{}' not found", model),
Self::Json { message } => write!(f, "JSON error: {}", message),
Self::Config { message } => write!(f, "Config error: {}", message),
Self::Internal { message } => write!(f, "Internal error: {}", message),
Self::Other { message } => write!(f, "Error: {}", message),
}
}
}
impl std::error::Error for ForgeError {}
impl From<reqwest::Error> for ForgeError {
fn from(err: reqwest::Error) -> Self {
if err.is_timeout() {
Self::Timeout {
message: err.to_string(),
}
} else if err.is_connect() {
Self::Network {
message: format!("Failed to connect: {}", err),
}
} else {
Self::Network {
message: err.to_string(),
}
}
}
}
impl From<serde_json::Error> for ForgeError {
fn from(err: serde_json::Error) -> Self {
Self::Json {
message: err.to_string(),
}
}
}