use std::pin::Pin; use tracing_futures::Instrument; use http::{Request, Response}; /// A layer that wraps a service. This can be used to add additional information to the request, or response on top of some other service pub trait Layer: Send + Sync + 'static { /// Wrap a boxed service with this layer fn layer(&self, inner: BoxedService) -> BoxedService; } impl Layer for L where L: tower_layer::Layer + Sync + Send + 'static, L::Service: Service + Send + 'static, { fn layer(&self, inner: BoxedService) -> BoxedService { BoxedService(Box::new(self.layer(inner))) } } /// A service is a function that takes a request and returns an async response pub trait Service { /// Run the service and produce a future that resolves to a response fn run( &mut self, req: http::Request, ) -> Pin< Box< dyn std::future::Future< Output = Result, server_fn::ServerFnError>, > + Send, >, >; } impl Service for S where S: tower::Service, Response = Response>, S::Future: Send + 'static, S::Error: Into, { fn run( &mut self, req: http::Request, ) -> Pin< Box< dyn std::future::Future< Output = Result, server_fn::ServerFnError>, > + Send, >, > { let fut = self.call(req).instrument(tracing::trace_span!( "service", "{}", std::any::type_name::() )); Box::pin(async move { fut.await.map_err(|err| err.into()) }) } } /// A boxed service is a type-erased service that can be used without knowing the underlying type pub struct BoxedService(pub Box); impl tower::Service> for BoxedService { type Response = http::Response; type Error = server_fn::ServerFnError; type Future = Pin< Box< dyn std::future::Future< Output = Result, server_fn::ServerFnError>, > + Send, >, >; fn poll_ready( &mut self, _cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { Ok(()).into() } fn call(&mut self, req: Request) -> Self::Future { self.0.run(req) } }