diff --git a/tonic-build/Cargo.toml b/tonic-build/Cargo.toml index 5528e25..b77cd94 100644 --- a/tonic-build/Cargo.toml +++ b/tonic-build/Cargo.toml @@ -14,4 +14,6 @@ proc-macro2 = "1.0" [features] +default = ["transport"] rustfmt = [] +transport = [] diff --git a/tonic-build/src/client.rs b/tonic-build/src/client.rs index ed330b4..ff8eeaf 100644 --- a/tonic-build/src/client.rs +++ b/tonic-build/src/client.rs @@ -7,11 +7,15 @@ pub(crate) fn generate(service: &Service, proto: &str) -> TokenStream { let service_ident = quote::format_ident!("{}Client", service.name); let methods = generate_methods(service, proto); + let connect = generate_connect(&service_ident); + quote! { pub struct #service_ident { inner: tonic::client::Grpc, } + #connect + impl #service_ident where T: tonic::client::GrpcService, T::ResponseBody: Body + HttpBody + Send + 'static, @@ -42,6 +46,26 @@ pub(crate) fn generate(service: &Service, proto: &str) -> TokenStream { } } +#[cfg(feature = "transport")] +fn generate_connect(service_ident: &syn::Ident) -> TokenStream { + quote! { + impl #service_ident { + pub fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + tonic::transport::Channel::builder().build(dst).map(|c| Self::new(c)) + } + } + } +} + +#[cfg(not(feature = "transport"))] +fn generate_connect() -> TokenStream { + TokenStream::new() +} + fn generate_methods(service: &Service, proto: &str) -> TokenStream { let mut stream = TokenStream::new(); diff --git a/tonic-examples/src/helloworld/client.rs b/tonic-examples/src/helloworld/client.rs index fd673ec..804d664 100644 --- a/tonic-examples/src/helloworld/client.rs +++ b/tonic-examples/src/helloworld/client.rs @@ -1,5 +1,3 @@ -use tonic::transport::Channel; - pub mod hello_world { include!(concat!(env!("OUT_DIR"), "/helloworld.rs")); } @@ -8,11 +6,7 @@ use hello_world::{client::GreeterClient, HelloRequest}; #[tokio::main] async fn main() -> Result<(), Box> { - let origin = vec![http::Uri::from_static("http://[::1]:50051").into()]; - - let svc = Channel::builder().balance_list(origin)?; - - let mut client = GreeterClient::new(svc); + let mut client = GreeterClient::connect("http://[::1]:50051")?; let request = tonic::Request::new(HelloRequest { name: "hello".into(), diff --git a/tonic-examples/src/routeguide/client.rs b/tonic-examples/src/routeguide/client.rs index 1fd3d3f..019ec04 100644 --- a/tonic-examples/src/routeguide/client.rs +++ b/tonic-examples/src/routeguide/client.rs @@ -2,7 +2,7 @@ use futures::TryStreamExt; use route_guide::{Point, RouteNote}; use std::time::{Duration, Instant}; use tokio::timer::Interval; -use tonic::{transport::Channel, Request}; +use tonic::Request; mod route_guide { include!(concat!(env!("OUT_DIR"), "/routeguide.rs")); @@ -12,10 +12,7 @@ use route_guide::client::RouteGuideClient; #[tokio::main] async fn main() -> Result<(), Box> { - let origin = http::Uri::from_static("http://[::1]:10000"); - - let svc = Channel::builder().build(origin)?; - let mut client = RouteGuideClient::new(svc); + let mut client = RouteGuideClient::connect("http://[::1]:10000")?; let start = Instant::now(); diff --git a/tonic/src/codec/decode.rs b/tonic/src/codec/decode.rs index 658032d..8169ac4 100644 --- a/tonic/src/codec/decode.rs +++ b/tonic/src/codec/decode.rs @@ -1,5 +1,5 @@ use super::Decoder; -use crate::{metadata::MetadataMap, body::BoxBody, Code, Status}; +use crate::{body::BoxBody, metadata::MetadataMap, Code, Status}; use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf}; use futures_core::Stream; use futures_util::{future, ready}; diff --git a/tonic/src/server/grpc.rs b/tonic/src/server/grpc.rs index 6e6368d..b7474c9 100644 --- a/tonic/src/server/grpc.rs +++ b/tonic/src/server/grpc.rs @@ -1,7 +1,8 @@ use crate::{ + body::BoxBody, codec::{encode_server, Codec, Streaming}, server::{ClientStreamingService, ServerStreamingService, StreamingService, UnaryService}, - body::BoxBody, Code, Request, Response, Status, + Code, Request, Response, Status, }; use bytes::Bytes; use futures_core::TryStream; diff --git a/tonic/src/transport/channel.rs b/tonic/src/transport/channel.rs index 72c6c21..dc7be30 100644 --- a/tonic/src/transport/channel.rs +++ b/tonic/src/transport/channel.rs @@ -7,6 +7,7 @@ use futures_util::try_future::{MapErr, TryFutureExt}; use http::Uri; use hyper::{Request, Response}; use std::{ + convert::TryInto, fmt, future::Future, pin::Pin, @@ -107,12 +108,12 @@ impl Builder { pub fn build(&mut self, uri: T) -> Result where - Uri: http::HttpTryFrom, + T: TryInto, + T::Error: Into, { - let uri: Uri = match http::HttpTryFrom::try_from(uri) { - Ok(u) => u, - Err(e) => panic!("Invalid uri: {}", e.into()), - }; + let uri = uri + .try_into() + .map_err(|e| super::Error::from((super::ErrorKind::Client, e.into())))?; self.balance_list(vec![uri.into()]) } diff --git a/tonic/src/transport/endpoint.rs b/tonic/src/transport/endpoint.rs index 2eabd31..ca60c48 100644 --- a/tonic/src/transport/endpoint.rs +++ b/tonic/src/transport/endpoint.rs @@ -1,7 +1,7 @@ use super::{channel::Channel, tls::Cert}; use bytes::Bytes; use http::uri::{InvalidUriBytes, Uri}; -use std::time::Duration; +use std::{convert::TryFrom, time::Duration}; #[derive(Debug, Clone)] pub struct Endpoint { @@ -65,3 +65,38 @@ impl From for Endpoint { } } } + +impl TryFrom for Endpoint { + type Error = InvalidUriBytes; + + fn try_from(t: Bytes) -> Result { + Self::from_shared(t) + } +} + +impl TryFrom for Endpoint { + type Error = InvalidUriBytes; + + fn try_from(t: String) -> Result { + Self::from_shared(t.into_bytes()) + } +} + +impl TryFrom<&'static str> for Endpoint { + type Error = Never; + + fn try_from(t: &'static str) -> Result { + Ok(Self::from_static(t)) + } +} + +#[derive(Debug)] +pub enum Never {} + +impl std::fmt::Display for Never { + fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self {} + } +} + +impl std::error::Error for Never {}