diff --git a/tonic-examples/src/helloworld/client.rs b/tonic-examples/src/helloworld/client.rs index c782cd9..816f51f 100644 --- a/tonic-examples/src/helloworld/client.rs +++ b/tonic-examples/src/helloworld/client.rs @@ -1,7 +1,4 @@ -use hyper::client::conn::Builder; -use hyper::client::connect::HttpConnector; -use hyper::client::service::{Connect, MakeService}; -use tonic::service::add_origin::AddOrigin; +use tonic::transport::Client; pub mod hello_world { include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); @@ -12,12 +9,7 @@ pub mod hello_world { async fn main() -> Result<(), Box> { let origin = http::Uri::from_static("http://[::1]:50051"); - let settings = Builder::new().http2_only(true).clone(); - let mut maker = Connect::new(HttpConnector::new(), settings); - - let svc = maker.make_service(origin.clone()).await?; - - let svc = AddOrigin::new(svc, origin); + let svc = Client::connect(origin).await?; let mut client = hello_world::GreeterClient::new(svc); diff --git a/tonic-examples/src/helloworld/server.rs b/tonic-examples/src/helloworld/server.rs index 277e027..bf389bc 100644 --- a/tonic-examples/src/helloworld/server.rs +++ b/tonic-examples/src/helloworld/server.rs @@ -1,6 +1,4 @@ use hyper::Server; -use std::time::Duration; -use tokio::timer::Delay; use tonic::{Request, Response, Status}; pub mod hello_world { diff --git a/tonic-examples/src/routeguide/client.rs b/tonic-examples/src/routeguide/client.rs index f8073b3..7405de3 100644 --- a/tonic-examples/src/routeguide/client.rs +++ b/tonic-examples/src/routeguide/client.rs @@ -5,8 +5,7 @@ use hyper::client::service::{Connect, MakeService}; use route_guide::{Point, RouteNote}; use std::time::{Duration, Instant}; use tokio::timer::Interval; -use tonic::service::add_origin::AddOrigin; -use tonic::Request; +use tonic::{Request, transport::Client}; mod route_guide { include!(concat!(env!("OUT_DIR"), "/routeguide.rs")); @@ -17,12 +16,7 @@ mod route_guide { async fn main() -> Result<(), Box> { let origin = http::Uri::from_static("http://[::1]:10000"); - let settings = Builder::new().http2_only(true).clone(); - let mut maker = Connect::new(HttpConnector::new(), settings); - - let svc = maker.make_service(origin.clone()).await?; - let svc = AddOrigin::new(svc, origin); - + let svc = Client::connect(origin).await?; let mut client = route_guide::RouteGuideClient::new(svc); let start = Instant::now(); diff --git a/tonic-interop/src/client.rs b/tonic-interop/src/client.rs index 07bf3e3..3aad2e8 100644 --- a/tonic-interop/src/client.rs +++ b/tonic-interop/src/client.rs @@ -1,15 +1,12 @@ use crate::{pb::*, test_assert, TestAssertion}; use futures_util::{future, stream, SinkExt, StreamExt}; -use hyper::client::conn::{Builder, SendRequest}; -use hyper::client::connect::HttpConnector; -use hyper::client::service::{Connect, MakeService}; use std::net::SocketAddr; use tokio::sync::mpsc; -use tonic::service::add_origin::AddOrigin; use tonic::{metadata::MetadataValue, Code, Request, Response, Status}; +use tonic::transport::Client; -pub type Client = TestServiceClient>>; -pub type UnimplementedClient = UnimplementedServiceClient>>; +pub type TestClient = TestServiceClient; +pub type UnimplementedClient = UnimplementedServiceClient; tonic::client!(service = "grpc.testing.TestService", proto = "crate::pb"); tonic::client!( @@ -25,14 +22,10 @@ const TEST_STATUS_MESSAGE: &'static str = "test status message"; const SPECIAL_TEST_STATUS_MESSAGE: &'static str = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n"; -pub async fn create(addr: SocketAddr) -> Result> { +pub async fn create(addr: SocketAddr) -> Result> { let origin = http::Uri::from_shared(format!("http://{}", addr).into()).unwrap(); - let settings = Builder::new().http2_only(true).clone(); - let mut maker = Connect::new(HttpConnector::new(), settings); - - let svc = maker.make_service(origin.clone()).await?; - let svc = AddOrigin::new(svc, origin); + let svc = Client::connect(origin).await?; Ok(TestServiceClient::new(svc)) } @@ -42,16 +35,12 @@ pub async fn create_unimplemented( ) -> Result> { let origin = http::Uri::from_shared(format!("http://{}", addr).into()).unwrap(); - let settings = Builder::new().http2_only(true).clone(); - let mut maker = Connect::new(HttpConnector::new(), settings); - - let svc = maker.make_service(origin.clone()).await?; - let svc = AddOrigin::new(svc, origin); + let svc = Client::connect(origin).await?; Ok(UnimplementedServiceClient::new(svc)) } -pub async fn empty_unary(client: &mut Client, assertions: &mut Vec) { +pub async fn empty_unary(client: &mut TestClient, assertions: &mut Vec) { let result = client.empty_call(Request::new(Empty {})).await; assertions.push(test_assert!( @@ -70,7 +59,7 @@ pub async fn empty_unary(client: &mut Client, assertions: &mut Vec) { +pub async fn large_unary(client: &mut TestClient, assertions: &mut Vec) { use std::mem; let payload = crate::client_payload(LARGE_REQ_SIZE); let req = SimpleRequest { @@ -114,7 +103,7 @@ pub async fn large_unary(client: &mut Client, assertions: &mut Vec) { +pub async fn client_streaming(client: &mut TestClient, assertions: &mut Vec) { let requests = REQUEST_LENGTHS .iter() .map(|len| StreamingInputCallRequest { @@ -144,7 +133,7 @@ pub async fn client_streaming(client: &mut Client, assertions: &mut Vec) { +pub async fn server_streaming(client: &mut TestClient, assertions: &mut Vec) { let req = StreamingOutputCallRequest { response_parameters: RESPONSE_LENGTHS .iter() @@ -186,7 +175,7 @@ pub async fn server_streaming(client: &mut Client, assertions: &mut Vec) { +pub async fn ping_pong(client: &mut TestClient, assertions: &mut Vec) { let (mut tx, rx) = mpsc::unbounded_channel(); tx.try_send(make_ping_pong_request(0)).unwrap(); @@ -243,7 +232,7 @@ pub async fn ping_pong(client: &mut Client, assertions: &mut Vec) } } -pub async fn empty_stream(client: &mut Client, assertions: &mut Vec) { +pub async fn empty_stream(client: &mut TestClient, assertions: &mut Vec) { let stream = stream::iter(Vec::new()); let result = client.full_duplex_call(Request::new(stream)).await; @@ -264,7 +253,7 @@ pub async fn empty_stream(client: &mut Client, assertions: &mut Vec) { +pub async fn status_code_and_message(client: &mut TestClient, assertions: &mut Vec) { fn validate_response(result: Result, assertions: &mut Vec) where T: std::fmt::Debug, @@ -322,7 +311,7 @@ pub async fn status_code_and_message(client: &mut Client, assertions: &mut Vec) { +pub async fn special_status_message(client: &mut TestClient, assertions: &mut Vec) { let req = SimpleRequest { response_status: Some(EchoStatus { code: 2, @@ -353,7 +342,7 @@ pub async fn special_status_message(client: &mut Client, assertions: &mut Vec) { +pub async fn unimplemented_method(client: &mut TestClient, assertions: &mut Vec) { let result = client.unimplemented_call(Request::new(Empty {})).await; assertions.push(test_assert!( "call must fail with unimplemented status code", @@ -380,7 +369,7 @@ pub async fn unimplemented_service( )); } -pub async fn custom_metadata(client: &mut Client, assertions: &mut Vec) { +pub async fn custom_metadata(client: &mut TestClient, assertions: &mut Vec) { let key1 = "x-grpc-test-echo-initial"; let value1 = MetadataValue::from_str("test_initial_metadata_value").unwrap(); let key2 = "x-grpc-test-echo-trailing-bin"; diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index ad65837..356c610 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -22,3 +22,8 @@ tokio-codec = "=0.2.0-alpha.4" async-stream = { path = "../../async-stream/async-stream" } http-body = "0.2.0-alpha.1" pin-project = "0.4.0-alpha.2" +hyper = { git = "https://github.com/hyperium/hyper", optional = true} + +[features] +default = ["transport"] +transport = ["hyper"] diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 3dcba65..70a58a7 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -11,6 +11,9 @@ pub mod metadata; pub mod server; pub mod service; +#[cfg(feature = "transport")] +pub mod transport; + mod request; mod response; mod status; diff --git a/tonic/src/service/mod.rs b/tonic/src/service/mod.rs index ade1bbc..b4d3380 100644 --- a/tonic/src/service/mod.rs +++ b/tonic/src/service/mod.rs @@ -1,5 +1,8 @@ +// TODO: make this private again pub mod add_origin; +pub use self::add_origin::AddOrigin; + use crate::body::Body; use http::{Request, Response}; use http_body::Body as HttpBody; diff --git a/tonic/src/transport/client.rs b/tonic/src/transport/client.rs new file mode 100644 index 0000000..e46ec17 --- /dev/null +++ b/tonic/src/transport/client.rs @@ -0,0 +1,68 @@ +use crate::{ + body::BoxBody, + service::{AddOrigin, GrpcService}, +}; +use http::Uri; +use hyper::client::conn; +use hyper::{Request, Response}; +use std::task::{Context, Poll}; +use tower_service::Service; +use hyper::client::conn::Builder; +use hyper::client::connect::HttpConnector; +use hyper::client::service::{Connect, MakeService}; + +//type BoxFuture<'a, T> = Pin + Send + 'a>>; +type BoxService = Box< + dyn GrpcService< + BoxBody, + ResponseBody = hyper::Body, + Error = hyper::Error, + Future = conn::ResponseFuture, //BoxFuture<'static, Result, hyper::Error>>, + > + Send + + 'static, +>; + +// #[derive/(Clone)] +pub struct Client { + svc: BoxService, +} + +impl Client { + pub async fn connect(addr: Uri) -> Result { + let settings = Builder::new().http2_only(true).clone(); + let mut maker = Connect::new(HttpConnector::new(), settings); + + maker.make_service(addr.clone()).await.map(|svc| Self::new(addr, svc)) + } + + fn new(addr: Uri, service: S) -> Self + where + S: Service< + Request, + Response = Response, + Error = hyper::Error, + Future = conn::ResponseFuture, //BoxFuture<'static, Result, hyper::Error>>, + > + Send + + 'static, + { + let svc = AddOrigin::new(service, addr); + + Self { svc: Box::new(svc) } + } +} + +impl GrpcService for Client { + type ResponseBody = hyper::Body; + type Error = hyper::Error; + + // type Future = BoxFuture<'static, Result, Self::Error>>; + type Future = conn::ResponseFuture; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.svc.poll_ready(cx) + } + + fn call(&mut self, request: Request) -> Self::Future { + self.svc.call(request) + } +} diff --git a/tonic/src/transport/mod.rs b/tonic/src/transport/mod.rs new file mode 100644 index 0000000..f535227 --- /dev/null +++ b/tonic/src/transport/mod.rs @@ -0,0 +1,3 @@ +mod client; + +pub use self::client::Client;