193 lines
4.8 KiB
Rust
193 lines
4.8 KiB
Rust
use crate::model::processing::PackError;
|
|
use axum::http::StatusCode;
|
|
use axum::response::{IntoResponse, Response};
|
|
use axum::Json;
|
|
use magnetar_common::util::FediverseTagParseError;
|
|
use magnetar_model::{CalckeyCacheError, CalckeyDbError};
|
|
use serde::Serialize;
|
|
use serde_json::json;
|
|
use std::fmt::{Display, Formatter};
|
|
use thiserror::Error;
|
|
|
|
pub mod auth;
|
|
pub mod extractors;
|
|
pub mod pagination;
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
#[repr(transparent)]
|
|
pub struct ErrorCode(pub String);
|
|
|
|
// This janky hack allows us to use `.error_code()` on enums with strum::IntoStaticStr
|
|
pub trait IntoErrorCode {
|
|
fn error_code<'a, 'b: 'a>(&'a self) -> ErrorCode
|
|
where
|
|
&'a Self: Into<&'b str>;
|
|
}
|
|
|
|
impl<T: ?Sized> IntoErrorCode for T {
|
|
fn error_code<'a, 'b: 'a>(&'a self) -> ErrorCode
|
|
where
|
|
&'a Self: Into<&'b str>,
|
|
{
|
|
ErrorCode(<&Self as Into<&'b str>>::into(self).to_string())
|
|
}
|
|
}
|
|
|
|
impl ErrorCode {
|
|
pub fn join(&self, other: &str) -> Self {
|
|
Self(format!("{}:{}", other, self.0))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub struct ApiError {
|
|
pub status: StatusCode,
|
|
pub code: ErrorCode,
|
|
pub message: String,
|
|
}
|
|
|
|
impl Display for ApiError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"ApiError[status = \"{}\", code = \"{:?}\"]: \"{}\"",
|
|
self.status, self.code, self.message
|
|
)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct AccessForbidden(pub String);
|
|
|
|
impl From<&AccessForbidden> for &str {
|
|
fn from(_: &AccessForbidden) -> &'static str {
|
|
"AccessForbidden"
|
|
}
|
|
}
|
|
|
|
impl IntoResponse for ApiError {
|
|
fn into_response(self) -> Response {
|
|
(
|
|
self.status,
|
|
Json(json!({
|
|
"status": self.status.as_u16(),
|
|
"code": self.code,
|
|
"message": self.message,
|
|
})),
|
|
)
|
|
.into_response()
|
|
}
|
|
}
|
|
|
|
impl From<AccessForbidden> for ApiError {
|
|
fn from(err: AccessForbidden) -> Self {
|
|
Self {
|
|
status: StatusCode::FORBIDDEN,
|
|
code: err.error_code(),
|
|
message: if cfg!(debug_assertions) {
|
|
format!("Forbidden: {}", err.0)
|
|
} else {
|
|
"Forbidden".to_string()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<FediverseTagParseError> for ApiError {
|
|
fn from(err: FediverseTagParseError) -> Self {
|
|
Self {
|
|
status: StatusCode::BAD_REQUEST,
|
|
code: err.error_code(),
|
|
message: if cfg!(debug_assertions) {
|
|
format!("Fediverse tag parse error: {}", err)
|
|
} else {
|
|
"Fediverse tag parse error".to_string()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<CalckeyDbError> for ApiError {
|
|
fn from(err: CalckeyDbError) -> Self {
|
|
Self {
|
|
status: StatusCode::INTERNAL_SERVER_ERROR,
|
|
code: err.error_code(),
|
|
message: if cfg!(debug_assertions) {
|
|
format!("Database error: {}", err)
|
|
} else {
|
|
"Database error".to_string()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<CalckeyCacheError> for ApiError {
|
|
fn from(err: CalckeyCacheError) -> Self {
|
|
Self {
|
|
status: StatusCode::INTERNAL_SERVER_ERROR,
|
|
code: err.error_code(),
|
|
message: if cfg!(debug_assertions) {
|
|
format!("Cache error: {}", err)
|
|
} else {
|
|
"Cache error".to_string()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<PackError> for ApiError {
|
|
fn from(err: PackError) -> Self {
|
|
Self {
|
|
status: StatusCode::INTERNAL_SERVER_ERROR,
|
|
code: err.error_code(),
|
|
message: if cfg!(debug_assertions) {
|
|
format!("Data transformation error: {}", err)
|
|
} else {
|
|
"Data transformation error".to_string()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ObjectNotFound(pub String);
|
|
|
|
impl From<&ObjectNotFound> for &str {
|
|
fn from(_: &ObjectNotFound) -> Self {
|
|
"ObjectNotFound"
|
|
}
|
|
}
|
|
|
|
impl From<ObjectNotFound> for ApiError {
|
|
fn from(err: ObjectNotFound) -> Self {
|
|
Self {
|
|
status: StatusCode::NOT_FOUND,
|
|
code: err.error_code(),
|
|
message: if cfg!(debug_assertions) {
|
|
format!("Object not found: {}", err.0)
|
|
} else {
|
|
"Object not found".to_string()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ArgumentOutOfRange(pub String);
|
|
|
|
impl From<&ArgumentOutOfRange> for &str {
|
|
fn from(_: &ArgumentOutOfRange) -> Self {
|
|
"ArgumentOutOfRange"
|
|
}
|
|
}
|
|
|
|
impl From<ArgumentOutOfRange> for ApiError {
|
|
fn from(err: ArgumentOutOfRange) -> Self {
|
|
Self {
|
|
status: StatusCode::BAD_REQUEST,
|
|
code: err.error_code(),
|
|
message: format!("Argument out of range: {}", err.0),
|
|
}
|
|
}
|
|
}
|