use super::{Background, Connection, Handshake, HandshakeError};
use Body;
use tower::MakeConnection;
use tower_service::Service;
use futures::future::Executor;
use futures::{Future, Poll};
use h2;
use std::error::Error;
use std::fmt;
use std::marker::PhantomData;
pub struct Connect<A, C, E, S> {
inner: C,
builder: h2::client::Builder,
executor: E,
_p: PhantomData<(A, S)>,
}
pub struct ConnectFuture<A, C, E, S>
where
C: MakeConnection<A>,
S: Body,
{
state: State<A, C, E, S>,
executor: Option<E>,
builder: h2::client::Builder,
}
enum State<A, C, E, S>
where
C: MakeConnection<A>,
S: Body,
{
Connect(C::Future),
Handshake(Handshake<C::Connection, E, S>),
}
#[derive(Debug)]
pub enum ConnectError<T> {
Connect(T),
Handshake(HandshakeError),
}
impl<A, C, E, S> Connect<A, C, E, S>
where
C: MakeConnection<A>,
E: Executor<Background<C::Connection, S>> + Clone,
S: Body,
S::Data: 'static,
S::Error: Into<Box<dyn std::error::Error>>,
{
pub fn new(inner: C, builder: h2::client::Builder, executor: E) -> Self {
Connect {
inner,
executor,
builder,
_p: PhantomData,
}
}
}
impl<A, C, E, S> Service<A> for Connect<A, C, E, S>
where
C: MakeConnection<A> + 'static,
E: Executor<Background<C::Connection, S>> + Clone,
S: Body + 'static,
S::Error: Into<Box<dyn std::error::Error>>,
{
type Response = Connection<C::Connection, E, S>;
type Error = ConnectError<C::Error>;
type Future = ConnectFuture<A, C, E, S>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.inner.poll_ready().map_err(ConnectError::Connect)
}
fn call(&mut self, target: A) -> Self::Future {
let state = State::Connect(self.inner.make_connection(target));
let builder = self.builder.clone();
ConnectFuture {
state,
builder,
executor: Some(self.executor.clone()),
}
}
}
impl<A, C, E, S> Future for ConnectFuture<A, C, E, S>
where
C: MakeConnection<A>,
E: Executor<Background<C::Connection, S>> + Clone,
S: Body,
S::Data: 'static,
S::Error: Into<Box<dyn std::error::Error>>,
{
type Item = Connection<C::Connection, E, S>;
type Error = ConnectError<C::Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
let io = match self.state {
State::Connect(ref mut fut) => {
let res = fut.poll().map_err(ConnectError::Connect);
try_ready!(res)
}
State::Handshake(ref mut fut) => {
return fut.poll().map_err(ConnectError::Handshake);
}
};
let executor = self.executor.take().expect("double poll");
let handshake = Handshake::new(io, executor, &self.builder);
self.state = State::Handshake(handshake);
}
}
}
impl<T> fmt::Display for ConnectError<T>
where
T: Error,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConnectError::Connect(ref why) => write!(
f,
"Error attempting to establish underlying session layer: {}",
why
),
ConnectError::Handshake(ref why) => {
write!(f, "Error while performing HTTP/2.0 handshake: {}", why,)
}
}
}
}
impl<T> Error for ConnectError<T>
where
T: Error,
{
fn description(&self) -> &str {
match *self {
ConnectError::Connect(_) => "error attempting to establish underlying session layer",
ConnectError::Handshake(_) => "error performing HTTP/2.0 handshake",
}
}
fn cause(&self) -> Option<&Error> {
match *self {
ConnectError::Connect(ref why) => Some(why),
ConnectError::Handshake(ref why) => Some(why),
}
}
}