159 lines
4.5 KiB
Rust
159 lines
4.5 KiB
Rust
use std::fmt;
|
|
use axum::http::StatusCode;
|
|
use axum::Json;
|
|
use axum::response::{IntoResponse, Response};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
pub type SirenResult<T> = Result<T, Error>;
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct Error {
|
|
pub status: u16,
|
|
pub details: String,
|
|
}
|
|
|
|
impl Error {
|
|
pub fn new(error_status_code: u16, error_message: String) -> Self {
|
|
Self {
|
|
status: error_status_code,
|
|
details: error_message,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Error {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.write_str(self.details.as_str())
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for Error {
|
|
fn description(&self) -> &str {
|
|
&self.details
|
|
}
|
|
}
|
|
|
|
impl IntoResponse for Error {
|
|
fn into_response(self) -> Response {
|
|
let status = StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
|
|
|
|
// Create a JSON response with the structured error
|
|
let body = Json(serde_json::json!({
|
|
"error": {
|
|
"status": self.status,
|
|
"details": self.details,
|
|
}
|
|
}));
|
|
|
|
// Return the response with the proper status and error body
|
|
(status, body).into_response()
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for Error {
|
|
fn from(error: std::io::Error) -> Self {
|
|
Self::new(500, format!("Unknown io error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<StatusCode> for Error {
|
|
fn from(status: StatusCode) -> Self {
|
|
Error {
|
|
status: status.as_u16(),
|
|
details: status
|
|
.canonical_reason()
|
|
.unwrap_or("Unknown error")
|
|
.to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<std::string::FromUtf8Error> for Error {
|
|
fn from(error: std::string::FromUtf8Error) -> Self {
|
|
Self::new(500, format!("Unknown from utf8 error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<sqlx::Error> for Error {
|
|
fn from(error: sqlx::Error) -> Self {
|
|
match error {
|
|
sqlx::Error::RowNotFound => Error::new(404, "Not found".to_string()),
|
|
sqlx::Error::ColumnIndexOutOfBounds { .. } => Error::new(422, error.to_string()),
|
|
sqlx::Error::ColumnNotFound { .. } => Error::new(422, error.to_string()),
|
|
sqlx::Error::ColumnDecode { .. } => Error::new(422, error.to_string()),
|
|
sqlx::Error::Decode(_) => Error::new(422, error.to_string()),
|
|
sqlx::Error::PoolTimedOut => Error::new(503, error.to_string()),
|
|
sqlx::Error::PoolClosed => Error::new(503, error.to_string()),
|
|
sqlx::Error::Tls(_) => Error::new(500, error.to_string()),
|
|
sqlx::Error::Io(_) => Error::new(500, error.to_string()),
|
|
sqlx::Error::Protocol(_) => Error::new(500, error.to_string()),
|
|
sqlx::Error::Configuration(_) => Error::new(500, error.to_string()),
|
|
sqlx::Error::AnyDriverError(_) => Error::new(500, error.to_string()),
|
|
sqlx::Error::Database(err) => {
|
|
if let Some(code) = err.code() {
|
|
match code.trim() {
|
|
// Unique violation
|
|
"23505" => return Error::new(409, err.to_string()),
|
|
_ => (),
|
|
}
|
|
}
|
|
Error::new(500, err.to_string())
|
|
}
|
|
sqlx::Error::Migrate(_) => Error::new(500, error.to_string()),
|
|
sqlx::Error::TypeNotFound { type_name } => {
|
|
Error::new(500, format!("Type not found: {}", type_name))
|
|
}
|
|
sqlx::Error::WorkerCrashed => Error::new(500, error.to_string()),
|
|
_ => Error::new(500, error.to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<sqlx::migrate::MigrateError> for Error {
|
|
fn from(error: sqlx::migrate::MigrateError) -> Self {
|
|
Error::new(500, error.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<reqwest::Error> for Error {
|
|
fn from(error: reqwest::Error) -> Self {
|
|
Self::new(500, format!("Unknown reqwest error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<serde_json::Error> for Error {
|
|
fn from(error: serde_json::Error) -> Self {
|
|
Self::new(500, format!("Unknown serde_json error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<serenity::Error> for Error {
|
|
fn from(error: serenity::Error) -> Self {
|
|
Self::new(500, format!("Unknown serenity error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<redis::RedisError> for Error {
|
|
fn from(error: redis::RedisError) -> Self {
|
|
Self::new(500, format!("Unknown redis error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<uuid::Error> for Error {
|
|
fn from(error: uuid::Error) -> Self {
|
|
Self::new(500, format!("Unknown uuid error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<std::env::VarError> for Error {
|
|
fn from(error: std::env::VarError) -> Self {
|
|
Self::new(500, format!("Unknown env error: {}", error))
|
|
}
|
|
}
|
|
|
|
impl From<songbird::error::JoinError> for Error {
|
|
fn from(error: songbird::error::JoinError) -> Self {
|
|
Self::new(500, format!("Unable to join channel: {}", error))
|
|
}
|
|
}
|