switchgear-service 0.1.2

Service layer and API implementations for Switchgear LNURL load balancer
Documentation
use crate::api::lnurl::{LnUrlError, LnUrlErrorStatus};
use crate::api::service::HasServiceErrorSource;
use axum::http::header::InvalidHeaderValue;
use axum::{
    http::StatusCode,
    response::{IntoResponse, Response},
};
use log::error;
use thiserror::Error;

#[macro_export]
macro_rules! lnurl_pay_error_from_service {
    ($error:expr) => {
        LnUrlPayServiceError::from_service_error(
            module_path!(),
            &format!("{}:{}", file!(), line!()),
            $error,
        )
    };
}

#[derive(Debug, Error, Clone)]
#[error("{status}: {message}")]
pub struct LnUrlPayServiceError {
    status: StatusCode,
    message: String,
}

impl LnUrlPayServiceError {
    pub fn not_found<E>(error: E) -> Self
    where
        E: std::fmt::Display,
    {
        Self {
            status: StatusCode::NOT_FOUND,
            message: error.to_string(),
        }
    }

    pub fn bad_request<E>(error: E) -> Self
    where
        E: std::fmt::Display,
    {
        Self {
            status: StatusCode::BAD_REQUEST,
            message: error.to_string(),
        }
    }

    pub fn internal_error<E>(service: &str, location: &str, error: E) -> Self
    where
        E: std::fmt::Display,
    {
        error!(target:service, "{error} at: {location}");
        Self {
            status: StatusCode::INTERNAL_SERVER_ERROR,
            message: error.to_string(),
        }
    }

    pub fn from_service_error<E>(service: &str, location: &str, error: E) -> Self
    where
        E: HasServiceErrorSource + std::fmt::Display,
    {
        error!(target:service, "{error} at: {location}");
        Self {
            status: error.get_service_error_source().to_http_status(),
            message: error.to_string(),
        }
    }
}

impl From<InvalidHeaderValue> for LnUrlPayServiceError {
    fn from(error: InvalidHeaderValue) -> Self {
        Self {
            status: StatusCode::INTERNAL_SERVER_ERROR,
            message: error.to_string(),
        }
    }
}

impl IntoResponse for LnUrlPayServiceError {
    fn into_response(self) -> Response {
        let reason = if self.status.is_server_error() {
            "internal server error".to_string()
        } else {
            self.message
        };
        let body = LnUrlError {
            status: LnUrlErrorStatus::Error,
            reason,
        };

        (self.status, axum::Json(body)).into_response()
    }
}