use std::io;
use axum::{
Json,
http::StatusCode,
response::{IntoResponse, Response},
};
use serde::Serialize;
use crate::conflict::ReplicationConflict;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, EventError>;
#[derive(Debug, Error)]
pub enum EventError {
#[error("configuration error: {0}")]
Config(String),
#[error("token not found or inactive")]
InvalidToken,
#[error("token has expired")]
TokenExpired,
#[error("token write limit reached")]
TokenLimitReached,
#[error("unauthorized")]
Unauthorized,
#[error("aggregate not found")]
AggregateNotFound,
#[error("aggregate is archived and cannot accept new events")]
AggregateArchived,
#[error("schema already exists")]
SchemaExists,
#[error("schema not found")]
SchemaNotFound,
#[error("invalid schema: {0}")]
InvalidSchema(String),
#[error("schema violation: {0}")]
SchemaViolation(String),
#[error("storage error: {0}")]
Storage(String),
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("serialization error: {0}")]
Serialization(String),
#[error("{0}")]
Conflict(#[from] ReplicationConflict),
}
impl From<toml::de::Error> for EventError {
fn from(err: toml::de::Error) -> Self {
Self::Serialization(err.to_string())
}
}
impl From<toml::ser::Error> for EventError {
fn from(err: toml::ser::Error) -> Self {
Self::Serialization(err.to_string())
}
}
impl From<serde_json::Error> for EventError {
fn from(err: serde_json::Error) -> Self {
Self::Serialization(err.to_string())
}
}
#[derive(Serialize)]
struct ErrorBody<'a> {
message: &'a str,
}
impl IntoResponse for EventError {
fn into_response(self) -> Response {
let status = match self {
Self::Config(_) => StatusCode::BAD_REQUEST,
Self::InvalidToken | Self::Unauthorized => StatusCode::UNAUTHORIZED,
Self::TokenExpired => StatusCode::UNAUTHORIZED,
Self::TokenLimitReached | Self::AggregateArchived => StatusCode::FORBIDDEN,
Self::AggregateNotFound | Self::SchemaNotFound => StatusCode::NOT_FOUND,
Self::SchemaExists => StatusCode::CONFLICT,
Self::SchemaViolation(_) => StatusCode::BAD_REQUEST,
Self::Storage(_) | Self::Serialization(_) | Self::Io(_) => {
StatusCode::INTERNAL_SERVER_ERROR
}
Self::InvalidSchema(_) => StatusCode::BAD_REQUEST,
Self::Conflict(_) => StatusCode::CONFLICT,
};
let message = self.to_string();
(status, Json(ErrorBody { message: &message })).into_response()
}
}