Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Endpoint connectors swappable #148

Closed
wants to merge 6 commits into from

Conversation

akshayknarayan
Copy link

Motivation

As discussed in #136, it would be useful if tonic supported other transports other than TCP.
The Server side is relatively straightforward to do, like so:

let fut = hyper::Server::builder(/* impl of hyper::server::accept::Accept */).serve(hyper::service::make_service_fn(move |_| {
  async move { Ok::<_, hyper::Error>(/* tonic rpc server type */ ) }
}));

The client side is what this PR addresses.

Solution

Change the connect() API to lift up the use of connector() to Endpoint::connect(), allowing users to provide their own implementations (for example, Unix-domain sockets). Any type which impls tower_make::MakeConnection is suitable.

To avoid breaking the default case of HTTP(S), introduce connect_with_connector() and retain connect(), which creates the default connector according to the activated feature gate and passes it to connect_with_connector().

@alce
Copy link
Collaborator

alce commented Nov 22, 2019

@akshayknarayan cargo-deny check is failing in part because hyper-unix-connector depends in hyperlocal, which in turn depends on hyper 0.12. Tonic depends on hyper 0.13.0-alpha.4 and cargo check is banning the duplicate dependency.

/// connector.
pub async fn connect_with_connector<C, D>(dst: D, connector: C) -> Result<Self, tonic::transport::Error>
where
C: tonic::transport::MakeConnection<http::Uri> + Send + 'static,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we clean up some of these imports these seems a bit verbose 😄

/// let endpoint = Endpoint::from_static("http://example.com");
/// endpoint.connect_with_connector(UnixClient); //.await
/// ```
pub async fn connect_with_connector<C>(&self, connector: C) -> Result<Channel, super::Error>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I think it makes more sense for the endpoint to contain a connector option that by default uses the built in tonic one. So instead of providing it at connect time its provided with the endpoint. This means in a load balance list of endpoints they can each have their own type of connector. This should also simplify a lot of the code too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have poked around at this idea a bit, and it probably involves making several things pub, like transport::service::Connector, which in turn would require exposing transport::service::io::BoxedIo, etc.

This is because having Endpoint<C: MakeConnection<...>> means we will have

pub fn tls_config(self, tls_config: ClientTlsConfig) -> Endpoint<transport::service::Connector> {

and transport::service::Connector is currently pub(crate).

What is your plan regarding the tls feature? Things might be simpler if it was in its own crate - then usage would just be

Endpoint::from(...).connector(/* tls connector from the external crate */).connect().await

with a plain HTTPConnector as the default.

Copy link
Member

@LucioFranco LucioFranco Nov 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use a Box<dyn Connector> type to avoid the generic for now. This should allow users to include it or not without generics.

@jen20
Copy link
Contributor

jen20 commented Nov 25, 2019

It looks like we have the same issue here as in #151 with cargo-deny picking up an existing dependency as bad.

Change the `connect()` API to lift up the use of `connector()` to
`Endpoint::connect()`, allowing users to provide their own
implementations (for example, Unix-domain sockets).
Any type which impls `tower_make::MakeConnection` is
suitable.

To avoid breaking the default case of HTTP(S), introduce
`connect_with_connector()` and retain `connect()`, which creates the
default connector according to the activated feature gate and passes it
to `connect_with_connector()`.

Fixes: hyperium#136
Instead of providing a connector in the call to `connect()`, make `Endpoint`
contain a connector, by default an `HTTPConnector`, which the caller can
swap.
@LucioFranco
Copy link
Member

Hey! I opened #184 which adds this and a UDS example. Thank you for contributing this, I am gonna close this PR <3! Let me know if the other one doesn't meet your needs!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants