xref: /tonic/tonic-build/src/server.rs (revision 8084f4ea)
1 use super::{Method, Service};
2 use crate::{generate_doc_comment, generate_doc_comments, naive_snake_case};
3 use proc_macro2::{Span, TokenStream};
4 use quote::quote;
5 use syn::{Ident, Lit, LitStr};
6 
7 /// Generate service for Server.
8 ///
9 /// This takes some `Service` and will generate a `TokenStream` that contains
10 /// a public module containing the server service and handler trait.
11 pub fn generate<T: Service>(
12     service: &T,
13     emit_package: bool,
14     proto_path: &str,
15     compile_well_known_types: bool,
16 ) -> TokenStream {
17     let methods = generate_methods(service, proto_path, compile_well_known_types);
18 
19     let server_service = quote::format_ident!("{}Server", service.name());
20     let server_trait = quote::format_ident!("{}", service.name());
21     let server_mod = quote::format_ident!("{}_server", naive_snake_case(&service.name()));
22     let generated_trait = generate_trait(
23         service,
24         proto_path,
25         compile_well_known_types,
26         server_trait.clone(),
27     );
28     let service_doc = generate_doc_comments(service.comment());
29     let package = if emit_package { service.package() } else { "" };
30     // Transport based implementations
31     let path = format!(
32         "{}{}{}",
33         package,
34         if package.is_empty() { "" } else { "." },
35         service.identifier()
36     );
37     let transport = generate_transport(&server_service, &server_trait, &path);
38 
39     quote! {
40         /// Generated server implementations.
41         pub mod #server_mod {
42             #![allow(unused_variables, dead_code, missing_docs)]
43             use tonic::codegen::*;
44 
45             #generated_trait
46 
47             #service_doc
48             #[derive(Debug)]
49             pub struct #server_service<T: #server_trait> {
50                 inner: _Inner<T>,
51             }
52 
53             struct _Inner<T>(Arc<T>);
54 
55             impl<T: #server_trait> #server_service<T> {
56                 pub fn new(inner: T) -> Self {
57                     let inner = Arc::new(inner);
58                     let inner = _Inner(inner);
59                     Self { inner }
60                 }
61 
62                 pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
63                 where
64                     F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
65                 {
66                     InterceptedService::new(Self::new(inner), interceptor)
67                 }
68             }
69 
70             impl<T, B> Service<http::Request<B>> for #server_service<T>
71                 where
72                     T: #server_trait,
73                     B: Body + Send + Sync + 'static,
74                     B::Error: Into<StdError> + Send + 'static,
75             {
76                 type Response = http::Response<tonic::body::BoxBody>;
77                 type Error = Never;
78                 type Future = BoxFuture<Self::Response, Self::Error>;
79 
80                 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
81                     Poll::Ready(Ok(()))
82                 }
83 
84                 fn call(&mut self, req: http::Request<B>) -> Self::Future {
85                     let inner = self.inner.clone();
86 
87                     match req.uri().path() {
88                         #methods
89 
90                         _ => Box::pin(async move {
91                             Ok(http::Response::builder()
92                                .status(200)
93                                .header("grpc-status", "12")
94                                .header("content-type", "application/grpc")
95                                .body(empty_body())
96                                .unwrap())
97                         }),
98                     }
99                 }
100             }
101 
102             impl<T: #server_trait> Clone for #server_service<T> {
103                 fn clone(&self) -> Self {
104                     let inner = self.inner.clone();
105                     Self { inner }
106                 }
107             }
108 
109             impl<T: #server_trait> Clone for _Inner<T> {
110                 fn clone(&self) -> Self {
111                     Self(self.0.clone())
112                 }
113             }
114 
115             impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
116                 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117                    write!(f, "{:?}", self.0)
118                 }
119             }
120 
121             #transport
122         }
123     }
124 }
125 
126 fn generate_trait<T: Service>(
127     service: &T,
128     proto_path: &str,
129     compile_well_known_types: bool,
130     server_trait: Ident,
131 ) -> TokenStream {
132     let methods = generate_trait_methods(service, proto_path, compile_well_known_types);
133     let trait_doc = generate_doc_comment(&format!(
134         "Generated trait containing gRPC methods that should be implemented for use with {}Server.",
135         service.name()
136     ));
137 
138     quote! {
139         #trait_doc
140         #[async_trait]
141         pub trait #server_trait : Send + Sync + 'static {
142             #methods
143         }
144     }
145 }
146 
147 fn generate_trait_methods<T: Service>(
148     service: &T,
149     proto_path: &str,
150     compile_well_known_types: bool,
151 ) -> TokenStream {
152     let mut stream = TokenStream::new();
153 
154     for method in service.methods() {
155         let name = quote::format_ident!("{}", method.name());
156 
157         let (req_message, res_message) =
158             method.request_response_name(proto_path, compile_well_known_types);
159 
160         let method_doc = generate_doc_comments(method.comment());
161 
162         let method = match (method.client_streaming(), method.server_streaming()) {
163             (false, false) => {
164                 quote! {
165                     #method_doc
166                     async fn #name(&self, request: tonic::Request<#req_message>)
167                         -> Result<tonic::Response<#res_message>, tonic::Status>;
168                 }
169             }
170             (true, false) => {
171                 quote! {
172                     #method_doc
173                     async fn #name(&self, request: tonic::Request<tonic::Streaming<#req_message>>)
174                         -> Result<tonic::Response<#res_message>, tonic::Status>;
175                 }
176             }
177             (false, true) => {
178                 let stream = quote::format_ident!("{}Stream", method.identifier());
179                 let stream_doc = generate_doc_comment(&format!(
180                     "Server streaming response type for the {} method.",
181                     method.identifier()
182                 ));
183 
184                 quote! {
185                     #stream_doc
186                     type #stream: futures_core::Stream<Item = Result<#res_message, tonic::Status>> + Send + Sync + 'static;
187 
188                     #method_doc
189                     async fn #name(&self, request: tonic::Request<#req_message>)
190                         -> Result<tonic::Response<Self::#stream>, tonic::Status>;
191                 }
192             }
193             (true, true) => {
194                 let stream = quote::format_ident!("{}Stream", method.identifier());
195                 let stream_doc = generate_doc_comment(&format!(
196                     "Server streaming response type for the {} method.",
197                     method.identifier()
198                 ));
199 
200                 quote! {
201                     #stream_doc
202                     type #stream: futures_core::Stream<Item = Result<#res_message, tonic::Status>> + Send + Sync + 'static;
203 
204                     #method_doc
205                     async fn #name(&self, request: tonic::Request<tonic::Streaming<#req_message>>)
206                         -> Result<tonic::Response<Self::#stream>, tonic::Status>;
207                 }
208             }
209         };
210 
211         stream.extend(method);
212     }
213 
214     stream
215 }
216 
217 #[cfg(feature = "transport")]
218 fn generate_transport(
219     server_service: &syn::Ident,
220     server_trait: &syn::Ident,
221     service_name: &str,
222 ) -> TokenStream {
223     let service_name = syn::LitStr::new(service_name, proc_macro2::Span::call_site());
224 
225     quote! {
226         impl<T: #server_trait> tonic::transport::NamedService for #server_service<T> {
227             const NAME: &'static str = #service_name;
228         }
229     }
230 }
231 
232 #[cfg(not(feature = "transport"))]
233 fn generate_transport(
234     _server_service: &syn::Ident,
235     _server_trait: &syn::Ident,
236     _service_name: &str,
237 ) -> TokenStream {
238     TokenStream::new()
239 }
240 
241 fn generate_methods<T: Service>(
242     service: &T,
243     proto_path: &str,
244     compile_well_known_types: bool,
245 ) -> TokenStream {
246     let mut stream = TokenStream::new();
247 
248     for method in service.methods() {
249         let path = format!(
250             "/{}{}{}/{}",
251             service.package(),
252             if service.package().is_empty() {
253                 ""
254             } else {
255                 "."
256             },
257             service.identifier(),
258             method.identifier()
259         );
260         let method_path = Lit::Str(LitStr::new(&path, Span::call_site()));
261         let ident = quote::format_ident!("{}", method.name());
262         let server_trait = quote::format_ident!("{}", service.name());
263 
264         let method_stream = match (method.client_streaming(), method.server_streaming()) {
265             (false, false) => generate_unary(
266                 method,
267                 proto_path,
268                 compile_well_known_types,
269                 ident,
270                 server_trait,
271             ),
272 
273             (false, true) => generate_server_streaming(
274                 method,
275                 proto_path,
276                 compile_well_known_types,
277                 ident.clone(),
278                 server_trait,
279             ),
280             (true, false) => generate_client_streaming(
281                 method,
282                 proto_path,
283                 compile_well_known_types,
284                 ident.clone(),
285                 server_trait,
286             ),
287 
288             (true, true) => generate_streaming(
289                 method,
290                 proto_path,
291                 compile_well_known_types,
292                 ident.clone(),
293                 server_trait,
294             ),
295         };
296 
297         let method = quote! {
298             #method_path => {
299                 #method_stream
300             }
301         };
302         stream.extend(method);
303     }
304 
305     stream
306 }
307 
308 fn generate_unary<T: Method>(
309     method: &T,
310     proto_path: &str,
311     compile_well_known_types: bool,
312     method_ident: Ident,
313     server_trait: Ident,
314 ) -> TokenStream {
315     let codec_name = syn::parse_str::<syn::Path>(T::CODEC_PATH).unwrap();
316 
317     let service_ident = quote::format_ident!("{}Svc", method.identifier());
318 
319     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
320 
321     quote! {
322         #[allow(non_camel_case_types)]
323         struct #service_ident<T: #server_trait >(pub Arc<T>);
324 
325         impl<T: #server_trait> tonic::server::UnaryService<#request> for #service_ident<T> {
326             type Response = #response;
327             type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
328 
329             fn call(&mut self, request: tonic::Request<#request>) -> Self::Future {
330                 let inner = self.0.clone();
331                 let fut = async move {
332                     (*inner).#method_ident(request).await
333                 };
334                 Box::pin(fut)
335             }
336         }
337 
338         let inner = self.inner.clone();
339         let fut = async move {
340             let inner = inner.0;
341             let method = #service_ident(inner);
342             let codec = #codec_name::default();
343 
344             let mut grpc = tonic::server::Grpc::new(codec);
345 
346             let res = grpc.unary(method, req).await;
347             Ok(res)
348         };
349 
350         Box::pin(fut)
351     }
352 }
353 
354 fn generate_server_streaming<T: Method>(
355     method: &T,
356     proto_path: &str,
357     compile_well_known_types: bool,
358     method_ident: Ident,
359     server_trait: Ident,
360 ) -> TokenStream {
361     let codec_name = syn::parse_str::<syn::Path>(T::CODEC_PATH).unwrap();
362 
363     let service_ident = quote::format_ident!("{}Svc", method.identifier());
364 
365     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
366 
367     let response_stream = quote::format_ident!("{}Stream", method.identifier());
368 
369     quote! {
370         #[allow(non_camel_case_types)]
371         struct #service_ident<T: #server_trait >(pub Arc<T>);
372 
373         impl<T: #server_trait> tonic::server::ServerStreamingService<#request> for #service_ident<T> {
374             type Response = #response;
375             type ResponseStream = T::#response_stream;
376             type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
377 
378             fn call(&mut self, request: tonic::Request<#request>) -> Self::Future {
379                 let inner = self.0.clone();
380                 let fut = async move {
381                     (*inner).#method_ident(request).await
382 
383                 };
384                 Box::pin(fut)
385             }
386         }
387 
388         let inner = self.inner.clone();
389         let fut = async move {
390             let inner = inner.0;
391             let method = #service_ident(inner);
392             let codec = #codec_name::default();
393 
394             let mut grpc = tonic::server::Grpc::new(codec);
395 
396             let res = grpc.server_streaming(method, req).await;
397             Ok(res)
398         };
399 
400         Box::pin(fut)
401     }
402 }
403 
404 fn generate_client_streaming<T: Method>(
405     method: &T,
406     proto_path: &str,
407     compile_well_known_types: bool,
408     method_ident: Ident,
409     server_trait: Ident,
410 ) -> TokenStream {
411     let service_ident = quote::format_ident!("{}Svc", method.identifier());
412 
413     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
414     let codec_name = syn::parse_str::<syn::Path>(T::CODEC_PATH).unwrap();
415 
416     quote! {
417         #[allow(non_camel_case_types)]
418         struct #service_ident<T: #server_trait >(pub Arc<T>);
419 
420         impl<T: #server_trait> tonic::server::ClientStreamingService<#request> for #service_ident<T>
421         {
422             type Response = #response;
423             type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
424 
425             fn call(&mut self, request: tonic::Request<tonic::Streaming<#request>>) -> Self::Future {
426                 let inner = self.0.clone();
427                 let fut = async move {
428                     (*inner).#method_ident(request).await
429 
430                 };
431                 Box::pin(fut)
432             }
433         }
434 
435         let inner = self.inner.clone();
436         let fut = async move {
437             let inner = inner.0;
438             let method = #service_ident(inner);
439             let codec = #codec_name::default();
440 
441             let mut grpc = tonic::server::Grpc::new(codec);
442 
443             let res = grpc.client_streaming(method, req).await;
444             Ok(res)
445         };
446 
447         Box::pin(fut)
448     }
449 }
450 
451 fn generate_streaming<T: Method>(
452     method: &T,
453     proto_path: &str,
454     compile_well_known_types: bool,
455     method_ident: Ident,
456     server_trait: Ident,
457 ) -> TokenStream {
458     let codec_name = syn::parse_str::<syn::Path>(T::CODEC_PATH).unwrap();
459 
460     let service_ident = quote::format_ident!("{}Svc", method.identifier());
461 
462     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
463 
464     let response_stream = quote::format_ident!("{}Stream", method.identifier());
465 
466     quote! {
467         #[allow(non_camel_case_types)]
468         struct #service_ident<T: #server_trait>(pub Arc<T>);
469 
470         impl<T: #server_trait> tonic::server::StreamingService<#request> for #service_ident<T>
471         {
472             type Response = #response;
473             type ResponseStream = T::#response_stream;
474             type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
475 
476             fn call(&mut self, request: tonic::Request<tonic::Streaming<#request>>) -> Self::Future {
477                 let inner = self.0.clone();
478                 let fut = async move {
479                     (*inner).#method_ident(request).await
480                 };
481                 Box::pin(fut)
482             }
483         }
484 
485         let inner = self.inner.clone();
486         let fut = async move {
487             let inner = inner.0;
488             let method = #service_ident(inner);
489             let codec = #codec_name::default();
490 
491             let mut grpc = tonic::server::Grpc::new(codec);
492 
493             let res = grpc.streaming(method, req).await;
494             Ok(res)
495         };
496 
497         Box::pin(fut)
498     }
499 }
500