Skip to main content

viz_tower/
lib.rs

1//! An adapter that makes a tower [`Service`] into a [`Handler`].
2
3use tower::{Service, ServiceExt};
4use viz_core::{Body, BoxError, Bytes, Error, Handler, HttpBody, Request, Response, Result};
5
6mod service;
7pub use service::HandlerService;
8
9mod middleware;
10pub use middleware::Middleware;
11
12mod layer;
13pub use layer::Layered;
14
15/// Converts a tower [`Service`] into a [`Handler`].
16#[derive(Clone, Debug)]
17pub struct ServiceHandler<S>(S);
18
19impl<S> ServiceHandler<S> {
20    /// Creates a new [`ServiceHandler`].
21    pub const fn new(s: S) -> Self {
22        Self(s)
23    }
24}
25
26#[viz_core::async_trait]
27impl<O, S> Handler<Request> for ServiceHandler<S>
28where
29    O: HttpBody + Send + 'static,
30    O::Data: Into<Bytes>,
31    O::Error: Into<BoxError>,
32    S: Service<Request, Response = Response<O>> + Send + Sync + Clone + 'static,
33    S::Future: Send,
34    S::Error: Into<BoxError>,
35{
36    type Output = Result<Response>;
37
38    async fn call(&self, req: Request) -> Self::Output {
39        self.0
40            .clone()
41            .oneshot(req)
42            .await
43            .map_err(Error::boxed)
44            .map(|resp| resp.map(Body::wrap))
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use std::{
52        sync::{
53            Arc,
54            atomic::{AtomicU64, Ordering},
55        },
56        time::Duration,
57    };
58    use tower::util::{MapErrLayer, MapRequestLayer, MapResponseLayer};
59    use tower::{ServiceBuilder, service_fn};
60    use tower_http::{
61        limit::RequestBodyLimitLayer,
62        request_id::{MakeRequestId, RequestId, SetRequestIdLayer},
63        timeout::TimeoutLayer,
64    };
65    use viz_core::{
66        Body, BoxHandler, Handler, HandlerExt, IntoResponse, Request, RequestExt, Response,
67    };
68
69    #[derive(Clone, Debug, Default)]
70    struct MyMakeRequestId {
71        counter: Arc<AtomicU64>,
72    }
73
74    impl MakeRequestId for MyMakeRequestId {
75        fn make_request_id<B>(&mut self, _: &Request<B>) -> Option<RequestId> {
76            let request_id = self
77                .counter
78                .fetch_add(1, Ordering::SeqCst)
79                .to_string()
80                .parse()
81                .unwrap();
82
83            Some(RequestId::new(request_id))
84        }
85    }
86
87    async fn hello(mut req: Request) -> Result<Response> {
88        let bytes = req.bytes().await?;
89        Ok(bytes.into_response())
90    }
91
92    #[tokio::test]
93    async fn tower_service_into_handler() {
94        let hello_svc = service_fn(hello);
95
96        let svc = ServiceBuilder::new()
97            .layer(RequestBodyLimitLayer::new(1))
98            .layer(MapErrLayer::new(Error::from))
99            .layer(SetRequestIdLayer::x_request_id(MyMakeRequestId::default()))
100            .layer(MapResponseLayer::new(IntoResponse::into_response))
101            .layer(MapRequestLayer::new(|req: Request<_>| req.map(Body::wrap)))
102            .layer(TimeoutLayer::new(Duration::from_secs(10)))
103            .service(hello_svc);
104
105        let r0 = Request::new(Body::Full("12".into()));
106        let h0 = ServiceHandler::new(svc);
107        assert!(h0.call(r0).await.is_err());
108
109        let r1 = Request::new(Body::Full("1".into()));
110        let b0: BoxHandler = h0.boxed();
111        assert!(b0.call(r1).await.is_ok());
112    }
113}