Skip to content

Commit

Permalink
Add tower server example (#375)
Browse files Browse the repository at this point in the history
Note that this also adds `impl From<Status> for http::Response<BoxBody>`
in order to make writing middleware which can return an error much
easier.
  • Loading branch information
belak authored Jun 22, 2020
1 parent 54d7a7a commit 80e90e3
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 8 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
86 changes: 86 additions & 0 deletions examples/src/tower/server.rs
Original file line number Diff line number Diff line change
@@ -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<HelloRequest>,
) -> Result<Response<HelloReply>, 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<dyn std::error::Error>> {
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<S> {
inner: S,
}

impl<S> Service<HyperRequest<Body>> for InterceptedService<S>
where
S: Service<HyperRequest<Body>, Response = HyperResponse<BoxBody>>
+ NamedService
+ Clone
+ Send
+ 'static,
S::Future: Send + 'static,
{
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, req: HyperRequest<Body>) -> Self::Future {
let mut svc = self.inner.clone();

Box::pin(async move {
// Do async work here....

svc.call(req).await
})
}
}

impl<S: NamedService> NamedService for InterceptedService<S> {
const NAME: &'static str = S::NAME;
}

0 comments on commit 80e90e3

Please sign in to comment.