use crate::{buf::SendBuf, flush::Flush, recv_body::RecvBody}; use futures_util::{future, FutureExt, TryFutureExt}; use h2::{client::SendRequest, RecvStream}; use http::{Request, Response}; use http_body::Body; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; use tower_service::Service; type BoxFuture = Pin + Send + 'static>>; pub struct Connection where B: Body + Unpin, B::Data: Unpin, { client: SendRequest>, } impl Connection where B: Body + Send + Unpin + 'static, B::Data: Send + Unpin + 'static, B::Error: Into>, { pub async fn handshake(io: T) -> Result, h2::Error> where T: AsyncRead + AsyncWrite + Send + Unpin + 'static, { let builder = h2::client::Builder::new(); let (client, conn) = builder.handshake(io).await?; tokio_executor::spawn(conn.map_err(|e| println!("ERROR={}", e)).map(drop)); Ok(Connection { client }) } pub async fn send(&mut self, request: Request) -> Result, h2::Error> { future::poll_fn(|cx| self.poll_ready(cx)).await?; self.call(request).await } } impl Service> for Connection where B: Body + Send + Unpin + 'static, B::Data: Send + Unpin + 'static, B::Error: Into>, { type Response = Response; type Error = h2::Error; type Future = BoxFuture>; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.client.poll_ready(cx) } fn call(&mut self, request: Request) -> Self::Future { let (parts, body) = request.into_parts(); let request = Request::from_parts(parts, ()); let eos = body.is_end_stream(); let res = self.client.send_request(request, eos); let (response, send_body) = match res { Ok(success) => success, Err(e) => { return Box::pin(future::err(e)); } }; if !eos { let flush = Flush::new(body, send_body); tokio_executor::spawn(flush.map(drop)); } Box::pin(response.map_ok(|r| r.map(RecvBody::new))) } }