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