tonic/service/
router.rs
1use crate::{
2 body::{boxed, BoxBody},
3 metadata::GRPC_CONTENT_TYPE,
4 server::NamedService,
5 Status,
6};
7use http::{HeaderValue, Request, Response};
8use std::{
9 convert::Infallible,
10 fmt,
11 future::Future,
12 pin::Pin,
13 task::{ready, Context, Poll},
14};
15use tower::{Service, ServiceExt};
16
17#[derive(Debug, Clone)]
19pub struct Routes {
20 router: axum::Router,
21}
22
23#[derive(Debug, Default, Clone)]
24pub struct RoutesBuilder {
26 routes: Option<Routes>,
27}
28
29impl RoutesBuilder {
30 pub fn add_service<S>(&mut self, svc: S) -> &mut Self
32 where
33 S: Service<Request<BoxBody>, Response = Response<BoxBody>, Error = Infallible>
34 + NamedService
35 + Clone
36 + Send
37 + 'static,
38 S::Future: Send + 'static,
39 S::Error: Into<crate::Error> + Send,
40 {
41 let routes = self.routes.take().unwrap_or_default();
42 self.routes.replace(routes.add_service(svc));
43 self
44 }
45
46 pub fn routes(self) -> Routes {
48 self.routes.unwrap_or_default()
49 }
50}
51
52impl Default for Routes {
53 fn default() -> Self {
54 Self {
55 router: axum::Router::new().fallback(unimplemented),
56 }
57 }
58}
59
60impl Routes {
61 pub fn new<S>(svc: S) -> Self
63 where
64 S: Service<Request<BoxBody>, Response = Response<BoxBody>, Error = Infallible>
65 + NamedService
66 + Clone
67 + Send
68 + 'static,
69 S::Future: Send + 'static,
70 S::Error: Into<crate::Error> + Send,
71 {
72 Self::default().add_service(svc)
73 }
74
75 pub fn builder() -> RoutesBuilder {
77 RoutesBuilder::default()
78 }
79
80 pub fn add_service<S>(mut self, svc: S) -> Self
82 where
83 S: Service<Request<BoxBody>, Response = Response<BoxBody>, Error = Infallible>
84 + NamedService
85 + Clone
86 + Send
87 + 'static,
88 S::Future: Send + 'static,
89 S::Error: Into<crate::Error> + Send,
90 {
91 self.router = self.router.route_service(
92 &format!("/{}/*rest", S::NAME),
93 svc.map_request(|req: Request<axum::body::Body>| req.map(boxed)),
94 );
95 self
96 }
97
98 pub fn prepare(self) -> Self {
102 Self {
103 router: self.router.with_state(()),
104 }
105 }
106
107 #[deprecated(since = "0.12.2", note = "Use `Routes::into_axum_router` instead.")]
109 pub fn into_router(self) -> axum::Router {
110 self.into_axum_router()
111 }
112
113 pub fn into_axum_router(self) -> axum::Router {
115 self.router
116 }
117}
118
119impl From<axum::Router> for Routes {
120 fn from(router: axum::Router) -> Self {
121 Self { router }
122 }
123}
124
125async fn unimplemented() -> impl axum::response::IntoResponse {
126 let status = http::StatusCode::OK;
127 let headers = [
128 (Status::GRPC_STATUS, HeaderValue::from_static("12")),
129 (http::header::CONTENT_TYPE, GRPC_CONTENT_TYPE),
130 ];
131 (status, headers)
132}
133
134impl Service<Request<BoxBody>> for Routes {
135 type Response = Response<BoxBody>;
136 type Error = crate::Error;
137 type Future = RoutesFuture;
138
139 #[inline]
140 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
141 Poll::Ready(Ok(()))
142 }
143
144 fn call(&mut self, req: Request<BoxBody>) -> Self::Future {
145 RoutesFuture(self.router.call(req))
146 }
147}
148
149pub struct RoutesFuture(axum::routing::future::RouteFuture<Infallible>);
150
151impl fmt::Debug for RoutesFuture {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 f.debug_tuple("RoutesFuture").finish()
154 }
155}
156
157impl Future for RoutesFuture {
158 type Output = Result<Response<BoxBody>, crate::Error>;
159
160 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
161 match ready!(Pin::new(&mut self.as_mut().0).poll(cx)) {
162 Ok(res) => Ok(res.map(boxed)).into(),
163 #[allow(unreachable_patterns)]
166 Err(err) => match err {},
167 }
168 }
169}