use std::sync::Arc;
use tokio::{
io::{AsyncRead, AsyncWrite},
net::{TcpStream, UnixStream},
};
use crate::endpoint::{
datagram::Session,
sys::PathGuard,
unix::{dgram::UnixDgramSocket, seqpacket::SeqpacketConn},
};
pub type SyncRead = Box<dyn std::io::Read + Send>;
pub type SyncWrite = Box<dyn std::io::Write + Send>;
pub type BoxRead = Box<dyn AsyncRead + Unpin + Send>;
pub type BoxWrite = Box<dyn AsyncWrite + Unpin + Send>;
pub trait AsyncStream: AsyncRead + AsyncWrite + Unpin + Send {}
impl<T: AsyncRead + AsyncWrite + Unpin + Send> AsyncStream for T {}
#[derive(Default)]
pub struct SyncHalves {
pub reader: Option<SyncRead>,
pub writer: Option<SyncWrite>,
pub guard: Option<PathGuard>,
}
pub struct Connection {
pub stream: EndpointStream,
pub guard: Option<PathGuard>,
pub keepalive: Option<Box<dyn Send>>,
}
impl Connection {
#[must_use]
pub fn with_keepalive(mut self, keepalive: impl Send + 'static) -> Self {
self.keepalive = Some(Box::new(keepalive));
self
}
}
pub enum EndpointStream {
Duplex(Box<dyn AsyncStream>),
Split(BoxRead, BoxWrite),
ReadOnly(BoxRead),
WriteOnly(BoxWrite),
Datagram(DatagramSocket),
}
#[derive(Clone)]
pub enum DatagramSocket {
Udp(Arc<tokio::net::UdpSocket>),
UnixDgram(Arc<UnixDgramSocket>),
Seqpacket(Arc<SeqpacketConn>),
Session(Arc<Session>),
}
impl DatagramSocket {
pub async fn recv(&self, buf: &mut [u8]) -> std::io::Result<Option<usize>> {
match self {
DatagramSocket::Udp(socket) => socket.recv(buf).await.map(Some),
DatagramSocket::UnixDgram(socket) => socket.recv(buf).await.map(Some),
DatagramSocket::Seqpacket(socket) => socket.recv(buf).await,
DatagramSocket::Session(session) => session.recv(buf).await,
}
}
pub async fn send(&self, buf: &[u8]) -> std::io::Result<usize> {
match self {
DatagramSocket::Udp(socket) => socket.send(buf).await,
DatagramSocket::UnixDgram(socket) => socket.send(buf).await,
DatagramSocket::Seqpacket(socket) => socket.send(buf).await,
DatagramSocket::Session(session) => session.send(buf).await,
}
}
pub fn finish(&self) {
if let DatagramSocket::Seqpacket(socket) = self {
socket.finish();
}
}
}
pub enum ReadHalf {
Stream(BoxRead),
Datagram(DatagramSocket),
}
pub enum WriteHalf {
Stream(BoxWrite),
Datagram(DatagramSocket),
}
impl EndpointStream {
pub fn into_connection(self) -> Connection {
Connection {
stream: self,
guard: None,
keepalive: None,
}
}
pub fn into_connection_with_guard(self, guard: Option<PathGuard>) -> Connection {
Connection {
stream: self,
guard,
keepalive: None,
}
}
pub fn tcp(s: TcpStream) -> Self {
Self::Duplex(Box::new(s))
}
pub fn unix(s: UnixStream) -> Self {
Self::Duplex(Box::new(s))
}
pub fn stdio() -> Self {
Self::Split(Box::new(tokio::io::stdin()), Box::new(tokio::io::stdout()))
}
pub fn read_only(r: impl AsyncRead + Unpin + Send + 'static) -> Self {
Self::ReadOnly(Box::new(r))
}
pub fn write_only(w: impl AsyncWrite + Unpin + Send + 'static) -> Self {
Self::WriteOnly(Box::new(w))
}
pub fn datagram(socket: tokio::net::UdpSocket) -> Self {
Self::Datagram(DatagramSocket::Udp(Arc::new(socket)))
}
pub fn seqpacket(socket: tokio_seqpacket::UnixSeqpacket) -> Self {
Self::Datagram(DatagramSocket::Seqpacket(Arc::new(SeqpacketConn::new(
socket,
))))
}
pub fn unix_dgram(socket: UnixDgramSocket) -> Self {
Self::Datagram(DatagramSocket::UnixDgram(Arc::new(socket)))
}
pub fn datagram_session(session: Session) -> Self {
Self::Datagram(DatagramSocket::Session(Arc::new(session)))
}
pub fn into_halves(self) -> (Option<ReadHalf>, Option<WriteHalf>) {
match self {
Self::Duplex(s) => {
let (r, w) = tokio::io::split(s);
(
Some(ReadHalf::Stream(Box::new(r))),
Some(WriteHalf::Stream(Box::new(w))),
)
}
Self::Split(r, w) => (Some(ReadHalf::Stream(r)), Some(WriteHalf::Stream(w))),
Self::ReadOnly(r) => (Some(ReadHalf::Stream(r)), None),
Self::WriteOnly(w) => (None, Some(WriteHalf::Stream(w))),
Self::Datagram(socket) => (
Some(ReadHalf::Datagram(socket.clone())),
Some(WriteHalf::Datagram(socket)),
),
}
}
}