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. The runtime must be the first field and the 13 // client must be the last field so that when `BlockingClient` is dropped the client is dropped 14 // before the runtime. Not doing this will result in a deadlock when dropped. 15 struct BlockingClient { 16 rt: Runtime, 17 client: GreeterClient<tonic::transport::Channel>, 18 } 19 20 impl BlockingClient { 21 pub fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error> 22 where 23 D: std::convert::TryInto<tonic::transport::Endpoint>, 24 D::Error: Into<StdError>, 25 { 26 let mut rt = Builder::new() 27 .basic_scheduler() 28 .enable_all() 29 .build() 30 .unwrap(); 31 let client = rt.block_on(GreeterClient::connect(dst))?; 32 33 Ok(Self { rt, client }) 34 } 35 36 pub fn say_hello( 37 &mut self, 38 request: impl tonic::IntoRequest<HelloRequest>, 39 ) -> Result<tonic::Response<HelloReply>, tonic::Status> { 40 self.rt.block_on(self.client.say_hello(request)) 41 } 42 } 43 44 fn main() -> Result<()> { 45 let mut client = BlockingClient::connect("http://[::1]:50051")?; 46 47 let request = tonic::Request::new(HelloRequest { 48 name: "Tonic".into(), 49 }); 50 51 let response = client.say_hello(request)?; 52 53 println!("RESPONSE={:?}", response); 54 55 Ok(()) 56 } 57