use hello_world::greeter_client::GreeterClient; use hello_world::HelloRequest; use service::AuthSvc; use tower::ServiceBuilder; use tonic::{transport::Channel, Request, Status}; pub mod hello_world { tonic::include_proto!("helloworld"); } #[tokio::main] async fn main() -> Result<(), Box> { let channel = Channel::from_static("http://[::1]:50051").connect().await?; let channel = ServiceBuilder::new() // Interceptors can be also be applied as middleware .layer(tonic::service::InterceptorLayer::new(intercept)) .layer_fn(AuthSvc::new) .service(channel); let mut client = GreeterClient::new(channel); let request = tonic::Request::new(HelloRequest { name: "Tonic".into(), }); let response = client.say_hello(request).await?; println!("RESPONSE={:?}", response); Ok(()) } // An interceptor function. fn intercept(req: Request<()>) -> Result, Status> { println!("received {:?}", req); Ok(req) } mod service { use http::{Request, Response}; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use tonic::body::Body; use tonic::transport::Channel; use tower::Service; pub struct AuthSvc { inner: Channel, } impl AuthSvc { pub fn new(inner: Channel) -> Self { AuthSvc { inner } } } impl Service> for AuthSvc { type Response = Response; type Error = Box; #[allow(clippy::type_complexity)] type Future = Pin> + Send>>; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx).map_err(Into::into) } fn call(&mut self, req: Request) -> Self::Future { // See: https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services let clone = self.inner.clone(); let mut inner = std::mem::replace(&mut self.inner, clone); Box::pin(async move { // Do extra async work here... let response = inner.call(req).await?; Ok(response) }) } } }