Skip to content

Commit

Permalink
chore(docs): Add warp + tonic example (#268)
Browse files Browse the repository at this point in the history
Signed-off-by: Lucio Franco <[email protected]>
  • Loading branch information
LucioFranco authored Feb 16, 2020
1 parent b49ad9b commit e2bff8f
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 50 deletions.
2 changes: 2 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ deny = [
skip-tree = [
{ name = "winapi", version = "<= 0.3" },
{ name = "autocfg", version = "<= 1" },
{ name = "base64", version = "<= 0.11" },
{ name = "version_check", version = "<= 0.9" }
]

[licenses]
Expand Down
12 changes: 8 additions & 4 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ name = "interceptor-server"
path = "src/interceptor/server.rs"

[[bin]]
name = "hyper-client"
path = "src/hyper/client.rs"
name = "hyper-warp-client"
path = "src/hyper_warp/client.rs"

[[bin]]
name = "hyper-server"
path = "src/hyper/server.rs"
name = "hyper-warp-server"
path = "src/hyper_warp/server.rs"

[dependencies]
tonic = { path = "../tonic", features = ["tls"] }
Expand All @@ -122,6 +122,10 @@ tracing-futures = "0.2"
prost-types = "0.6"
# Hyper example
hyper = "0.13"
warp = { version = "0.2", default-features = false }
http = "0.2"
http-body = "0.3"
pin-project = "0.4"

[build-dependencies]
tonic-build = { path = "../tonic-build" }
46 changes: 0 additions & 46 deletions examples/src/hyper/server.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! To hit the gRPC endpoint you must run this client via:
//! `cargo run --bin hyper-warp-client
//! To hit the warp server you can run this command:
//! `curl localhost:50051/hello`
use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
use hyper::{Client, Uri};
Expand Down
130 changes: 130 additions & 0 deletions examples/src/hyper_warp/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//! To hit the gRPC endpoint you must run this client via:
//! `cargo run --bin hyper-warp-client
//! To hit the warp server you can run this command:
//! `curl localhost:50051/hello`
use futures::future::{self, Either, TryFutureExt};
use http::version::Version;
use hyper::{service::make_service_fn, Server};
use pin_project::{pin_project, project};
use std::convert::Infallible;
use std::{
pin::Pin,
task::{Context, Poll},
};
use tonic::{Request, Response, Status};
use tower::Service;
use warp::Filter;

use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};

type Error = Box<dyn std::error::Error + Send + Sync + 'static>;

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();

println!("GreeterServer listening on {}", addr);

let tonic = GreeterServer::new(greeter);
let warp = warp::service(warp::path("hello").map(|| "hello, world!"));

Server::bind(&addr)
.serve(make_service_fn(move |_| {
let mut tonic = tonic.clone();
let mut warp = warp.clone();
future::ok::<_, Infallible>(tower::service_fn(
move |req: hyper::Request<hyper::Body>| match req.version() {
Version::HTTP_11 | Version::HTTP_10 => Either::Left(
warp.call(req)
.map_ok(|res| res.map(EitherBody::Left))
.map_err(Error::from),
),
Version::HTTP_2 => Either::Right(
tonic
.call(req)
.map_ok(|res| res.map(EitherBody::Right))
.map_err(Error::from),
),
_ => unimplemented!(),
},
))
}))
.await?;

Ok(())
}

#[pin_project]
enum EitherBody<A, B> {
Left(#[pin] A),
Right(#[pin] B),
}

impl<A, B> http_body::Body for EitherBody<A, B>
where
A: http_body::Body + Send,
B: http_body::Body<Data = A::Data> + Send,
A::Error: Into<Error>,
B::Error: Into<Error>,
{
type Data = A::Data;
type Error = Box<dyn std::error::Error + Send + Sync + 'static>;

fn is_end_stream(&self) -> bool {
match self {
EitherBody::Left(b) => b.is_end_stream(),
EitherBody::Right(b) => b.is_end_stream(),
}
}

#[project]
fn poll_data(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
#[project]
match self.project() {
EitherBody::Left(b) => b.poll_data(cx).map(map_option_err),
EitherBody::Right(b) => b.poll_data(cx).map(map_option_err),
}
}

#[project]
fn poll_trailers(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
#[project]
match self.project() {
EitherBody::Left(b) => b.poll_trailers(cx).map_err(Into::into),
EitherBody::Right(b) => b.poll_trailers(cx).map_err(Into::into),
}
}
}

fn map_option_err<T, U: Into<Error>>(err: Option<Result<T, U>>) -> Option<Result<T, Error>> {
err.map(|e| e.map_err(Into::into))
}

0 comments on commit e2bff8f

Please sign in to comment.