use std::future::Future;
use std::ops::ControlFlow;
use tower::BoxError;
use tower::ServiceBuilder;
use tower::buffer::BufferLayer;
use tower::layer::util::Stack;
use tower_service::Service;
use tracing::Span;
use self::map_first_graphql_response::MapFirstGraphqlResponseLayer;
use self::map_first_graphql_response::MapFirstGraphqlResponseService;
use crate::Context;
use crate::graphql;
use crate::layers::async_checkpoint::AsyncCheckpointLayer;
use crate::layers::async_checkpoint::OneShotAsyncCheckpointLayer;
use crate::layers::instrument::InstrumentLayer;
use crate::layers::map_future_with_request_data::MapFutureWithRequestDataLayer;
use crate::layers::map_future_with_request_data::MapFutureWithRequestDataService;
use crate::layers::sync_checkpoint::CheckpointLayer;
use crate::services::supergraph;
pub mod async_checkpoint;
pub mod instrument;
pub mod map_first_graphql_response;
pub mod map_future_with_request_data;
pub mod sync_checkpoint;
pub(crate) const DEFAULT_BUFFER_SIZE: usize = 20_000;
#[allow(clippy::type_complexity)]
pub trait ServiceBuilderExt<L>: Sized {
fn checkpoint<S, Request>(
self,
checkpoint_fn: impl Fn(
Request,
) -> Result<
ControlFlow<<S as Service<Request>>::Response, Request>,
<S as Service<Request>>::Error,
> + Send
+ Sync
+ 'static,
) -> ServiceBuilder<Stack<CheckpointLayer<S, Request>, L>>
where
S: Service<Request> + Send + 'static,
Request: Send + 'static,
S::Future: Send,
S::Response: Send + 'static,
S::Error: Into<BoxError> + Send + 'static,
{
self.layer(CheckpointLayer::new(checkpoint_fn))
}
fn checkpoint_async<F, S, Fut, Request>(
self,
async_checkpoint_fn: F,
) -> ServiceBuilder<Stack<AsyncCheckpointLayer<S, Fut, Request>, L>>
where
S: Service<Request, Error = BoxError> + Clone + Send + 'static,
Fut: Future<
Output = Result<ControlFlow<<S as Service<Request>>::Response, Request>, BoxError>,
>,
F: Fn(Request) -> Fut + Send + Sync + 'static,
{
self.layer(AsyncCheckpointLayer::new(async_checkpoint_fn))
}
fn oneshot_checkpoint_async<F, S, Fut, Request>(
self,
async_checkpoint_fn: F,
) -> ServiceBuilder<Stack<OneShotAsyncCheckpointLayer<S, Fut, Request>, L>>
where
S: Service<Request, Error = BoxError> + Send + 'static,
Fut: Future<
Output = Result<ControlFlow<<S as Service<Request>>::Response, Request>, BoxError>,
>,
F: Fn(Request) -> Fut + Send + Sync + 'static,
{
self.layer(OneShotAsyncCheckpointLayer::new(async_checkpoint_fn))
}
fn buffered<Request>(self) -> ServiceBuilder<Stack<BufferLayer<Request>, L>>;
fn instrument<F, Request>(
self,
span_fn: F,
) -> ServiceBuilder<Stack<InstrumentLayer<F, Request>, L>>
where
F: Fn(&Request) -> Span,
{
self.layer(InstrumentLayer::new(span_fn))
}
fn map_first_graphql_response<Callback>(
self,
callback: Callback,
) -> ServiceBuilder<Stack<MapFirstGraphqlResponseLayer<Callback>, L>>
where
Callback: FnOnce(
Context,
http::response::Parts,
graphql::Response,
) -> (http::response::Parts, graphql::Response)
+ Clone
+ Send
+ 'static,
{
self.layer(MapFirstGraphqlResponseLayer { callback })
}
fn map_future_with_request_data<RF, MF>(
self,
req_fn: RF,
map_fn: MF,
) -> ServiceBuilder<Stack<MapFutureWithRequestDataLayer<RF, MF>, L>> {
self.layer(MapFutureWithRequestDataLayer::new(req_fn, map_fn))
}
fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>>;
}
#[allow(clippy::type_complexity)]
impl<L> ServiceBuilderExt<L> for ServiceBuilder<L> {
fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>> {
ServiceBuilder::layer(self, layer)
}
fn buffered<Request>(self) -> ServiceBuilder<Stack<BufferLayer<Request>, L>> {
self.buffer(DEFAULT_BUFFER_SIZE)
}
}
pub trait ServiceExt<Request>: Service<Request> {
fn map_first_graphql_response<Callback>(
self,
callback: Callback,
) -> MapFirstGraphqlResponseService<Self, Callback>
where
Self: Sized + Service<Request, Response = supergraph::Response>,
<Self as Service<Request>>::Future: Send + 'static,
Callback: FnOnce(
Context,
http::response::Parts,
graphql::Response,
) -> (http::response::Parts, graphql::Response)
+ Clone
+ Send
+ 'static,
{
ServiceBuilder::new()
.map_first_graphql_response(callback)
.service(self)
}
fn map_future_with_request_data<RF, MF>(
self,
req_fn: RF,
map_fn: MF,
) -> MapFutureWithRequestDataService<Self, RF, MF>
where
Self: Sized,
RF: Clone,
MF: Clone,
{
MapFutureWithRequestDataService::new(self, req_fn, map_fn)
}
}
impl<T: ?Sized, Request> ServiceExt<Request> for T where T: Service<Request> {}