From 80e90e3b5dfde24b848bbf1f284051b73891e3c8 Mon Sep 17 00:00:00 2001 From: Kaleb Elwert Date: Mon, 22 Jun 2020 09:04:02 -0700 Subject: [PATCH] Add tower server example (#375) Note that this also adds `impl From for http::Response` in order to make writing middleware which can return an error much easier. --- examples/Cargo.toml | 4 ++ examples/README.md | 8 ++++ examples/src/tower/server.rs | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 examples/src/tower/server.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 87f207628..2b00c845c 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -66,6 +66,10 @@ path = "src/tls_client_auth/server.rs" name = "tls-client-auth-client" path = "src/tls_client_auth/client.rs" +[[bin]] +name = "tower-server" +path = "src/tower/server.rs" + [[bin]] name = "multiplex-server" path = "src/multiplex/server.rs" diff --git a/examples/README.md b/examples/README.md index 127398721..b474e76c2 100644 --- a/examples/README.md +++ b/examples/README.md @@ -94,6 +94,14 @@ $ cargo run --bin tls-server $ cargo run --bin health-server ``` +## Tower Middleware + +### Server + +```bash +$ cargo run --bin tower-server +``` + ## Autoreloading Server ### Server diff --git a/examples/src/tower/server.rs b/examples/src/tower/server.rs new file mode 100644 index 000000000..d25097049 --- /dev/null +++ b/examples/src/tower/server.rs @@ -0,0 +1,86 @@ +use hyper::{Body, Request as HyperRequest, Response as HyperResponse}; +use std::task::{Context, Poll}; +use tonic::{ + body::BoxBody, + transport::{NamedService, Server}, + Request, Response, Status, +}; +use tower::Service; + +use hello_world::greeter_server::{Greeter, GreeterServer}; +use hello_world::{HelloReply, HelloRequest}; + +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, + ) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + + let reply = hello_world::HelloReply { + message: format!("Hello {}!", request.into_inner().name), + }; + Ok(Response::new(reply)) + } +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let addr = "[::1]:50051".parse().unwrap(); + let greeter = MyGreeter::default(); + + println!("GreeterServer listening on {}", addr); + + let svc = InterceptedService { + inner: GreeterServer::new(greeter), + }; + + Server::builder().add_service(svc).serve(addr).await?; + + Ok(()) +} + +#[derive(Debug, Clone)] +struct InterceptedService { + inner: S, +} + +impl Service> for InterceptedService +where + S: Service, Response = HyperResponse> + + NamedService + + Clone + + Send + + 'static, + S::Future: Send + 'static, +{ + type Response = S::Response; + type Error = S::Error; + type Future = futures::future::BoxFuture<'static, Result>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: HyperRequest) -> Self::Future { + let mut svc = self.inner.clone(); + + Box::pin(async move { + // Do async work here.... + + svc.call(req).await + }) + } +} + +impl NamedService for InterceptedService { + const NAME: &'static str = S::NAME; +}