use std::io::Result;
use std::future::Future;
use std::fmt::{Display, Formatter};
use super::{IOStream, AsyncAccept, AsyncConnect};
use super::nop::{NopAccept, NopConnect};
use super::ws::{WsConf, WsAccept, WsConnect};
use super::tls::{TlsClientConf, TlsServerConf, TlsAccept, TlsConnect};
#[derive(Debug, Clone)]
pub struct MixClientConf {
pub ws: Option<WsConf>,
pub tls: Option<TlsClientConf>,
}
#[derive(Debug, Clone)]
pub enum MixConnect {
Plain(NopConnect),
Ws(WsConnect<NopConnect>),
Tls(TlsConnect<NopConnect>),
Wss(WsConnect<TlsConnect<NopConnect>>),
}
impl MixConnect {
pub fn new(conf: MixClientConf) -> Self {
use MixConnect::*;
let MixClientConf { ws, tls } = conf;
match (ws, tls) {
(None, None) => Plain(NopConnect {}),
(Some(ws), None) => Ws(WsConnect::new(NopConnect {}, ws)),
(None, Some(tls)) => Tls(TlsConnect::new(NopConnect {}, tls)),
(Some(ws), Some(tls)) => Wss(WsConnect::new(TlsConnect::new(NopConnect {}, tls), ws)),
}
}
pub fn new_shared(conf: MixClientConf) -> Self {
use MixConnect::*;
let MixClientConf { ws, tls } = conf;
match (ws, tls) {
(None, None) => Plain(NopConnect {}),
(Some(ws), None) => Ws(WsConnect::new(NopConnect {}, ws)),
(None, Some(tls)) => Tls(TlsConnect::new_shared(NopConnect {}, tls)),
(Some(ws), Some(tls)) => Wss(WsConnect::new(
TlsConnect::new_shared(NopConnect {}, tls),
ws,
)),
}
}
}
impl<S: IOStream> AsyncConnect<S> for MixConnect {
type Stream = stream::MixClientStream<S>;
type ConnectFut<'a> = impl Future<Output = Result<Self::Stream>> +'a where Self:'a;
fn connect<'a>(&'a self, stream: S, buf: &'a mut [u8]) -> Self::ConnectFut<'_> {
use MixConnect::*;
use stream::MixClientStream as MixS;
async move {
match self {
Plain(cc) => cc.connect(stream, buf).await.map(MixS::Plain),
Ws(cc) => cc.connect(stream, buf).await.map(MixS::Ws),
Tls(cc) => cc.connect(stream, buf).await.map(MixS::Tls),
Wss(cc) => cc.connect(stream, buf).await.map(MixS::Wss),
}
}
}
}
#[derive(Debug, Clone)]
pub struct MixServerConf {
pub ws: Option<WsConf>,
pub tls: Option<TlsServerConf>,
}
#[derive(Debug, Clone)]
pub enum MixAccept {
Plain(NopAccept),
Ws(WsAccept<NopAccept>),
Tls(TlsAccept<NopAccept>),
Wss(WsAccept<TlsAccept<NopAccept>>),
}
impl MixAccept {
pub fn new(conf: MixServerConf) -> Self {
use MixAccept::*;
let MixServerConf { ws, tls } = conf;
match (ws, tls) {
(None, None) => Plain(NopAccept {}),
(Some(ws), None) => Ws(WsAccept::new(NopAccept {}, ws)),
(None, Some(tls)) => Tls(TlsAccept::new(NopAccept {}, tls)),
(Some(ws), Some(tls)) => Wss(WsAccept::new(TlsAccept::new(NopAccept {}, tls), ws)),
}
}
pub fn new_shared(conf: MixServerConf) -> Self {
use MixAccept::*;
let MixServerConf { ws, tls } = conf;
match (ws, tls) {
(None, None) => Plain(NopAccept {}),
(Some(ws), None) => Ws(WsAccept::new(NopAccept {}, ws)),
(None, Some(tls)) => Tls(TlsAccept::new_shared(NopAccept {}, tls)),
(Some(ws), Some(tls)) => {
Wss(WsAccept::new(TlsAccept::new_shared(NopAccept {}, tls), ws))
}
}
}
}
impl<S: IOStream> AsyncAccept<S> for MixAccept {
type Stream = stream::MixServerStream<S>;
type AcceptFut<'a> = impl Future<Output = Result<Self::Stream>> +'a where Self:'a;
fn accept<'a>(&'a self, stream: S, buf: &'a mut [u8]) -> Self::AcceptFut<'a> {
use MixAccept::*;
use stream::MixServerStream as MixS;
async move {
match self {
Plain(ac) => ac.accept(stream, buf).await.map(MixS::Plain),
Ws(ac) => ac.accept(stream, buf).await.map(MixS::Ws),
Tls(ac) => ac.accept(stream, buf).await.map(MixS::Tls),
Wss(ac) => ac.accept(stream, buf).await.map(MixS::Wss),
}
}
}
}
pub use stream::{MixClientStream, MixServerStream};
mod stream {
use std::io::Result;
use std::pin::Pin;
use std::task::{Poll, Context};
use tokio::io::{ReadBuf, AsyncRead, AsyncWrite};
use crate::ws::{WsClientStream, WsServerStream};
use crate::tls::{TlsClientStream, TlsServerStream};
#[derive(Debug)]
pub enum MixClientStream<T> {
Plain(T),
Ws(WsClientStream<T>),
Tls(TlsClientStream<T>),
Wss(WsClientStream<TlsClientStream<T>>),
}
#[derive(Debug)]
pub enum MixServerStream<T> {
Plain(T),
Ws(WsServerStream<T>),
Tls(TlsServerStream<T>),
Wss(WsServerStream<TlsServerStream<T>>),
}
macro_rules! call_each {
($this: ident || $( $name: ident, )+ || $func: ident, $cx: ident, $buf: ident) => {
match $this.get_mut() {
$(
$name(x) => Pin::new(x).$func($cx, $buf),
)+
}
};
($this: ident || $( $name: ident, )+ || $func: ident, $cx: ident) => {
match $this.get_mut() {
$(
$name(x) => Pin::new(x).$func($cx),
)+
}
};
}
macro_rules! impl_async_read {
($stream: ident) => {
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for $stream<T> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<()>> {
use $stream::*;
call_each!(self || Plain, Ws, Tls, Wss, || poll_read, cx, buf)
}
}
};
}
macro_rules! impl_async_write {
($stream: ident) => {
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for $stream<T> {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize>> {
use $stream::*;
call_each!(self || Plain, Ws, Tls, Wss, || poll_write, cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
use $stream::*;
call_each!(self || Plain, Ws, Tls, Wss, || poll_flush, cx)
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
use $stream::*;
call_each!(self || Plain, Ws, Tls, Wss, || poll_shutdown, cx)
}
}
};
}
impl_async_read!(MixClientStream);
impl_async_write!(MixClientStream);
impl_async_read!(MixServerStream);
impl_async_write!(MixServerStream);
}
macro_rules! impl_type_cast {
($mix: ident || $([$func: ident :: $member: ident => $ret: ty], )+ ) => {
impl $mix {
$(
pub fn $func(&self) -> Option<&$ret> {
use $mix::*;
if let $member(x) = self {
Some(x)
} else {
None
}
}
)+
}
};
}
impl_type_cast!(
MixConnect ||
[as_plain :: Plain => NopConnect],
[as_ws :: Ws => WsConnect<NopConnect>],
[as_tls :: Tls => TlsConnect<NopConnect>],
[as_wss :: Wss => WsConnect<TlsConnect<NopConnect>>],
);
impl_type_cast!(
MixAccept ||
[as_plain :: Plain => NopAccept],
[as_ws :: Ws => WsAccept<NopAccept>],
[as_tls :: Tls => TlsAccept<NopAccept>],
[as_wss :: Wss => WsAccept<TlsAccept<NopAccept>>],
);
macro_rules! impl_display {
($mix: ident || $($member: ident,)+ ) => {
impl Display for $mix {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use $mix::*;
match self {
$(
$member(x) => write!(f, "{}", x),
)+
}
}
}
};
}
impl_display!(MixConnect || Plain, Ws, Tls, Wss,);
impl_display!(MixAccept || Plain, Ws, Tls, Wss,);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn print_conn() {
let conf = MixClientConf {
ws: Some(WsConf {
host: String::from("abc"),
path: String::from("chat"),
}),
tls: Some(TlsClientConf {
sni: String::from("abc"),
alpn: vec![Vec::from("h2"), Vec::from("http/1.1")],
insecure: true,
early_data: true,
}),
};
println!("ws: {}", conf.clone().ws.unwrap());
println!("tls: {}", conf.clone().tls.unwrap());
let conn = MixConnect::new(conf);
println!("{}", conn);
}
#[test]
fn print_lis() {
let conf = MixServerConf {
ws: Some(WsConf {
host: String::from("abc"),
path: String::from("chat"),
}),
tls: Some(TlsServerConf {
crt: String::new(),
key: String::new(),
ocsp: String::new(),
server_name: String::from("abc"),
}),
};
println!("ws: {}", conf.clone().ws.unwrap());
println!("tls: {}", conf.clone().tls.unwrap());
let lis = MixAccept::new(conf);
println!("{}", lis);
}
}