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 mut rt = Builder::new() 28 .basic_scheduler() 29 .enable_all() 30 .build() 31 .unwrap(); 32 let client = rt.block_on(GreeterClient::connect(dst))?; 33 34 Ok(Self { rt, client }) 35 } 36 37 pub fn say_hello( 38 &mut self, 39 request: impl tonic::IntoRequest<HelloRequest>, 40 ) -> Result<tonic::Response<HelloReply>, tonic::Status> { 41 self.rt.block_on(self.client.say_hello(request)) 42 } 43 } 44 45 fn main() -> Result<()> { 46 let mut client = BlockingClient::connect("http://[::1]:50051")?; 47 48 let request = tonic::Request::new(HelloRequest { 49 name: "Tonic".into(), 50 }); 51 52 let response = client.say_hello(request)?; 53 54 println!("RESPONSE={:?}", response); 55 56 Ok(()) 57 } 58