xref: /tonic/examples/src/tower/client.rs (revision b29f4668)
1 use hello_world::greeter_client::GreeterClient;
2 use hello_world::HelloRequest;
3 use service::AuthSvc;
4 use tower::ServiceBuilder;
5 
6 use tonic::{transport::Channel, Request, Status};
7 
8 pub mod hello_world {
9     tonic::include_proto!("helloworld");
10 }
11 
12 #[tokio::main]
13 async fn main() -> Result<(), Box<dyn std::error::Error>> {
14     let channel = Channel::from_static("http://[::1]:50051").connect().await?;
15 
16     let channel = ServiceBuilder::new()
17         // Interceptors can be also be applied as middleware
18         .layer(tonic::service::interceptor(intercept))
19         .layer_fn(AuthSvc::new)
20         .service(channel);
21 
22     let mut client = GreeterClient::new(channel);
23 
24     let request = tonic::Request::new(HelloRequest {
25         name: "Tonic".into(),
26     });
27 
28     let response = client.say_hello(request).await?;
29 
30     println!("RESPONSE={:?}", response);
31 
32     Ok(())
33 }
34 
35 // An interceptor function.
36 fn intercept(req: Request<()>) -> Result<Request<()>, Status> {
37     println!("received {:?}", req);
38     Ok(req)
39 }
40 
41 mod service {
42     use http::{Request, Response};
43     use std::future::Future;
44     use std::pin::Pin;
45     use std::task::{Context, Poll};
46     use tonic::body::BoxBody;
47     use tonic::transport::Body;
48     use tonic::transport::Channel;
49     use tower::Service;
50 
51     pub struct AuthSvc {
52         inner: Channel,
53     }
54 
55     impl AuthSvc {
56         pub fn new(inner: Channel) -> Self {
57             AuthSvc { inner }
58         }
59     }
60 
61     impl Service<Request<BoxBody>> for AuthSvc {
62         type Response = Response<Body>;
63         type Error = Box<dyn std::error::Error + Send + Sync>;
64         #[allow(clippy::type_complexity)]
65         type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
66 
67         fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
68             self.inner.poll_ready(cx).map_err(Into::into)
69         }
70 
71         fn call(&mut self, req: Request<BoxBody>) -> Self::Future {
72             // This is necessary because tonic internally uses `tower::buffer::Buffer`.
73             // See https://github.com/tower-rs/tower/issues/547#issuecomment-767629149
74             // for details on why this is necessary
75             let clone = self.inner.clone();
76             let mut inner = std::mem::replace(&mut self.inner, clone);
77 
78             Box::pin(async move {
79                 // Do extra async work here...
80                 let response = inner.call(req).await?;
81 
82                 Ok(response)
83             })
84         }
85     }
86 }
87