use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use moirai_async::io::{AsyncRead, AsyncWrite};
use moirai_async::net::TcpStream;
use moirai_tls::{ServerName, TlsConnector, TlsStream};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Origin {
pub secure: bool,
pub host: String,
pub port: u16,
}
impl Origin {
#[must_use]
pub fn authority(&self) -> String {
format!("{}:{}", self.host, self.port)
}
#[must_use]
pub fn host_header(&self) -> String {
let default = if self.secure { 443 } else { 80 };
if self.port == default {
self.host.clone()
} else {
format!("{}:{}", self.host, self.port)
}
}
}
pub enum Conn {
Plain(TcpStream),
Tls(Box<TlsStream<TcpStream>>),
}
impl Conn {
pub async fn connect(origin: &Origin, tls: &TlsConnector) -> io::Result<Self> {
let tcp = TcpStream::connect(&origin.authority()).await?;
if origin.secure {
let domain = ServerName::try_from(origin.host.clone())
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let stream = tls.connect(domain, tcp).await?;
Ok(Conn::Tls(Box::new(stream)))
} else {
Ok(Conn::Plain(tcp))
}
}
}
impl AsyncRead for Conn {
#[inline]
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
match self.get_mut() {
Conn::Plain(s) => AsyncRead::poll_read(Pin::new(s), cx, buf),
Conn::Tls(s) => AsyncRead::poll_read(Pin::new(s.as_mut()), cx, buf),
}
}
}
impl AsyncWrite for Conn {
#[inline]
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
match self.get_mut() {
Conn::Plain(s) => AsyncWrite::poll_write(Pin::new(s), cx, buf),
Conn::Tls(s) => AsyncWrite::poll_write(Pin::new(s.as_mut()), cx, buf),
}
}
#[inline]
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
Conn::Plain(s) => AsyncWrite::poll_flush(Pin::new(s), cx),
Conn::Tls(s) => AsyncWrite::poll_flush(Pin::new(s.as_mut()), cx),
}
}
#[inline]
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
Conn::Plain(s) => AsyncWrite::poll_shutdown(Pin::new(s), cx),
Conn::Tls(s) => AsyncWrite::poll_shutdown(Pin::new(s.as_mut()), cx),
}
}
}