refactor(client): breakout connect_to future into separate function
This commit is contained in:
		| @@ -119,6 +119,8 @@ pub struct Parts<T> { | |||||||
| // ========== internal client api | // ========== internal client api | ||||||
|  |  | ||||||
| /// A `Future` for when `SendRequest::poll_ready()` is ready. | /// A `Future` for when `SendRequest::poll_ready()` is ready. | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| #[must_use = "futures do nothing unless polled"] | #[must_use = "futures do nothing unless polled"] | ||||||
| pub(super) struct WhenReady<B> { | pub(super) struct WhenReady<B> { | ||||||
|     tx: Option<SendRequest<B>>, |     tx: Option<SendRequest<B>>, | ||||||
|   | |||||||
| @@ -90,10 +90,9 @@ use http::header::{Entry, HeaderValue, HOST}; | |||||||
| use http::uri::Scheme; | use http::uri::Scheme; | ||||||
|  |  | ||||||
| use body::{Body, Payload}; | use body::{Body, Payload}; | ||||||
| use common::Exec; | use common::{Exec, lazy as hyper_lazy, Lazy}; | ||||||
| use common::lazy as hyper_lazy; |  | ||||||
| use self::connect::{Connect, Destination}; | use self::connect::{Connect, Destination}; | ||||||
| use self::pool::{Pool, Poolable, Reservation}; | use self::pool::{Key as PoolKey, Pool, Poolable, Pooled, Reservation}; | ||||||
|  |  | ||||||
| #[cfg(feature = "runtime")] pub use self::connect::HttpConnector; | #[cfg(feature = "runtime")] pub use self::connect::HttpConnector; | ||||||
|  |  | ||||||
| @@ -261,62 +260,10 @@ where C: Connect + Sync + 'static, | |||||||
|  |  | ||||||
|     //TODO: replace with `impl Future` when stable |     //TODO: replace with `impl Future` when stable | ||||||
|     fn send_request(&self, mut req: Request<B>, domain: &str) -> Box<Future<Item=Response<Body>, Error=ClientError<B>> + Send> { |     fn send_request(&self, mut req: Request<B>, domain: &str) -> Box<Future<Item=Response<Body>, Error=ClientError<B>> + Send> { | ||||||
|         let url = req.uri().clone(); |  | ||||||
|         let ver = self.ver; |         let ver = self.ver; | ||||||
|         let pool_key = (Arc::new(domain.to_string()), self.ver); |         let pool_key = (Arc::new(domain.to_string()), self.ver); | ||||||
|         let checkout = self.pool.checkout(pool_key.clone()); |         let checkout = self.pool.checkout(pool_key.clone()); | ||||||
|         let connect = { |         let connect = self.connect_to(req.uri().clone(), pool_key); | ||||||
|             let executor = self.executor.clone(); |  | ||||||
|             let pool = self.pool.clone(); |  | ||||||
|             let h1_writev = self.h1_writev; |  | ||||||
|             let h1_title_case_headers = self.h1_title_case_headers; |  | ||||||
|             let connector = self.connector.clone(); |  | ||||||
|             let dst = Destination { |  | ||||||
|                 uri: url, |  | ||||||
|             }; |  | ||||||
|             hyper_lazy(move || { |  | ||||||
|                 if let Some(connecting) = pool.connecting(&pool_key) { |  | ||||||
|                     Either::A(connector.connect(dst) |  | ||||||
|                         .map_err(::Error::new_connect) |  | ||||||
|                         .and_then(move |(io, connected)| { |  | ||||||
|                             conn::Builder::new() |  | ||||||
|                                 .exec(executor.clone()) |  | ||||||
|                                 .h1_writev(h1_writev) |  | ||||||
|                                 .h1_title_case_headers(h1_title_case_headers) |  | ||||||
|                                 .http2_only(pool_key.1 == Ver::Http2) |  | ||||||
|                                 .handshake(io) |  | ||||||
|                                 .and_then(move |(tx, conn)| { |  | ||||||
|                                     let bg = executor.execute(conn.map_err(|e| { |  | ||||||
|                                         debug!("client connection error: {}", e) |  | ||||||
|                                     })); |  | ||||||
|  |  | ||||||
|                                     // This task is critical, so an execute error |  | ||||||
|                                     // should be returned. |  | ||||||
|                                     if let Err(err) = bg { |  | ||||||
|                                         warn!("error spawning critical client task: {}", err); |  | ||||||
|                                         return Either::A(future::err(err)); |  | ||||||
|                                     } |  | ||||||
|  |  | ||||||
|                                     // Wait for 'conn' to ready up before we |  | ||||||
|                                     // declare this tx as usable |  | ||||||
|                                     Either::B(tx.when_ready()) |  | ||||||
|                                 }) |  | ||||||
|                                 .map(move |tx| { |  | ||||||
|                                     pool.pooled(connecting, PoolClient { |  | ||||||
|                                         is_proxied: connected.is_proxied, |  | ||||||
|                                         tx: match ver { |  | ||||||
|                                             Ver::Http1 => PoolTx::Http1(tx), |  | ||||||
|                                             Ver::Http2 => PoolTx::Http2(tx.into_http2()), |  | ||||||
|                                         }, |  | ||||||
|                                     }) |  | ||||||
|                                 }) |  | ||||||
|                         })) |  | ||||||
|                 } else { |  | ||||||
|                     let canceled = ::Error::new_canceled(Some("HTTP/2 connection in progress")); |  | ||||||
|                     Either::B(future::err(canceled)) |  | ||||||
|                 } |  | ||||||
|             }) |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         let executor = self.executor.clone(); |         let executor = self.executor.clone(); | ||||||
|         // The order of the `select` is depended on below... |         // The order of the `select` is depended on below... | ||||||
| @@ -486,6 +433,69 @@ where C: Connect + Sync + 'static, | |||||||
|  |  | ||||||
|         Box::new(resp) |         Box::new(resp) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn connect_to(&self, uri: Uri, pool_key: PoolKey) | ||||||
|  |         -> impl Lazy<Item=Pooled<PoolClient<B>>, Error=::Error> | ||||||
|  |     { | ||||||
|  |         let executor = self.executor.clone(); | ||||||
|  |         let pool = self.pool.clone(); | ||||||
|  |         let h1_writev = self.h1_writev; | ||||||
|  |         let h1_title_case_headers = self.h1_title_case_headers; | ||||||
|  |         let connector = self.connector.clone(); | ||||||
|  |         let ver = pool_key.1; | ||||||
|  |         let dst = Destination { | ||||||
|  |             uri, | ||||||
|  |         }; | ||||||
|  |         hyper_lazy(move || { | ||||||
|  |             // Try to take a "connecting lock". | ||||||
|  |             // | ||||||
|  |             // If the pool_key is for HTTP/2, and there is already a | ||||||
|  |             // connection being estabalished, then this can't take a | ||||||
|  |             // second lock. The "connect_to" future is Canceled. | ||||||
|  |             let connecting = match pool.connecting(&pool_key) { | ||||||
|  |                 Some(lock) => lock, | ||||||
|  |                 None => { | ||||||
|  |                     let canceled = ::Error::new_canceled(Some("HTTP/2 connection in progress")); | ||||||
|  |                     return Either::B(future::err(canceled)); | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |             Either::A(connector.connect(dst) | ||||||
|  |                 .map_err(::Error::new_connect) | ||||||
|  |                 .and_then(move |(io, connected)| { | ||||||
|  |                     conn::Builder::new() | ||||||
|  |                         .exec(executor.clone()) | ||||||
|  |                         .h1_writev(h1_writev) | ||||||
|  |                         .h1_title_case_headers(h1_title_case_headers) | ||||||
|  |                         .http2_only(pool_key.1 == Ver::Http2) | ||||||
|  |                         .handshake(io) | ||||||
|  |                         .and_then(move |(tx, conn)| { | ||||||
|  |                             let bg = executor.execute(conn.map_err(|e| { | ||||||
|  |                                 debug!("client connection error: {}", e) | ||||||
|  |                             })); | ||||||
|  |  | ||||||
|  |                             // This task is critical, so an execute error | ||||||
|  |                             // should be returned. | ||||||
|  |                             if let Err(err) = bg { | ||||||
|  |                                 warn!("error spawning critical client task: {}", err); | ||||||
|  |                                 return Either::A(future::err(err)); | ||||||
|  |                             } | ||||||
|  |  | ||||||
|  |                             // Wait for 'conn' to ready up before we | ||||||
|  |                             // declare this tx as usable | ||||||
|  |                             Either::B(tx.when_ready()) | ||||||
|  |                         }) | ||||||
|  |                         .map(move |tx| { | ||||||
|  |                             pool.pooled(connecting, PoolClient { | ||||||
|  |                                 is_proxied: connected.is_proxied, | ||||||
|  |                                 tx: match ver { | ||||||
|  |                                     Ver::Http1 => PoolTx::Http1(tx), | ||||||
|  |                                     Ver::Http2 => PoolTx::Http2(tx.into_http2()), | ||||||
|  |                                 }, | ||||||
|  |                             }) | ||||||
|  |                         }) | ||||||
|  |                 })) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<C, B> Clone for Client<C, B> { | impl<C, B> Clone for Client<C, B> { | ||||||
| @@ -588,6 +598,8 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| struct PoolClient<B> { | struct PoolClient<B> { | ||||||
|     is_proxied: bool, |     is_proxied: bool, | ||||||
|     tx: PoolTx<B>, |     tx: PoolTx<B>, | ||||||
|   | |||||||
| @@ -12,6 +12,8 @@ use tokio_timer::Interval; | |||||||
| use common::Exec; | use common::Exec; | ||||||
| use super::Ver; | use super::Ver; | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) struct Pool<T> { | pub(super) struct Pool<T> { | ||||||
|     inner: Arc<PoolInner<T>>, |     inner: Arc<PoolInner<T>>, | ||||||
| } | } | ||||||
| @@ -34,6 +36,8 @@ pub(super) trait Poolable: Send + Sized + 'static { | |||||||
| /// | /// | ||||||
| /// Specifically, HTTP/1 requires a unique reservation, but HTTP/2 can be | /// Specifically, HTTP/1 requires a unique reservation, but HTTP/2 can be | ||||||
| /// used for multiple requests. | /// used for multiple requests. | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) enum Reservation<T> { | pub(super) enum Reservation<T> { | ||||||
|     /// This connection could be used multiple times, the first one will be |     /// This connection could be used multiple times, the first one will be | ||||||
|     /// reinserted into the `idle` pool, and the second will be given to |     /// reinserted into the `idle` pool, and the second will be given to | ||||||
| @@ -45,7 +49,7 @@ pub(super) enum Reservation<T> { | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Simple type alias in case the key type needs to be adjusted. | /// Simple type alias in case the key type needs to be adjusted. | ||||||
| type Key = (Arc<String>, Ver); | pub(super) type Key = (Arc<String>, Ver); | ||||||
|  |  | ||||||
| struct PoolInner<T> { | struct PoolInner<T> { | ||||||
|     connections: Mutex<Connections<T>>, |     connections: Mutex<Connections<T>>, | ||||||
| @@ -85,8 +89,17 @@ struct Connections<T> { | |||||||
| struct WeakOpt<T>(Option<Weak<T>>); | struct WeakOpt<T>(Option<Weak<T>>); | ||||||
|  |  | ||||||
| // Newtypes to act as keyword arguments for `Pool::new`... | // Newtypes to act as keyword arguments for `Pool::new`... | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) struct Enabled(pub(super) bool); | pub(super) struct Enabled(pub(super) bool); | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) struct IdleTimeout(pub(super) Option<Duration>); | pub(super) struct IdleTimeout(pub(super) Option<Duration>); | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) struct MaxIdlePerHost(pub(super) usize); | pub(super) struct MaxIdlePerHost(pub(super) usize); | ||||||
|  |  | ||||||
| impl<T> Pool<T> { | impl<T> Pool<T> { | ||||||
| @@ -593,6 +606,8 @@ struct Idle<T> { | |||||||
|     value: T, |     value: T, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) struct Checkout<T> { | pub(super) struct Checkout<T> { | ||||||
|     key: Key, |     key: Key, | ||||||
|     pool: Pool<T>, |     pool: Pool<T>, | ||||||
| @@ -662,6 +677,8 @@ impl<T> Drop for Checkout<T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
| pub(super) struct Connecting<T: Poolable> { | pub(super) struct Connecting<T: Poolable> { | ||||||
|     key: Key, |     key: Key, | ||||||
|     pool: WeakOpt<PoolInner<T>>, |     pool: WeakOpt<PoolInner<T>>, | ||||||
|   | |||||||
| @@ -2,6 +2,10 @@ use std::mem; | |||||||
|  |  | ||||||
| use futures::{Future, IntoFuture, Poll}; | use futures::{Future, IntoFuture, Poll}; | ||||||
|  |  | ||||||
|  | pub(crate) trait Started: Future { | ||||||
|  |     fn started(&self) -> bool; | ||||||
|  | } | ||||||
|  |  | ||||||
| pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R> | pub(crate) fn lazy<F, R>(func: F) -> Lazy<F, R> | ||||||
| where | where | ||||||
|     F: FnOnce() -> R, |     F: FnOnce() -> R, | ||||||
| @@ -12,7 +16,9 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct Lazy<F, R: IntoFuture> { | // FIXME: allow() required due to `impl Trait` leaking types to this lint | ||||||
|  | #[allow(missing_debug_implementations)] | ||||||
|  | pub(crate) struct Lazy<F, R: IntoFuture> { | ||||||
|     inner: Inner<F, R::Future> |     inner: Inner<F, R::Future> | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -22,12 +28,12 @@ enum Inner<F, R> { | |||||||
|     Empty, |     Empty, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<F, R> Lazy<F, R> | impl<F, R> Started for Lazy<F, R> | ||||||
| where | where | ||||||
|     F: FnOnce() -> R, |     F: FnOnce() -> R, | ||||||
|     R: IntoFuture, |     R: IntoFuture, | ||||||
| { | { | ||||||
|     pub fn started(&self) -> bool { |     fn started(&self) -> bool { | ||||||
|         match self.inner { |         match self.inner { | ||||||
|             Inner::Init(_) => false, |             Inner::Init(_) => false, | ||||||
|             Inner::Fut(_) | |             Inner::Fut(_) | | ||||||
| @@ -61,3 +67,4 @@ where | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,5 +9,5 @@ mod never; | |||||||
|  |  | ||||||
| pub(crate) use self::buf::StaticBuf; | pub(crate) use self::buf::StaticBuf; | ||||||
| pub(crate) use self::exec::Exec; | pub(crate) use self::exec::Exec; | ||||||
| pub(crate) use self::lazy::lazy; | pub(crate) use self::lazy::{lazy, Started as Lazy}; | ||||||
| pub use self::never::Never; | pub use self::never::Never; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user