xref: /tonic/examples/src/tower/client.rs (revision 60b131d2)
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]
main() -> Result<(), Box<dyn std::error::Error>>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::InterceptorLayer::new(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.
intercept(req: Request<()>) -> Result<Request<()>, Status>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::Body;
47     use tonic::transport::Channel;
48     use tower::Service;
49 
50     pub struct AuthSvc {
51         inner: Channel,
52     }
53 
54     impl AuthSvc {
new(inner: Channel) -> Self55         pub fn new(inner: Channel) -> Self {
56             AuthSvc { inner }
57         }
58     }
59 
60     impl Service<Request<Body>> for AuthSvc {
61         type Response = Response<Body>;
62         type Error = Box<dyn std::error::Error + Send + Sync>;
63         #[allow(clippy::type_complexity)]
64         type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
65 
poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>66         fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
67             self.inner.poll_ready(cx).map_err(Into::into)
68         }
69 
call(&mut self, req: Request<Body>) -> Self::Future70         fn call(&mut self, req: Request<Body>) -> Self::Future {
71             // See: https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services
72             let clone = self.inner.clone();
73             let mut inner = std::mem::replace(&mut self.inner, clone);
74 
75             Box::pin(async move {
76                 // Do extra async work here...
77                 let response = inner.call(req).await?;
78 
79                 Ok(response)
80             })
81         }
82     }
83 }
84