use std::{
future::Future,
task::{Context, Poll},
pin::Pin,
};
use futures::ready;
use tokio::net::TcpStream;
use tower_service::Service;
use hyper::{
Uri,
client::{
connect::{Connection, Connected},
HttpConnector,
},
};
use super::{SalsaStream, Connector};
#[derive(Clone)]
pub struct HyperSalsaConnector {
http: HttpConnector,
connector: Connector,
}
impl HyperSalsaConnector {
pub fn new(http: HttpConnector, connector: Connector) -> Self {
Self { http, connector }
}
pub fn new_http(connector: Connector) -> Self {
Self::new(HttpConnector::new(), connector)
}
}
type BoxErr = Box<dyn std::error::Error + Send + Sync>;
impl Service<Uri> for HyperSalsaConnector {
type Response = SalsaStream<TcpStream>;
type Error = BoxErr;
type Future = HyperSalsaConnecting;
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
match ready!(self.http.poll_ready(ctx)) {
Ok(()) => Poll::Ready(Ok(())),
Err(e) => Poll::Ready(Err(e.into()))
}
}
fn call(&mut self, dst: Uri) -> Self::Future {
let tcp_connecting = self.http.call(dst);
let connector = self.connector.clone();
let fut = async move {
let socket = tcp_connecting
.await?;
let wrapped = connector
.connect(socket)
.await?;
Ok(wrapped)
};
HyperSalsaConnecting(Box::pin(fut))
}
}
type BoxFut = Pin<Box<dyn Future<Output = Result<SalsaStream<TcpStream>, BoxErr>> + Send>>;
pub struct HyperSalsaConnecting(BoxFut);
impl Future for HyperSalsaConnecting {
type Output = Result<SalsaStream<TcpStream>, BoxErr>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.0).poll(ctx)
}
}
impl<T> Connection for SalsaStream<T> {
fn connected(&self) -> Connected {
Connected::new()
}
}