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