From bfed50e79d5400381912be3bef9225f0778c78a2 Mon Sep 17 00:00:00 2001 From: David Bernard Date: Sun, 22 Sep 2024 16:54:28 +0200 Subject: [PATCH] build(example): made protoc useless to build grpc client & server - store the generated content --- examples/grpc/build.rs | 14 +- examples/grpc/src/client.rs | 9 +- examples/grpc/src/generated/helloworld.rs | 364 ++++++++++++++++++ .../src/generated/helloworld_descriptor.bin | Bin 0 -> 3223 bytes examples/grpc/src/server.rs | 16 +- 5 files changed, 390 insertions(+), 13 deletions(-) create mode 100644 examples/grpc/src/generated/helloworld.rs create mode 100644 examples/grpc/src/generated/helloworld_descriptor.bin diff --git a/examples/grpc/build.rs b/examples/grpc/build.rs index d72abf5..e4b96e7 100644 --- a/examples/grpc/build.rs +++ b/examples/grpc/build.rs @@ -1,10 +1,20 @@ -use std::{env, path::PathBuf}; +use std::path::PathBuf; fn main() { - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + // trigger rebuild if "proto" folder change + print!("cargo:rerun-if-changed=./proto"); + + //let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_dir = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("generated"); + std::fs::create_dir_all(&out_dir).unwrap(); tonic_build::configure() + .build_client(true) + .build_server(true) .file_descriptor_set_path(out_dir.join("helloworld_descriptor.bin")) + .out_dir(out_dir) .compile(&["helloworld.proto"], &["proto"]) .unwrap(); } diff --git a/examples/grpc/src/client.rs b/examples/grpc/src/client.rs index d50bed5..01fc1b3 100644 --- a/examples/grpc/src/client.rs +++ b/examples/grpc/src/client.rs @@ -1,12 +1,13 @@ -use hello_world::greeter_client::GreeterClient; -use hello_world::{HelloRequest, StatusRequest}; +use generated::greeter_client::GreeterClient; +use generated::{HelloRequest, StatusRequest}; use tonic::transport::Channel; use tonic::Code; use tonic_tracing_opentelemetry::middleware::client::OtelGrpcLayer; use tower::ServiceBuilder; -pub mod hello_world { - tonic::include_proto!("helloworld"); +pub mod generated { + //tonic::include_proto!("helloworld"); + include!("generated/helloworld.rs"); } #[tokio::main] diff --git a/examples/grpc/src/generated/helloworld.rs b/examples/grpc/src/generated/helloworld.rs new file mode 100644 index 0000000..be21540 --- /dev/null +++ b/examples/grpc/src/generated/helloworld.rs @@ -0,0 +1,364 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloRequest { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HelloReply { + #[prost(string, tag = "1")] + pub message: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StatusRequest { + /// + #[prost(int32, tag = "1")] + pub code: i32, + #[prost(string, tag = "2")] + pub message: ::prost::alloc::string::String, +} +/// Generated client implementations. +pub mod greeter_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct GreeterClient { + inner: tonic::client::Grpc, + } + impl GreeterClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl GreeterClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> GreeterClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + GreeterClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn say_hello( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/helloworld.Greeter/SayHello", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("helloworld.Greeter", "SayHello")); + self.inner.unary(req, path, codec).await + } + pub async fn say_status( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/helloworld.Greeter/SayStatus", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("helloworld.Greeter", "SayStatus")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod greeter_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with GreeterServer. + #[async_trait] + pub trait Greeter: std::marker::Send + std::marker::Sync + 'static { + async fn say_hello( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn say_status( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + #[derive(Debug)] + pub struct GreeterServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl GreeterServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for GreeterServer + where + T: Greeter, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/helloworld.Greeter/SayHello" => { + #[allow(non_camel_case_types)] + struct SayHelloSvc(pub Arc); + impl tonic::server::UnaryService + for SayHelloSvc { + type Response = super::HelloReply; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::say_hello(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SayHelloSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/helloworld.Greeter/SayStatus" => { + #[allow(non_camel_case_types)] + struct SayStatusSvc(pub Arc); + impl tonic::server::UnaryService + for SayStatusSvc { + type Response = (); + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::say_status(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SayStatusSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", tonic::Code::Unimplemented as i32) + .header( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ) + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for GreeterServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "helloworld.Greeter"; + impl tonic::server::NamedService for GreeterServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/examples/grpc/src/generated/helloworld_descriptor.bin b/examples/grpc/src/generated/helloworld_descriptor.bin new file mode 100644 index 0000000000000000000000000000000000000000..3fff95c8b9237ed3de0736c7dec726a060712bfa GIT binary patch literal 3223 zcmbtW&vWBg5te1gab7Z$j3(I{25Pp~yR$O`j=hAUirOi*kZr}$;#fwKCxjESr8p{N z$w+cSirT+`8-D^vE*v;gMHP4cAa3yWlQr=S102Y~dHwqJ*I)n8>nHyCNPK&qB=acf zEYl=UrmL$?uvq4IZ7FK|g|d*KY;KD!gZ15S#N%1AXuqfL3aK44*0}PEQaw*1FP^uP zbbjw9zgq@b=T~uZ8y7B@(|=Sde^9G~arckvvw>vQmPl~iz6he|r+nCDyRZLxAnID} znR0R<{=O$Fds_9GqMiJ0kEFpYiKx4}x(d>aj;Vlpk&*A^9))opq_b=A3Fs4aD{Ikhm|s(p%Kym< zJQs-{UWGG{5nAM>0m1Vk%=5q}6znGSvB(I%9(3BoAjn3(7E~2r)9krbk5jE*&Id z7J1THV0=eoms=aVLPOc`q&-0 zw%MJymhA{?>JChsQlpP9$@ux$HXMg6o6Pg^&;%ObZGGgLhSMT*)EiFv=4j9&AkfHi z1r5z})5SU0YDu^MZb#NBof~%V3^01v9GdQ>ba-mIBX)Lb*@AQ$>$Yq5CPUq(@x&fm zjzJt*-*kFI-8?t?ZTN>zGTs;?mz*dqI0lIHbyt_Jfq`^Ej{v$8$CQaPN3LPp zld)@BqgSZ%1u}!sb=dZ0hOH4t%e`V)_9eq|9%Kbtba7^2AB7$j+0r>74w|FqZXSa} z^a=`nA195B!O$ESqn^QhEQYx-9pe=WW`f&*F*(f_I-H_W;FvoSyig)uZ?rCwjCzuJ zN_zhdK>Forbbw>7+XY6>q<6N?IoiJ=Dymi`DEN)HSVovy8RN2*HIgNO}Vwgae&~J;`K$I?L)b-Mr z@4YqJ@~QEPXVWUhWcv^L*9FWsg8!;D1tmLaJebyTZ|2Dl#P7Go!8P6%$!(HG{`%P? z?suO4xA#%ADfZ6T*e+t%G*RP={z-)@FL!LYZhkJr`ph!A)1HX!b(PkKO0oH4@xZ~{ zS!EkwJb~r8ExX3+O>wryqSl1By*W z`-#|reZfZi*5N6$(LX4|j6Vix$WYC_qQEM%LA#v#MiB#T{DV-ps(wCb+fC?$aJ?mQ?Z z!0jG9l5iER_E0$};F!Y0h9==E9MrygBuyXyZhs922?zIg4oV&1_8%WgI901@oK9|H z6{obukywD8%5aD3qo==o`zW1b+OMWWU@f1JPD4BK^UWWeY;FZ(ChlgI{rpnq2 z|I Result<(), Box> { let (_, health_service) = tonic_health::server::health_reporter(); let reflection_service = tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(hello_world::FILE_DESCRIPTOR_SET) + .register_encoded_file_descriptor_set(generated::FILE_DESCRIPTOR_SET) .build_v1()?; println!("GreeterServer listening on {}", addr);