1 use hello_world::greeter_client::GreeterClient; 2 use hello_world::HelloRequest; 3 use http::Uri; 4 use hyper::Client; 5 6 pub mod hello_world { 7 tonic::include_proto!("helloworld"); 8 } 9 10 #[tokio::main] 11 async fn main() -> Result<(), Box<dyn std::error::Error>> { 12 let origin = Uri::from_static("http://[::1]:50051"); 13 let h2c_client = h2c::H2cChannel { 14 client: Client::new(), 15 }; 16 17 let mut client = GreeterClient::with_origin(h2c_client, origin); 18 19 let request = tonic::Request::new(HelloRequest { 20 name: "Tonic".into(), 21 }); 22 23 let response = client.say_hello(request).await?; 24 25 println!("RESPONSE={:?}", response); 26 27 Ok(()) 28 } 29 30 mod h2c { 31 use std::{ 32 pin::Pin, 33 task::{Context, Poll}, 34 }; 35 36 use hyper::{client::HttpConnector, Client}; 37 use tonic::body::BoxBody; 38 use tower::Service; 39 40 pub struct H2cChannel { 41 pub client: Client<HttpConnector>, 42 } 43 44 impl Service<http::Request<BoxBody>> for H2cChannel { 45 type Response = http::Response<hyper::Body>; 46 type Error = hyper::Error; 47 type Future = 48 Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>; 49 50 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { 51 Poll::Ready(Ok(())) 52 } 53 54 fn call(&mut self, request: http::Request<BoxBody>) -> Self::Future { 55 let client = self.client.clone(); 56 57 Box::pin(async move { 58 let origin = request.uri(); 59 60 let h2c_req = hyper::Request::builder() 61 .uri(origin) 62 .header(http::header::UPGRADE, "h2c") 63 .body(hyper::Body::empty()) 64 .unwrap(); 65 66 let res = client.request(h2c_req).await.unwrap(); 67 68 if res.status() != http::StatusCode::SWITCHING_PROTOCOLS { 69 panic!("Our server didn't upgrade: {}", res.status()); 70 } 71 72 let upgraded_io = hyper::upgrade::on(res).await.unwrap(); 73 74 // In an ideal world you would somehow cache this connection 75 let (mut h2_client, conn) = hyper::client::conn::Builder::new() 76 .http2_only(true) 77 .handshake(upgraded_io) 78 .await 79 .unwrap(); 80 tokio::spawn(conn); 81 82 h2_client.send_request(request).await 83 }) 84 } 85 } 86 } 87