#![allow(missing_docs)]
use actix_web::{HttpResponse, ResponseError};
use thiserror::Error;
pub type Result<T> = std::result::Result<T, GatewayError>;
#[derive(Error, Debug)]
#[allow(dead_code)]
pub enum GatewayError {
#[error("Configuration error: {0}")]
Config(String),
#[error("Database error: {0}")]
Database(#[from] sea_orm::DbErr),
#[error("Redis error: {0}")]
Redis(#[from] redis::RedisError),
#[error("HTTP client error: {0}")]
HttpClient(#[from] reqwest::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("YAML error: {0}")]
Yaml(#[from] serde_yaml::Error),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Authentication error: {0}")]
Auth(String),
#[error("Authorization error: {0}")]
Authorization(String),
#[error("Provider error: {0}")]
Provider(#[from] ProviderError),
#[error("Rate limit exceeded: {0}")]
RateLimit(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("Cache error: {0}")]
Cache(String),
#[error("Circuit breaker error: {0}")]
CircuitBreaker(String),
#[error("Timeout error: {0}")]
Timeout(String),
#[error("Not found: {0}")]
NotFound(String),
#[error("Conflict: {0}")]
Conflict(String),
#[error("Bad request: {0}")]
BadRequest(String),
#[error("Internal server error: {0}")]
Internal(String),
#[error("Service unavailable: {0}")]
ServiceUnavailable(String),
#[error("JWT error: {0}")]
Jwt(#[from] jsonwebtoken::errors::Error),
#[error("Crypto error: {0}")]
Crypto(String),
#[error("File storage error: {0}")]
FileStorage(String),
#[error("Vector database error: {0}")]
VectorDb(String),
#[error("Monitoring error: {0}")]
Monitoring(String),
#[error("Integration error: {0}")]
Integration(String),
#[error("Network error: {0}")]
Network(String),
#[error("Parsing error: {0}")]
Parsing(String),
#[error("Alert error: {0}")]
Alert(String),
#[error("Not implemented: {0}")]
NotImplemented(String),
#[error("Unauthorized: {0}")]
Unauthorized(String),
#[error("Forbidden: {0}")]
Forbidden(String),
#[error("External service error: {0}")]
External(String),
#[error("Invalid request: {0}")]
InvalidRequest(String),
#[error("No providers available: {0}")]
NoProvidersAvailable(String),
#[error("Provider not found: {0}")]
ProviderNotFound(String),
#[error("No providers for model: {0}")]
NoProvidersForModel(String),
#[error("No healthy providers: {0}")]
NoHealthyProviders(String),
}
#[derive(Error, Debug)]
#[allow(dead_code)]
pub enum ProviderError {
#[error("API error: {message} (status: {status_code})")]
ApiError {
status_code: u16,
message: String,
provider: String,
},
#[error("Network error: {0}")]
Network(String),
#[error("Provider authentication error: {0}")]
Authentication(String),
#[error("Provider rate limit: {0}")]
RateLimit(String),
#[error("Provider quota exceeded: {0}")]
QuotaExceeded(String),
#[error("Model not found: {0}")]
ModelNotFound(String),
#[error("Invalid request: {0}")]
InvalidRequest(String),
#[error("Provider timeout: {0}")]
Timeout(String),
#[error("Provider unavailable: {0}")]
Unavailable(String),
#[error("Provider configuration error: {0}")]
Configuration(String),
#[error("Unknown provider error: {0}")]
Unknown(String),
}
impl ResponseError for GatewayError {
fn error_response(&self) -> HttpResponse {
let (status_code, error_code, message) = match self {
GatewayError::Config(_) => (
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
"CONFIG_ERROR",
self.to_string(),
),
GatewayError::Database(_) => (
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
"DATABASE_ERROR",
"Database operation failed".to_string(),
),
GatewayError::Redis(_) => (
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
"CACHE_ERROR",
"Cache operation failed".to_string(),
),
GatewayError::Auth(_) => (
actix_web::http::StatusCode::UNAUTHORIZED,
"AUTH_ERROR",
self.to_string(),
),
GatewayError::Authorization(_) => (
actix_web::http::StatusCode::FORBIDDEN,
"AUTHORIZATION_ERROR",
self.to_string(),
),
GatewayError::Provider(provider_error) => match provider_error {
ProviderError::ApiError { status_code, .. } => (
actix_web::http::StatusCode::from_u16(*status_code)
.unwrap_or(actix_web::http::StatusCode::BAD_GATEWAY),
"PROVIDER_API_ERROR",
provider_error.to_string(),
),
ProviderError::RateLimit(_) => (
actix_web::http::StatusCode::TOO_MANY_REQUESTS,
"PROVIDER_RATE_LIMIT",
provider_error.to_string(),
),
ProviderError::QuotaExceeded(_) => (
actix_web::http::StatusCode::PAYMENT_REQUIRED,
"PROVIDER_QUOTA_EXCEEDED",
provider_error.to_string(),
),
ProviderError::ModelNotFound(_) => (
actix_web::http::StatusCode::NOT_FOUND,
"MODEL_NOT_FOUND",
provider_error.to_string(),
),
ProviderError::InvalidRequest(_) => (
actix_web::http::StatusCode::BAD_REQUEST,
"INVALID_REQUEST",
provider_error.to_string(),
),
ProviderError::Timeout(_) => (
actix_web::http::StatusCode::GATEWAY_TIMEOUT,
"PROVIDER_TIMEOUT",
provider_error.to_string(),
),
ProviderError::Unavailable(_) => (
actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
"PROVIDER_UNAVAILABLE",
provider_error.to_string(),
),
_ => (
actix_web::http::StatusCode::BAD_GATEWAY,
"PROVIDER_ERROR",
provider_error.to_string(),
),
},
GatewayError::RateLimit(_) => (
actix_web::http::StatusCode::TOO_MANY_REQUESTS,
"RATE_LIMIT_EXCEEDED",
self.to_string(),
),
GatewayError::Validation(_) => (
actix_web::http::StatusCode::BAD_REQUEST,
"VALIDATION_ERROR",
self.to_string(),
),
GatewayError::NotFound(_) => (
actix_web::http::StatusCode::NOT_FOUND,
"NOT_FOUND",
self.to_string(),
),
GatewayError::Conflict(_) => (
actix_web::http::StatusCode::CONFLICT,
"CONFLICT",
self.to_string(),
),
GatewayError::BadRequest(_) => (
actix_web::http::StatusCode::BAD_REQUEST,
"BAD_REQUEST",
self.to_string(),
),
GatewayError::Timeout(_) => (
actix_web::http::StatusCode::REQUEST_TIMEOUT,
"TIMEOUT",
self.to_string(),
),
GatewayError::ServiceUnavailable(_) => (
actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
"SERVICE_UNAVAILABLE",
self.to_string(),
),
GatewayError::CircuitBreaker(_) => (
actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
"CIRCUIT_BREAKER_OPEN",
self.to_string(),
),
GatewayError::Network(_) => (
actix_web::http::StatusCode::BAD_GATEWAY,
"NETWORK_ERROR",
self.to_string(),
),
GatewayError::Parsing(_) => (
actix_web::http::StatusCode::BAD_REQUEST,
"PARSING_ERROR",
self.to_string(),
),
GatewayError::Alert(_) => (
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
"ALERT_ERROR",
self.to_string(),
),
GatewayError::NotImplemented(_) => (
actix_web::http::StatusCode::NOT_IMPLEMENTED,
"NOT_IMPLEMENTED",
self.to_string(),
),
GatewayError::Unauthorized(_) => (
actix_web::http::StatusCode::UNAUTHORIZED,
"UNAUTHORIZED",
self.to_string(),
),
GatewayError::Forbidden(_) => (
actix_web::http::StatusCode::FORBIDDEN,
"FORBIDDEN",
self.to_string(),
),
GatewayError::External(_) => (
actix_web::http::StatusCode::BAD_GATEWAY,
"EXTERNAL_ERROR",
self.to_string(),
),
GatewayError::InvalidRequest(_) => (
actix_web::http::StatusCode::BAD_REQUEST,
"INVALID_REQUEST",
self.to_string(),
),
GatewayError::NoProvidersAvailable(_) => (
actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
"NO_PROVIDERS_AVAILABLE",
self.to_string(),
),
GatewayError::ProviderNotFound(_) => (
actix_web::http::StatusCode::NOT_FOUND,
"PROVIDER_NOT_FOUND",
self.to_string(),
),
GatewayError::NoProvidersForModel(_) => (
actix_web::http::StatusCode::BAD_REQUEST,
"NO_PROVIDERS_FOR_MODEL",
self.to_string(),
),
GatewayError::NoHealthyProviders(_) => (
actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
"NO_HEALTHY_PROVIDERS",
self.to_string(),
),
_ => (
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
"INTERNAL_ERROR",
"An internal error occurred".to_string(),
),
};
let error_response = ErrorResponse {
error: ErrorDetail {
code: error_code.to_string(),
message,
timestamp: chrono::Utc::now().timestamp(),
request_id: None, },
};
HttpResponse::build(status_code).json(error_response)
}
}
#[derive(serde::Serialize)]
pub struct ErrorResponse {
pub error: ErrorDetail,
}
#[derive(serde::Serialize)]
pub struct ErrorDetail {
pub code: String,
pub message: String,
pub timestamp: i64,
pub request_id: Option<String>,
}
#[allow(dead_code)]
impl GatewayError {
pub fn auth<S: Into<String>>(message: S) -> Self {
Self::Auth(message.into())
}
pub fn authorization<S: Into<String>>(message: S) -> Self {
Self::Authorization(message.into())
}
pub fn bad_request<S: Into<String>>(message: S) -> Self {
Self::BadRequest(message.into())
}
pub fn not_found<S: Into<String>>(message: S) -> Self {
Self::NotFound(message.into())
}
pub fn conflict<S: Into<String>>(message: S) -> Self {
Self::Conflict(message.into())
}
pub fn internal<S: Into<String>>(message: S) -> Self {
Self::Internal(message.into())
}
pub fn validation<S: Into<String>>(message: S) -> Self {
Self::Validation(message.into())
}
pub fn rate_limit<S: Into<String>>(message: S) -> Self {
Self::RateLimit(message.into())
}
pub fn timeout<S: Into<String>>(message: S) -> Self {
Self::Timeout(message.into())
}
pub fn service_unavailable<S: Into<String>>(message: S) -> Self {
Self::ServiceUnavailable(message.into())
}
pub fn server<S: Into<String>>(message: S) -> Self {
Self::Internal(message.into())
}
pub fn network<S: Into<String>>(message: S) -> Self {
Self::Network(message.into())
}
pub fn external_service<S: Into<String>>(message: S) -> Self {
Self::Internal(message.into())
}
pub fn invalid_request<S: Into<String>>(message: S) -> Self {
Self::BadRequest(message.into())
}
pub fn parsing<S: Into<String>>(message: S) -> Self {
Self::Parsing(message.into())
}
pub fn alert<S: Into<String>>(message: S) -> Self {
Self::Alert(message.into())
}
pub fn not_implemented<S: Into<String>>(message: S) -> Self {
Self::NotImplemented(message.into())
}
pub fn unauthorized<S: Into<String>>(message: S) -> Self {
Self::Unauthorized(message.into())
}
pub fn forbidden<S: Into<String>>(message: S) -> Self {
Self::Forbidden(message.into())
}
pub fn external<S: Into<String>>(message: S) -> Self {
Self::External(message.into())
}
pub fn invalid_request_error<S: Into<String>>(message: S) -> Self {
Self::InvalidRequest(message.into())
}
pub fn no_providers_available<S: Into<String>>(message: S) -> Self {
Self::NoProvidersAvailable(message.into())
}
pub fn provider_not_found<S: Into<String>>(message: S) -> Self {
Self::ProviderNotFound(message.into())
}
pub fn no_providers_for_model<S: Into<String>>(message: S) -> Self {
Self::NoProvidersForModel(message.into())
}
pub fn no_healthy_providers<S: Into<String>>(message: S) -> Self {
Self::NoHealthyProviders(message.into())
}
}
#[allow(dead_code)]
impl ProviderError {
pub fn api_error<S: Into<String>>(status_code: u16, message: S, provider: S) -> Self {
Self::ApiError {
status_code,
message: message.into(),
provider: provider.into(),
}
}
pub fn rate_limit<S: Into<String>>(message: S) -> Self {
Self::RateLimit(message.into())
}
pub fn quota_exceeded<S: Into<String>>(message: S) -> Self {
Self::QuotaExceeded(message.into())
}
pub fn model_not_found<S: Into<String>>(message: S) -> Self {
Self::ModelNotFound(message.into())
}
pub fn invalid_request<S: Into<String>>(message: S) -> Self {
Self::InvalidRequest(message.into())
}
pub fn timeout<S: Into<String>>(message: S) -> Self {
Self::Timeout(message.into())
}
pub fn unavailable<S: Into<String>>(message: S) -> Self {
Self::Unavailable(message.into())
}
}
impl From<crate::core::providers::ProviderError> for GatewayError {
fn from(err: crate::core::providers::ProviderError) -> Self {
match err {
crate::core::providers::ProviderError::Network(msg) => GatewayError::network(msg),
crate::core::providers::ProviderError::Authentication(msg) => GatewayError::Auth(msg),
crate::core::providers::ProviderError::RateLimit(msg) => GatewayError::RateLimit(msg),
crate::core::providers::ProviderError::RateLimited(msg) => GatewayError::RateLimit(msg),
crate::core::providers::ProviderError::InvalidRequest(msg) => {
GatewayError::BadRequest(msg)
}
crate::core::providers::ProviderError::ModelNotFound(msg) => {
GatewayError::NotFound(msg)
}
crate::core::providers::ProviderError::Parsing(msg) => GatewayError::parsing(msg),
crate::core::providers::ProviderError::Timeout(msg) => GatewayError::Timeout(msg),
crate::core::providers::ProviderError::Unavailable(msg) => {
GatewayError::ServiceUnavailable(msg)
}
crate::core::providers::ProviderError::Unknown(msg) => GatewayError::Internal(msg),
crate::core::providers::ProviderError::Other(msg) => GatewayError::Internal(msg),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_creation() {
let error = GatewayError::auth("Invalid token");
assert!(matches!(error, GatewayError::Auth(_)));
let error = GatewayError::bad_request("Missing parameter");
assert!(matches!(error, GatewayError::BadRequest(_)));
}
#[test]
fn test_provider_error_creation() {
let error = ProviderError::api_error(400, "Bad request", "openai");
assert!(matches!(error, ProviderError::ApiError { .. }));
let error = ProviderError::rate_limit("Too many requests");
assert!(matches!(error, ProviderError::RateLimit(_)));
}
}