Skip to content

Instantly share code, notes, and snippets.

@cab
Created October 7, 2021 20:00
Show Gist options
  • Save cab/e6298b384e96418c3f6eebd4ba250e35 to your computer and use it in GitHub Desktop.
Save cab/e6298b384e96418c3f6eebd4ba250e35 to your computer and use it in GitHub Desktop.
use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};
use tonic::{transport::Server, Request, Response, Status};
pub mod hello_world {
tonic::include_proto!("helloworld");
}
#[derive(Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name),
};
Ok(Response::new(reply))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();
let svc = GreeterServer::new(greeter);
println!("GreeterServer listening on {}", addr);
Server::builder()
.layer(async_interceptor::async_interceptor(|request| async move {
println!("async!");
Ok(request)
// Err(Status::unauthenticated("bad auth"))
}))
.add_service(svc)
.serve(addr)
.await?;
Ok(())
}
mod async_interceptor {
use std::future::Future;
use std::task::{Context, Poll};
use tonic::Status;
use tower::Service;
pub fn async_interceptor<R, S, F>(
f: impl Fn(R) -> F + Clone + Send + Sync + 'static,
) -> impl tower::layer::Layer<
S,
Service = impl Service<
R,
Response = S::Response,
Future = impl Future<Output = Result<S::Response, S::Error>> + Send,
Error = S::Error,
> + Clone
+ Send
+ Sync,
> + Clone
where
R: Send + Sync + 'static,
S: Service<R> + Clone + Send + Sync + 'static,
<S as Service<R>>::Future: Send,
<S as Service<R>>::Error: From<Status> + Send + Sync,
F: std::future::Future<Output = Result<R, Status>> + Send,
{
tower::layer::layer_fn({
move |inner: S| {
let f = f.clone();
AsyncInterceptor { inner, f }
}
})
}
#[derive(Clone)]
struct AsyncInterceptor<S, F> {
inner: S,
f: F,
}
impl<S, F, Fut, Request> Service<Request> for AsyncInterceptor<S, F>
where
Request: Send + 'static,
S: Service<Request> + Clone + Send + Sync + 'static,
<S as Service<Request>>::Future: Send,
<S as Service<Request>>::Error: From<Status> + Send,
F: (Fn(Request) -> Fut) + Clone + Send + Sync + 'static,
Fut: std::future::Future<Output = Result<Request, Status>> + Send,
{
type Response = S::Response;
type Error = S::Error;
type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, request: Request) -> Self::Future {
let f = self.f.clone();
let mut inner = self.inner.clone();
Box::pin(async move {
match f(request).await {
Ok(request) => inner.call(request).await,
Err(err) => Err(err.into()),
}
})
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment