1 use tokio::runtime::{Builder, Runtime}; 2 3 pub mod hello_world { 4 tonic::include_proto!("helloworld"); 5 } 6 7 use hello_world::{greeter_client::GreeterClient, HelloReply, HelloRequest}; 8 9 type StdError = Box<dyn std::error::Error + Send + Sync + 'static>; 10 type Result<T, E = StdError> = ::std::result::Result<T, E>; 11 12 // The order of the fields in this struct is important. They must be ordered 13 // such that when `BlockingClient` is dropped the client is dropped 14 // before the runtime. Not doing this will result in a deadlock when dropped. 15 // Rust drops struct fields in declaration order. 16 struct BlockingClient { 17 client: GreeterClient<tonic::transport::Channel>, 18 rt: Runtime, 19 } 20 21 impl BlockingClient { 22 pub fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> 23 where 24 D: std::convert::TryInto<tonic::transport::Endpoint>, 25 D::Error: Into<StdError>, 26 { 27 let rt = Builder::new_multi_thread().enable_all().build().unwrap(); 28 let client = rt.block_on(GreeterClient::connect(dst))?; 29 30 Ok(Self { client, rt }) 31 } 32 33 pub fn say_hello( 34 &mut self, 35 request: impl tonic::IntoRequest<HelloRequest>, 36 ) -> Result<tonic::Response<HelloReply>, tonic::Status> { 37 self.rt.block_on(self.client.say_hello(request)) 38 } 39 } 40 41 fn main() -> Result<()> { 42 let mut client = BlockingClient::connect("http://[::1]:50051")?; 43 44 let request = tonic::Request::new(HelloRequest { 45 name: "Tonic".into(), 46 }); 47 48 let response = client.say_hello(request)?; 49 50 println!("RESPONSE={:?}", response); 51 52 Ok(()) 53 } 54