use std::{io, sync::Arc};
use xitca_io::net::{Stream, TcpListener};
#[cfg(unix)]
use xitca_io::net::UnixListener;
use tracing::info;
#[cfg(feature = "quic")]
use xitca_io::net::{QuicListener, QuicListenerBuilder};
pub trait Listen: Send + Sync {
fn accept(&self) -> impl Future<Output = io::Result<Stream>> + Send;
}
mod _seal {
use core::{future::Future, pin::Pin};
use super::*;
type BoxFuture<'f, T> = Pin<Box<dyn Future<Output = T> + Send + 'f>>;
#[doc(hidden)]
pub trait ListenDyn: Send + Sync {
fn accept_dyn(&self) -> BoxFuture<'_, io::Result<Stream>>;
}
impl<S> ListenDyn for S
where
S: Listen,
{
#[inline]
fn accept_dyn(&self) -> BoxFuture<'_, io::Result<Stream>> {
Box::pin(Listen::accept(self))
}
}
}
pub(crate) type ListenerDyn = Arc<dyn _seal::ListenDyn>;
impl Listen for TcpListener {
async fn accept(&self) -> io::Result<Stream> {
let (stream, addr) = self.accept().await?;
let stream = stream.into_std()?;
Ok(Stream::Tcp(stream, addr))
}
}
#[cfg(unix)]
impl Listen for UnixListener {
async fn accept(&self) -> io::Result<Stream> {
let (stream, _) = self.accept().await?;
let stream = stream.into_std()?;
let addr = stream.peer_addr()?;
Ok(Stream::Unix(stream, addr))
}
}
#[cfg(feature = "quic")]
impl Listen for QuicListener {
async fn accept(&self) -> io::Result<Stream> {
let stream = self.accept().await?;
let addr = stream.peer_addr();
Ok(Stream::Udp(stream, addr))
}
}
pub trait IntoListener: Send {
type Listener: Listen;
fn into_listener(self) -> io::Result<Self::Listener>;
}
impl IntoListener for std::net::TcpListener {
type Listener = TcpListener;
fn into_listener(self) -> io::Result<Self::Listener> {
self.set_nonblocking(true)?;
let listener = TcpListener::from_std(self)?;
info!("Started Tcp listening on: {:?}", listener.local_addr().ok());
Ok(listener)
}
}
#[cfg(unix)]
impl IntoListener for std::os::unix::net::UnixListener {
type Listener = UnixListener;
fn into_listener(self) -> io::Result<Self::Listener> {
self.set_nonblocking(true)?;
let listener = UnixListener::from_std(self)?;
info!("Started Unix listening on: {:?}", listener.local_addr().ok());
Ok(listener)
}
}
#[cfg(feature = "quic")]
impl IntoListener for QuicListenerBuilder {
type Listener = QuicListener;
fn into_listener(self) -> io::Result<Self::Listener> {
let udp = self.build()?;
info!("Started Udp listening on: {:?}", udp.endpoint().local_addr().ok());
Ok(udp)
}
}