use std::fmt::Debug;
use std::marker::Unpin;
use std::net::SocketAddr;
#[cfg(unix)]
use std::path::{Path, PathBuf};
use futures_core::future::BoxFuture;
use tokio::io::{self, AsyncRead, AsyncWrite};
#[cfg(unix)]
use tokio::net::UnixStream;
use tokio::net::{lookup_host, TcpStream};
pub trait Connector: Send + Sync {
type Stream: AsyncRead + AsyncWrite + Debug + Unpin + Send;
fn connect(&self) -> BoxFuture<'_, io::Result<Self::Stream>>;
}
#[derive(Debug)]
pub struct TcpConnector {
addr: SocketAddr,
}
#[cfg(unix)]
#[derive(Debug)]
pub struct UnixConnector {
path: PathBuf,
}
#[derive(Debug, thiserror::Error)]
pub enum LookupError {
#[error("IO error during DNS lookup")]
Io(#[from] std::io::Error),
#[error("DNS record not found")]
NotFound,
}
impl TcpConnector {
pub fn new(addr: SocketAddr) -> Self {
TcpConnector { addr }
}
pub async fn lookup(addr: &str) -> Result<Self, LookupError> {
let addr = lookup_host(addr)
.await?
.next()
.ok_or(LookupError::NotFound)?;
Ok(TcpConnector::new(addr))
}
}
impl Connector for TcpConnector {
type Stream = TcpStream;
fn connect(&self) -> BoxFuture<'_, io::Result<Self::Stream>> {
Box::pin(TcpStream::connect(self.addr))
}
}
#[cfg(unix)]
impl UnixConnector {
pub fn new<P: AsRef<Path>>(path: P) -> Self {
UnixConnector {
path: path.as_ref().to_owned(),
}
}
}
#[cfg(unix)]
impl Connector for UnixConnector {
type Stream = UnixStream;
fn connect(&self) -> BoxFuture<'_, io::Result<Self::Stream>> {
Box::pin(UnixStream::connect(&self.path))
}
}