~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/zkwid

0
0
main
92 lines · 2.5 KB Raw History
use axum::Json;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};

#[derive(Debug, Clone, PartialEq)]
pub struct XrpcError {
    pub status: StatusCode,
    pub error: String,
    pub message: String,
}

impl XrpcError {
    pub fn new(status: StatusCode, error: impl Into<String>, message: impl Into<String>) -> Self {
        XrpcError {
            status,
            error: error.into(),
            message: message.into(),
        }
    }

    pub fn bad_request(error: impl Into<String>, message: impl Into<String>) -> Self {
        Self::new(StatusCode::BAD_REQUEST, error, message)
    }

    pub fn invalid_request(message: impl Into<String>) -> Self {
        Self::bad_request("InvalidRequest", message)
    }

    pub fn auth_required(message: impl Into<String>) -> Self {
        Self::new(StatusCode::UNAUTHORIZED, "AuthRequired", message)
    }

    pub fn invalid_token(message: impl Into<String>) -> Self {
        Self::new(StatusCode::UNAUTHORIZED, "InvalidToken", message)
    }

    pub fn forbidden(error: impl Into<String>, message: impl Into<String>) -> Self {
        Self::new(StatusCode::FORBIDDEN, error, message)
    }

    pub fn not_found(error: impl Into<String>, message: impl Into<String>) -> Self {
        Self::new(StatusCode::NOT_FOUND, error, message)
    }

    pub fn upstream(message: impl Into<String>) -> Self {
        Self::new(StatusCode::BAD_GATEWAY, "UpstreamFailure", message)
    }

    pub fn internal(message: impl Into<String>) -> Self {
        Self::new(
            StatusCode::INTERNAL_SERVER_ERROR,
            "InternalServerError",
            message,
        )
    }
}

impl std::fmt::Display for XrpcError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{} {}: {}",
            self.status.as_u16(),
            self.error,
            self.message
        )
    }
}

impl std::error::Error for XrpcError {}

impl From<anyhow::Error> for XrpcError {
    fn from(error: anyhow::Error) -> Self {
        match error.downcast::<XrpcError>() {
            Ok(xrpc) => xrpc,
            Err(error) => {
                tracing::warn!("internal error: {error:#}");
                Self::internal(format!("{error:#}"))
            }
        }
    }
}

impl IntoResponse for XrpcError {
    fn into_response(self) -> Response {
        (
            self.status,
            Json(serde_json::json!({ "error": self.error, "message": self.message })),
        )
            .into_response()
    }
}