#![deny(clippy::unwrap_used, clippy::dbg_macro, clippy::unimplemented, clippy::todo, clippy::missing_safety_doc)]
#![warn(
clippy::missing_errors_doc,
clippy::indexing_slicing,
clippy::inline_always,
clippy::fn_params_excessive_bools,
missing_debug_implementations
)]
pub mod backend_service;
pub mod body;
pub mod extension;
pub mod extractor;
pub mod helper_layers;
pub mod listener;
pub mod service;
pub mod utils;
pub use backend_service::ArcHyperService;
pub use body::SgBody;
use extension::Reflect;
pub use extractor::Extract;
use hyper::{body::Bytes, Request, Response, StatusCode};
use std::{convert::Infallible, fmt};
pub use tokio_util::sync::CancellationToken;
pub use tower_layer::Layer;
use tower_layer::layer_fn;
pub type BoxResult<T> = Result<T, BoxError>;
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub type SgRequest = Request<SgBody>;
pub type SgResponse = Response<SgBody>;
pub trait SgRequestExt {
fn with_reflect(&mut self);
fn reflect_mut(&mut self) -> &mut Reflect;
fn reflect(&self) -> &Reflect;
#[cfg(feature = "ext-redis")]
fn get_redis_client_by_gateway_name(&self) -> Option<spacegate_ext_redis::RedisClient>;
fn extract<M: Extract>(&self) -> M;
fn defer_call<F>(&mut self, f: F)
where
F: FnOnce(SgRequest) -> SgRequest + Send + 'static;
}
impl SgRequestExt for SgRequest {
fn reflect_mut(&mut self) -> &mut Reflect {
self.extensions_mut().get_mut::<Reflect>().expect("reflect extension not found")
}
fn reflect(&self) -> &Reflect {
self.extensions().get::<Reflect>().expect("reflect extension not found")
}
fn with_reflect(&mut self) {
if self.extensions().get::<Reflect>().is_none() {
self.extensions_mut().insert(Reflect::new());
}
}
#[cfg(feature = "ext-redis")]
fn get_redis_client_by_gateway_name(&self) -> Option<spacegate_ext_redis::RedisClient> {
self.extensions().get::<extension::GatewayName>().and_then(|gateway_name| spacegate_ext_redis::RedisClientRepo::global().get(gateway_name))
}
fn extract<M: Extract>(&self) -> M {
M::extract(self)
}
fn defer_call<F>(&mut self, f: F)
where
F: FnOnce(SgRequest) -> SgRequest + Send + 'static,
{
let defer = self.extensions_mut().get_or_insert_default::<extension::Defer>();
defer.push_back(f);
}
}
pub trait SgResponseExt {
fn with_code_message(code: StatusCode, message: impl Into<Bytes>) -> Self;
fn bad_gateway<E: std::error::Error>(e: E) -> Self
where
Self: Sized,
{
let message = e.to_string();
let src = e.source();
let message = if let Some(src) = src { format!("{}:\n {}", message, src) } else { message };
Self::with_code_message(StatusCode::BAD_GATEWAY, message)
}
}
impl SgResponseExt for Response<SgBody> {
fn with_code_message(code: StatusCode, message: impl Into<Bytes>) -> Self {
let body = SgBody::full(message);
let mut resp = Response::builder().status(code).body(body).expect("response builder error");
resp.extensions_mut().insert(Reflect::new());
resp
}
}
pub struct BoxLayer {
boxed: Box<dyn Layer<ArcHyperService, Service = ArcHyperService> + Send + Sync + 'static>,
}
impl BoxLayer {
pub fn new<L>(inner_layer: L) -> Self
where
L: Layer<ArcHyperService> + Send + Sync + 'static,
L::Service: Clone + hyper::service::Service<Request<SgBody>, Response = Response<SgBody>, Error = Infallible> + Send + Sync + 'static,
<L::Service as hyper::service::Service<Request<SgBody>>>::Future: Send + 'static,
{
let layer = layer_fn(move |inner: ArcHyperService| {
let out = inner_layer.layer(inner);
ArcHyperService::new(out)
});
Self { boxed: Box::new(layer) }
}
#[must_use]
pub fn layer_shared(&self, inner: ArcHyperService) -> ArcHyperService {
self.boxed.layer(inner)
}
}
impl<S> Layer<S> for BoxLayer
where
S: hyper::service::Service<Request<SgBody>, Response = Response<SgBody>, Error = Infallible> + Send + Sync + 'static,
<S as hyper::service::Service<hyper::Request<SgBody>>>::Future: std::marker::Send,
{
type Service = ArcHyperService;
fn layer(&self, inner: S) -> Self::Service {
self.boxed.layer(ArcHyperService::new(inner))
}
}
impl fmt::Debug for BoxLayer {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("BoxLayer").finish()
}
}