use crate::{RuntimeTrait, Swansong, Transport, UdpTransport};
use listenfd::ListenFd;
#[cfg(unix)]
use std::os::unix::net::UnixListener;
use std::{future::Future, io::Result, net::TcpListener};
use trillium::Info;
pub trait Server: Sized + Send + Sync + 'static {
type Transport: Transport;
type Runtime: RuntimeTrait;
type UdpTransport: UdpTransport;
fn accept(&mut self) -> impl Future<Output = Result<Self::Transport>> + Send;
fn init(&self, info: &mut Info) {
let _ = info;
}
fn clean_up(self) -> impl Future<Output = ()> + Send {
async {}
}
fn runtime() -> Self::Runtime;
fn from_host_and_port(host: &str, port: u16) -> Self {
match resolve_listener(host, port).unwrap() {
PreboundListener::Tcp(tcp_listener) => Self::from_tcp(tcp_listener),
#[cfg(unix)]
PreboundListener::Unix(unix_listener) => Self::from_unix(unix_listener),
}
}
fn from_tcp(tcp_listener: TcpListener) -> Self {
let _ = tcp_listener;
unimplemented!()
}
#[cfg(unix)]
fn from_unix(unix_listener: UnixListener) -> Self {
let _ = unix_listener;
unimplemented!()
}
fn handle_signals(_swansong: Swansong) -> impl Future<Output = ()> + Send {
async {}
}
}
#[derive(Debug)]
pub(crate) enum PreboundListener {
Tcp(TcpListener),
#[cfg(unix)]
Unix(UnixListener),
}
pub(crate) fn resolve_listener(host: &str, port: u16) -> Result<PreboundListener> {
#[cfg(unix)]
if host.starts_with(['/', '.', '~']) {
log::debug!("using unix listener at {host}");
let unix_listener = UnixListener::bind(host)?;
log::debug!("listening at {:?}", unix_listener.local_addr());
return Ok(PreboundListener::Unix(unix_listener));
}
let mut listen_fd = ListenFd::from_env();
#[cfg(unix)]
if let Ok(Some(unix_listener)) = listen_fd.take_unix_listener(0) {
log::debug!(
"using unix listener from systemfd environment {:?}",
unix_listener.local_addr()
);
return Ok(PreboundListener::Unix(unix_listener));
}
let tcp_listener = match listen_fd.take_tcp_listener(0).ok().flatten() {
Some(tcp_listener) => {
log::debug!(
"using tcp listener from systemfd environment, listening at {:?}",
tcp_listener.local_addr()
);
tcp_listener
}
None => {
log::debug!("using tcp listener at {host}:{port}");
let tcp_listener = TcpListener::bind((host, port))?;
log::debug!("listening at {:?}", tcp_listener.local_addr());
tcp_listener
}
};
tcp_listener.set_nonblocking(true)?;
Ok(PreboundListener::Tcp(tcp_listener))
}