xref: /tonic/tonic/src/service/router.rs (revision afb9df89)
1 use crate::{body::Body, server::NamedService, Status};
2 use http::{Request, Response};
3 use std::{
4     convert::Infallible,
5     fmt,
6     future::Future,
7     pin::Pin,
8     task::{ready, Context, Poll},
9 };
10 use tower::{Service, ServiceExt};
11 
12 /// A [`Service`] router.
13 #[derive(Debug, Clone)]
14 pub struct Routes {
15     router: axum::Router,
16 }
17 
18 #[derive(Debug, Default, Clone)]
19 /// Allows adding new services to routes by passing a mutable reference to this builder.
20 pub struct RoutesBuilder {
21     routes: Option<Routes>,
22 }
23 
24 impl RoutesBuilder {
25     /// Add a new service.
add_service<S>(&mut self, svc: S) -> &mut Self where S: Service<Request<Body>, Error = Infallible> + NamedService + Clone + Send + Sync + 'static, S::Response: axum::response::IntoResponse, S::Future: Send + 'static,26     pub fn add_service<S>(&mut self, svc: S) -> &mut Self
27     where
28         S: Service<Request<Body>, Error = Infallible>
29             + NamedService
30             + Clone
31             + Send
32             + Sync
33             + 'static,
34         S::Response: axum::response::IntoResponse,
35         S::Future: Send + 'static,
36     {
37         let routes = self.routes.take().unwrap_or_default();
38         self.routes.replace(routes.add_service(svc));
39         self
40     }
41 
42     /// Returns the routes with added services or empty [`Routes`] if no service was added
routes(self) -> Routes43     pub fn routes(self) -> Routes {
44         self.routes.unwrap_or_default()
45     }
46 }
47 
48 impl Default for Routes {
default() -> Self49     fn default() -> Self {
50         Self {
51             router: axum::Router::new().fallback(unimplemented),
52         }
53     }
54 }
55 
56 impl Routes {
57     /// Create a new routes with `svc` already added to it.
new<S>(svc: S) -> Self where S: Service<Request<Body>, Error = Infallible> + NamedService + Clone + Send + Sync + 'static, S::Response: axum::response::IntoResponse, S::Future: Send + 'static,58     pub fn new<S>(svc: S) -> Self
59     where
60         S: Service<Request<Body>, Error = Infallible>
61             + NamedService
62             + Clone
63             + Send
64             + Sync
65             + 'static,
66         S::Response: axum::response::IntoResponse,
67         S::Future: Send + 'static,
68     {
69         Self::default().add_service(svc)
70     }
71 
72     /// Create a new empty builder.
builder() -> RoutesBuilder73     pub fn builder() -> RoutesBuilder {
74         RoutesBuilder::default()
75     }
76 
77     /// Add a new service.
add_service<S>(mut self, svc: S) -> Self where S: Service<Request<Body>, Error = Infallible> + NamedService + Clone + Send + Sync + 'static, S::Response: axum::response::IntoResponse, S::Future: Send + 'static,78     pub fn add_service<S>(mut self, svc: S) -> Self
79     where
80         S: Service<Request<Body>, Error = Infallible>
81             + NamedService
82             + Clone
83             + Send
84             + Sync
85             + 'static,
86         S::Response: axum::response::IntoResponse,
87         S::Future: Send + 'static,
88     {
89         self.router = self.router.route_service(
90             &format!("/{}/{{*rest}}", S::NAME),
91             svc.map_request(|req: Request<axum::body::Body>| req.map(Body::new)),
92         );
93         self
94     }
95 
96     /// This makes axum perform update some internals of the router that improves perf.
97     ///
98     /// See <https://docs.rs/axum/latest/axum/routing/struct.Router.html#a-note-about-performance>
prepare(self) -> Self99     pub fn prepare(self) -> Self {
100         Self {
101             router: self.router.with_state(()),
102         }
103     }
104 
105     /// Convert this `Routes` into an [`axum::Router`].
into_axum_router(self) -> axum::Router106     pub fn into_axum_router(self) -> axum::Router {
107         self.router
108     }
109 
110     /// Get a mutable reference to the [`axum::Router`].
axum_router_mut(&mut self) -> &mut axum::Router111     pub fn axum_router_mut(&mut self) -> &mut axum::Router {
112         &mut self.router
113     }
114 }
115 
116 impl From<Routes> for RoutesBuilder {
from(routes: Routes) -> Self117     fn from(routes: Routes) -> Self {
118         Self {
119             routes: Some(routes),
120         }
121     }
122 }
123 
124 impl From<axum::Router> for RoutesBuilder {
from(router: axum::Router) -> Self125     fn from(router: axum::Router) -> Self {
126         Self {
127             routes: Some(router.into()),
128         }
129     }
130 }
131 
132 impl From<axum::Router> for Routes {
from(router: axum::Router) -> Self133     fn from(router: axum::Router) -> Self {
134         Self { router }
135     }
136 }
137 
unimplemented() -> Response<Body>138 async fn unimplemented() -> Response<Body> {
139     let (parts, ()) = Status::unimplemented("").into_http::<()>().into_parts();
140     Response::from_parts(parts, Body::empty())
141 }
142 
143 impl<B> Service<Request<B>> for Routes
144 where
145     B: http_body::Body<Data = bytes::Bytes> + Send + 'static,
146     B::Error: Into<crate::BoxError>,
147 {
148     type Response = Response<Body>;
149     type Error = crate::BoxError;
150     type Future = RoutesFuture;
151 
152     #[inline]
poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>>153     fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
154         Poll::Ready(Ok(()))
155     }
156 
call(&mut self, req: Request<B>) -> Self::Future157     fn call(&mut self, req: Request<B>) -> Self::Future {
158         RoutesFuture(self.router.call(req.map(axum::body::Body::new)))
159     }
160 }
161 
162 pub struct RoutesFuture(axum::routing::future::RouteFuture<Infallible>);
163 
164 impl fmt::Debug for RoutesFuture {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result165     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166         f.debug_tuple("RoutesFuture").finish()
167     }
168 }
169 
170 impl Future for RoutesFuture {
171     type Output = Result<Response<Body>, crate::BoxError>;
172 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>173     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
174         match ready!(Pin::new(&mut self.as_mut().0).poll(cx)) {
175             Ok(res) => Ok(res.map(Body::new)).into(),
176             // NOTE: This pattern is not needed from Rust 1.82.
177             // See https://github.com/rust-lang/rust/pull/122792.
178             #[allow(unreachable_patterns)]
179             Err(err) => match err {},
180         }
181     }
182 }
183