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