use tokio::io::{AsyncRead, AsyncWrite};
use crate::errors::Error;
use crate::models::{ConnectionID, Message, Role, StreamID, Version};
use crate::tls::Security;
use crate::protocol::{h1::H1Connection, h2::H2Connection, h3::H3Connection};
#[allow(async_fn_in_trait)]
pub trait Connection {
fn version(&self) -> Version;
fn role(&self) -> Role;
fn id(&self) -> ConnectionID;
fn reusable(&self) -> bool {
true
}
fn security(&self) -> Security {
Security::default()
}
fn client(&self) -> Option<std::net::SocketAddr> {
None
}
async fn send(&mut self, message: Message) -> Result<(), Error>;
async fn receive(&mut self) -> Result<Message, Error>;
async fn close(&mut self);
}
#[allow(async_fn_in_trait)]
pub trait Stream {
fn id(&self) -> StreamID;
async fn reset(&mut self, code: u64);
}
pub trait Transport: AsyncRead + AsyncWrite + Unpin + Send {}
impl<T: AsyncRead + AsyncWrite + Unpin + Send> Transport for T {}
#[allow(clippy::large_enum_variant)]
pub enum AnyConnection {
H1(H1Connection<Box<dyn Transport>>),
H2(H2Connection<Box<dyn Transport>>),
H3(H3Connection),
}
impl AnyConnection {
pub fn into_transport(self, stream_id: Option<StreamID>) -> Result<(Box<dyn Transport>, Option<crate::protocol::common::Buffer>), Error> {
let named = || stream_id.ok_or_else(|| Error::Protocol("a multiplexed version needs the stream to tunnel".into()));
match self {
Self::H1(connection) => {
let (transport, buffer) = connection.upgrade();
Ok((transport, Some(buffer)))
}
Self::H2(connection) => Ok((Box::new(connection.tunnel(named()?)), None)),
Self::H3(mut connection) => Ok((Box::new(connection.tunnel(named()?)?), None)),
}
}
pub fn with_security(self, security: Security) -> Self {
match self {
Self::H1(connection) => Self::H1(connection.with_security(security)),
Self::H2(connection) => Self::H2(connection.with_security(security)),
Self::H3(connection) => Self::H3(connection),
}
}
}
macro_rules! forward {
(
$(fn $name:ident(&self) -> $ret:ty;)*
$(async fn $sent:ident(&mut self $(, $arg:ident: $ty:ty)*) $(-> $sent_ret:ty)?;)*
) => {
$(
fn $name(&self) -> $ret {
match self {
Self::H1(connection) => connection.$name(),
Self::H2(connection) => connection.$name(),
Self::H3(connection) => connection.$name(),
}
}
)*
$(
async fn $sent(&mut self $(, $arg: $ty)*) $(-> $sent_ret)? {
match self {
Self::H1(connection) => connection.$sent($($arg),*).await,
Self::H2(connection) => connection.$sent($($arg),*).await,
Self::H3(connection) => connection.$sent($($arg),*).await,
}
}
)*
};
}
impl Connection for AnyConnection {
forward! {
fn version(&self) -> Version;
fn role(&self) -> Role;
fn id(&self) -> ConnectionID;
fn reusable(&self) -> bool;
fn security(&self) -> Security;
fn client(&self) -> Option<std::net::SocketAddr>;
async fn send(&mut self, message: Message) -> Result<(), Error>;
async fn receive(&mut self) -> Result<Message, Error>;
async fn close(&mut self);
}
}