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