xref: /tonic/tonic-build/src/server.rs (revision 7eeda243)
1 use std::collections::HashSet;
2 
3 use super::{Attributes, Method, Service};
4 use crate::{format_method_name, generate_doc_comment, generate_doc_comments, naive_snake_case};
5 use proc_macro2::{Span, TokenStream};
6 use quote::quote;
7 use syn::{Ident, Lit, LitStr};
8 
9 /// Generate service for Server.
10 ///
11 /// This takes some `Service` and will generate a `TokenStream` that contains
12 /// a public module containing the server service and handler trait.
13 #[deprecated(since = "0.8.3", note = "Use CodeGenBuilder::generate_server")]
14 pub fn generate<T: Service>(
15     service: &T,
16     emit_package: bool,
17     proto_path: &str,
18     compile_well_known_types: bool,
19     attributes: &Attributes,
20 ) -> TokenStream {
21     generate_internal(
22         service,
23         emit_package,
24         proto_path,
25         compile_well_known_types,
26         attributes,
27         &HashSet::default(),
28     )
29 }
30 
31 pub(crate) fn generate_internal<T: Service>(
32     service: &T,
33     emit_package: bool,
34     proto_path: &str,
35     compile_well_known_types: bool,
36     attributes: &Attributes,
37     disable_comments: &HashSet<String>,
38 ) -> TokenStream {
39     let methods = generate_methods(service, proto_path, compile_well_known_types);
40 
41     let server_service = quote::format_ident!("{}Server", service.name());
42     let server_trait = quote::format_ident!("{}", service.name());
43     let server_mod = quote::format_ident!("{}_server", naive_snake_case(service.name()));
44     let generated_trait = generate_trait(
45         service,
46         emit_package,
47         proto_path,
48         compile_well_known_types,
49         server_trait.clone(),
50         disable_comments,
51     );
52     let package = if emit_package { service.package() } else { "" };
53     // Transport based implementations
54     let path = format!(
55         "{}{}{}",
56         package,
57         if package.is_empty() { "" } else { "." },
58         service.identifier()
59     );
60 
61     let service_doc = if disable_comments.contains(&path) {
62         TokenStream::new()
63     } else {
64         generate_doc_comments(service.comment())
65     };
66 
67     let named = generate_named(&server_service, &server_trait, &path);
68     let mod_attributes = attributes.for_mod(package);
69     let struct_attributes = attributes.for_struct(&path);
70 
71     let configure_compression_methods = quote! {
72         /// Enable decompressing requests with the given encoding.
73         #[must_use]
74         pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
75             self.accept_compression_encodings.enable(encoding);
76             self
77         }
78 
79         /// Compress responses with the given encoding, if the client supports it.
80         #[must_use]
81         pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
82             self.send_compression_encodings.enable(encoding);
83             self
84         }
85     };
86 
87     let configure_max_message_size_methods = quote! {
88         /// Limits the maximum size of a decoded message.
89         #[must_use]
90         pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
91             self.max_decoding_message_size = Some(limit);
92             self
93         }
94 
95         /// Limits the maximum size of an encoded message.
96         #[must_use]
97         pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
98             self.max_encoding_message_size = Some(limit);
99             self
100         }
101     };
102 
103     quote! {
104         /// Generated server implementations.
105         #(#mod_attributes)*
106         pub mod #server_mod {
107             #![allow(
108                 unused_variables,
109                 dead_code,
110                 missing_docs,
111                 // will trigger if compression is disabled
112                 clippy::let_unit_value,
113             )]
114             use tonic::codegen::*;
115 
116             #generated_trait
117 
118             #service_doc
119             #(#struct_attributes)*
120             #[derive(Debug)]
121             pub struct #server_service<T: #server_trait> {
122                 inner: _Inner<T>,
123                 accept_compression_encodings: EnabledCompressionEncodings,
124                 send_compression_encodings: EnabledCompressionEncodings,
125                 max_decoding_message_size: Option<usize>,
126                 max_encoding_message_size: Option<usize>,
127             }
128 
129             struct _Inner<T>(Arc<T>);
130 
131             impl<T: #server_trait> #server_service<T> {
132                 pub fn new(inner: T) -> Self {
133                     Self::from_arc(Arc::new(inner))
134                 }
135 
136                 pub fn from_arc(inner: Arc<T>) -> Self {
137                     let inner = _Inner(inner);
138                     Self {
139                         inner,
140                         accept_compression_encodings: Default::default(),
141                         send_compression_encodings: Default::default(),
142                         max_decoding_message_size: None,
143                         max_encoding_message_size: None,
144                     }
145                 }
146 
147                 pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
148                 where
149                     F: tonic::service::Interceptor,
150                 {
151                     InterceptedService::new(Self::new(inner), interceptor)
152                 }
153 
154                 #configure_compression_methods
155 
156                 #configure_max_message_size_methods
157             }
158 
159             impl<T, B> tonic::codegen::Service<http::Request<B>> for #server_service<T>
160                 where
161                     T: #server_trait,
162                     B: Body + Send + 'static,
163                     B::Error: Into<StdError> + Send + 'static,
164             {
165                 type Response = http::Response<tonic::body::BoxBody>;
166                 type Error = std::convert::Infallible;
167                 type Future = BoxFuture<Self::Response, Self::Error>;
168 
169                 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
170                     Poll::Ready(Ok(()))
171                 }
172 
173                 fn call(&mut self, req: http::Request<B>) -> Self::Future {
174                     let inner = self.inner.clone();
175 
176                     match req.uri().path() {
177                         #methods
178 
179                         _ => Box::pin(async move {
180                             Ok(http::Response::builder()
181                                .status(200)
182                                .header("grpc-status", "12")
183                                .header("content-type", "application/grpc")
184                                .body(empty_body())
185                                .unwrap())
186                         }),
187                     }
188                 }
189             }
190 
191             impl<T: #server_trait> Clone for #server_service<T> {
192                 fn clone(&self) -> Self {
193                     let inner = self.inner.clone();
194                     Self {
195                         inner,
196                         accept_compression_encodings: self.accept_compression_encodings,
197                         send_compression_encodings: self.send_compression_encodings,
198                         max_decoding_message_size: self.max_decoding_message_size,
199                         max_encoding_message_size: self.max_encoding_message_size,
200                     }
201                 }
202             }
203 
204             impl<T: #server_trait> Clone for _Inner<T> {
205                 fn clone(&self) -> Self {
206                     Self(Arc::clone(&self.0))
207                 }
208             }
209 
210             impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
211                 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212                    write!(f, "{:?}", self.0)
213                 }
214             }
215 
216             #named
217         }
218     }
219 }
220 
221 fn generate_trait<T: Service>(
222     service: &T,
223     emit_package: bool,
224     proto_path: &str,
225     compile_well_known_types: bool,
226     server_trait: Ident,
227     disable_comments: &HashSet<String>,
228 ) -> TokenStream {
229     let methods = generate_trait_methods(
230         service,
231         emit_package,
232         proto_path,
233         compile_well_known_types,
234         disable_comments,
235     );
236     let trait_doc = generate_doc_comment(format!(
237         " Generated trait containing gRPC methods that should be implemented for use with {}Server.",
238         service.name()
239     ));
240 
241     quote! {
242         #trait_doc
243         #[async_trait]
244         pub trait #server_trait : Send + Sync + 'static {
245             #methods
246         }
247     }
248 }
249 
250 fn generate_trait_methods<T: Service>(
251     service: &T,
252     emit_package: bool,
253     proto_path: &str,
254     compile_well_known_types: bool,
255     disable_comments: &HashSet<String>,
256 ) -> TokenStream {
257     let mut stream = TokenStream::new();
258 
259     let package = if emit_package { service.package() } else { "" };
260     for method in service.methods() {
261         let name = quote::format_ident!("{}", method.name());
262 
263         let (req_message, res_message) =
264             method.request_response_name(proto_path, compile_well_known_types);
265 
266         let method_doc = if disable_comments.contains(&format_method_name(package, service, method))
267         {
268             TokenStream::new()
269         } else {
270             generate_doc_comments(method.comment())
271         };
272 
273         let method = match (method.client_streaming(), method.server_streaming()) {
274             (false, false) => {
275                 quote! {
276                     #method_doc
277                     async fn #name(&self, request: tonic::Request<#req_message>)
278                         -> std::result::Result<tonic::Response<#res_message>, tonic::Status>;
279                 }
280             }
281             (true, false) => {
282                 quote! {
283                     #method_doc
284                     async fn #name(&self, request: tonic::Request<tonic::Streaming<#req_message>>)
285                         -> std::result::Result<tonic::Response<#res_message>, tonic::Status>;
286                 }
287             }
288             (false, true) => {
289                 let stream = quote::format_ident!("{}Stream", method.identifier());
290                 let stream_doc = generate_doc_comment(format!(
291                     " Server streaming response type for the {} method.",
292                     method.identifier()
293                 ));
294 
295                 quote! {
296                     #stream_doc
297                     type #stream: futures_core::Stream<Item = std::result::Result<#res_message, tonic::Status>> + Send + 'static;
298 
299                     #method_doc
300                     async fn #name(&self, request: tonic::Request<#req_message>)
301                         -> std::result::Result<tonic::Response<Self::#stream>, tonic::Status>;
302                 }
303             }
304             (true, true) => {
305                 let stream = quote::format_ident!("{}Stream", method.identifier());
306                 let stream_doc = generate_doc_comment(format!(
307                     " Server streaming response type for the {} method.",
308                     method.identifier()
309                 ));
310 
311                 quote! {
312                     #stream_doc
313                     type #stream: futures_core::Stream<Item = std::result::Result<#res_message, tonic::Status>> + Send + 'static;
314 
315                     #method_doc
316                     async fn #name(&self, request: tonic::Request<tonic::Streaming<#req_message>>)
317                         -> std::result::Result<tonic::Response<Self::#stream>, tonic::Status>;
318                 }
319             }
320         };
321 
322         stream.extend(method);
323     }
324 
325     stream
326 }
327 
328 fn generate_named(
329     server_service: &syn::Ident,
330     server_trait: &syn::Ident,
331     service_name: &str,
332 ) -> TokenStream {
333     let service_name = syn::LitStr::new(service_name, proc_macro2::Span::call_site());
334 
335     quote! {
336         impl<T: #server_trait> tonic::server::NamedService for #server_service<T> {
337             const NAME: &'static str = #service_name;
338         }
339     }
340 }
341 
342 fn generate_methods<T: Service>(
343     service: &T,
344     proto_path: &str,
345     compile_well_known_types: bool,
346 ) -> TokenStream {
347     let mut stream = TokenStream::new();
348 
349     for method in service.methods() {
350         let path = format!(
351             "/{}{}{}/{}",
352             service.package(),
353             if service.package().is_empty() {
354                 ""
355             } else {
356                 "."
357             },
358             service.identifier(),
359             method.identifier()
360         );
361         let method_path = Lit::Str(LitStr::new(&path, Span::call_site()));
362         let ident = quote::format_ident!("{}", method.name());
363         let server_trait = quote::format_ident!("{}", service.name());
364 
365         let method_stream = match (method.client_streaming(), method.server_streaming()) {
366             (false, false) => generate_unary(
367                 method,
368                 proto_path,
369                 compile_well_known_types,
370                 ident,
371                 server_trait,
372             ),
373 
374             (false, true) => generate_server_streaming(
375                 method,
376                 proto_path,
377                 compile_well_known_types,
378                 ident.clone(),
379                 server_trait,
380             ),
381             (true, false) => generate_client_streaming(
382                 method,
383                 proto_path,
384                 compile_well_known_types,
385                 ident.clone(),
386                 server_trait,
387             ),
388 
389             (true, true) => generate_streaming(
390                 method,
391                 proto_path,
392                 compile_well_known_types,
393                 ident.clone(),
394                 server_trait,
395             ),
396         };
397 
398         let method = quote! {
399             #method_path => {
400                 #method_stream
401             }
402         };
403         stream.extend(method);
404     }
405 
406     stream
407 }
408 
409 fn generate_unary<T: Method>(
410     method: &T,
411     proto_path: &str,
412     compile_well_known_types: bool,
413     method_ident: Ident,
414     server_trait: Ident,
415 ) -> TokenStream {
416     let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
417 
418     let service_ident = quote::format_ident!("{}Svc", method.identifier());
419 
420     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
421 
422     quote! {
423         #[allow(non_camel_case_types)]
424         struct #service_ident<T: #server_trait >(pub Arc<T>);
425 
426         impl<T: #server_trait> tonic::server::UnaryService<#request> for #service_ident<T> {
427             type Response = #response;
428             type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
429 
430             fn call(&mut self, request: tonic::Request<#request>) -> Self::Future {
431                 let inner = Arc::clone(&self.0);
432                 let fut = async move {
433                     (*inner).#method_ident(request).await
434                 };
435                 Box::pin(fut)
436             }
437         }
438 
439         let accept_compression_encodings = self.accept_compression_encodings;
440         let send_compression_encodings = self.send_compression_encodings;
441         let max_decoding_message_size = self.max_decoding_message_size;
442         let max_encoding_message_size = self.max_encoding_message_size;
443         let inner = self.inner.clone();
444         let fut = async move {
445             let inner = inner.0;
446             let method = #service_ident(inner);
447             let codec = #codec_name::default();
448 
449             let mut grpc = tonic::server::Grpc::new(codec)
450                 .apply_compression_config(accept_compression_encodings, send_compression_encodings)
451                 .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);
452 
453             let res = grpc.unary(method, req).await;
454             Ok(res)
455         };
456 
457         Box::pin(fut)
458     }
459 }
460 
461 fn generate_server_streaming<T: Method>(
462     method: &T,
463     proto_path: &str,
464     compile_well_known_types: bool,
465     method_ident: Ident,
466     server_trait: Ident,
467 ) -> TokenStream {
468     let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
469 
470     let service_ident = quote::format_ident!("{}Svc", method.identifier());
471 
472     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
473 
474     let response_stream = quote::format_ident!("{}Stream", method.identifier());
475 
476     quote! {
477         #[allow(non_camel_case_types)]
478         struct #service_ident<T: #server_trait >(pub Arc<T>);
479 
480         impl<T: #server_trait> tonic::server::ServerStreamingService<#request> for #service_ident<T> {
481             type Response = #response;
482             type ResponseStream = T::#response_stream;
483             type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
484 
485             fn call(&mut self, request: tonic::Request<#request>) -> Self::Future {
486                 let inner = Arc::clone(&self.0);
487                 let fut = async move {
488                     (*inner).#method_ident(request).await
489                 };
490                 Box::pin(fut)
491             }
492         }
493 
494         let accept_compression_encodings = self.accept_compression_encodings;
495         let send_compression_encodings = self.send_compression_encodings;
496         let max_decoding_message_size = self.max_decoding_message_size;
497         let max_encoding_message_size = self.max_encoding_message_size;
498         let inner = self.inner.clone();
499         let fut = async move {
500             let inner = inner.0;
501             let method = #service_ident(inner);
502             let codec = #codec_name::default();
503 
504             let mut grpc = tonic::server::Grpc::new(codec)
505                 .apply_compression_config(accept_compression_encodings, send_compression_encodings)
506                 .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);
507 
508             let res = grpc.server_streaming(method, req).await;
509             Ok(res)
510         };
511 
512         Box::pin(fut)
513     }
514 }
515 
516 fn generate_client_streaming<T: Method>(
517     method: &T,
518     proto_path: &str,
519     compile_well_known_types: bool,
520     method_ident: Ident,
521     server_trait: Ident,
522 ) -> TokenStream {
523     let service_ident = quote::format_ident!("{}Svc", method.identifier());
524 
525     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
526     let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
527 
528     quote! {
529         #[allow(non_camel_case_types)]
530         struct #service_ident<T: #server_trait >(pub Arc<T>);
531 
532         impl<T: #server_trait> tonic::server::ClientStreamingService<#request> for #service_ident<T>
533         {
534             type Response = #response;
535             type Future = BoxFuture<tonic::Response<Self::Response>, tonic::Status>;
536 
537             fn call(&mut self, request: tonic::Request<tonic::Streaming<#request>>) -> Self::Future {
538                 let inner = Arc::clone(&self.0);
539                 let fut = async move {
540                     (*inner).#method_ident(request).await
541 
542                 };
543                 Box::pin(fut)
544             }
545         }
546 
547         let accept_compression_encodings = self.accept_compression_encodings;
548         let send_compression_encodings = self.send_compression_encodings;
549         let max_decoding_message_size = self.max_decoding_message_size;
550         let max_encoding_message_size = self.max_encoding_message_size;
551         let inner = self.inner.clone();
552         let fut = async move {
553             let inner = inner.0;
554             let method = #service_ident(inner);
555             let codec = #codec_name::default();
556 
557             let mut grpc = tonic::server::Grpc::new(codec)
558                 .apply_compression_config(accept_compression_encodings, send_compression_encodings)
559                 .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);
560 
561             let res = grpc.client_streaming(method, req).await;
562             Ok(res)
563         };
564 
565         Box::pin(fut)
566     }
567 }
568 
569 fn generate_streaming<T: Method>(
570     method: &T,
571     proto_path: &str,
572     compile_well_known_types: bool,
573     method_ident: Ident,
574     server_trait: Ident,
575 ) -> TokenStream {
576     let codec_name = syn::parse_str::<syn::Path>(method.codec_path()).unwrap();
577 
578     let service_ident = quote::format_ident!("{}Svc", method.identifier());
579 
580     let (request, response) = method.request_response_name(proto_path, compile_well_known_types);
581 
582     let response_stream = quote::format_ident!("{}Stream", method.identifier());
583 
584     quote! {
585         #[allow(non_camel_case_types)]
586         struct #service_ident<T: #server_trait>(pub Arc<T>);
587 
588         impl<T: #server_trait> tonic::server::StreamingService<#request> for #service_ident<T>
589         {
590             type Response = #response;
591             type ResponseStream = T::#response_stream;
592             type Future = BoxFuture<tonic::Response<Self::ResponseStream>, tonic::Status>;
593 
594             fn call(&mut self, request: tonic::Request<tonic::Streaming<#request>>) -> Self::Future {
595                 let inner = Arc::clone(&self.0);
596                 let fut = async move {
597                     (*inner).#method_ident(request).await
598                 };
599                 Box::pin(fut)
600             }
601         }
602 
603         let accept_compression_encodings = self.accept_compression_encodings;
604         let send_compression_encodings = self.send_compression_encodings;
605         let max_decoding_message_size = self.max_decoding_message_size;
606         let max_encoding_message_size = self.max_encoding_message_size;
607         let inner = self.inner.clone();
608         let fut = async move {
609             let inner = inner.0;
610             let method = #service_ident(inner);
611             let codec = #codec_name::default();
612 
613             let mut grpc = tonic::server::Grpc::new(codec)
614                 .apply_compression_config(accept_compression_encodings, send_compression_encodings)
615                 .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size);
616 
617             let res = grpc.streaming(method, req).await;
618             Ok(res)
619         };
620 
621         Box::pin(fut)
622     }
623 }
624