Skip to main content

trillium_server_common/
server.rs

1use crate::{RuntimeTrait, Swansong, Transport, UdpTransport};
2use listenfd::ListenFd;
3#[cfg(unix)]
4use std::os::unix::net::UnixListener;
5use std::{future::Future, io::Result, net::TcpListener};
6use trillium::Info;
7
8/// The server trait, for standard network-based server implementations.
9pub trait Server: Sized + Send + Sync + 'static {
10    /// the individual byte stream that http
11    /// will be communicated over. This is often an async "stream"
12    /// like TcpStream or UnixStream. See [`Transport`]
13    type Transport: Transport;
14
15    /// The [`RuntimeTrait`] for this `Server`.
16    type Runtime: RuntimeTrait;
17
18    /// The async UDP socket type for this server. Used by QUIC adapters
19    /// for HTTP/3 support. Runtimes that do not support UDP should set
20    /// this to `()`.
21    type UdpTransport: UdpTransport;
22
23    /// Asynchronously return a single `Self::Transport` from a
24    /// `Self::Listener`. Must be implemented.
25    fn accept(&mut self) -> impl Future<Output = Result<Self::Transport>> + Send;
26
27    /// Populate [`Info`] with data from this server, such as the bound socket address.
28    /// Called during server startup before any connections are accepted.
29    fn init(&self, info: &mut Info) {
30        let _ = info;
31    }
32
33    /// After the server has shut down, perform any housekeeping, eg
34    /// unlinking a unix socket.
35    fn clean_up(self) -> impl Future<Output = ()> + Send {
36        async {}
37    }
38
39    /// Return this `Server`'s `Runtime`
40    fn runtime() -> Self::Runtime;
41
42    /// Build a listener from the config. The default logic for this
43    /// is described elsewhere. To override the default logic, server
44    /// implementations could potentially implement this directly.  To
45    /// use this default logic, implement
46    /// [`Server::from_tcp`] and
47    /// [`Server::from_unix`].
48    fn from_host_and_port(host: &str, port: u16) -> Self {
49        #[cfg(unix)]
50        if host.starts_with(['/', '.', '~']) {
51            log::debug!("using unix listener at {host}");
52            return UnixListener::bind(host)
53                .inspect(|unix_listener| {
54                    log::debug!("listening at {:?}", unix_listener.local_addr().unwrap());
55                })
56                .map(Self::from_unix)
57                .unwrap();
58        }
59
60        let mut listen_fd = ListenFd::from_env();
61
62        #[cfg(unix)]
63        if let Ok(Some(unix_listener)) = listen_fd.take_unix_listener(0) {
64            log::debug!(
65                "using unix listener from systemfd environment {:?}",
66                unix_listener.local_addr().unwrap()
67            );
68            return Self::from_unix(unix_listener);
69        }
70
71        let tcp_listener = listen_fd
72            .take_tcp_listener(0)
73            .ok()
74            .flatten()
75            .inspect(|tcp_listener| {
76                log::debug!(
77                    "using tcp listener from systemfd environment, listening at {:?}",
78                    tcp_listener.local_addr()
79                )
80            })
81            .unwrap_or_else(|| {
82                log::debug!("using tcp listener at {host}:{port}");
83                TcpListener::bind((host, port))
84                    .inspect(|tcp_listener| {
85                        log::debug!("listening at {:?}", tcp_listener.local_addr().unwrap())
86                    })
87                    .unwrap()
88            });
89
90        tcp_listener.set_nonblocking(true).unwrap();
91        Self::from_tcp(tcp_listener)
92    }
93
94    /// Build a Self::Listener from a tcp listener. This is called by
95    /// the [`Server::from_host_and_port`] default implementation, and
96    /// is mandatory if the default implementation is used.
97    fn from_tcp(tcp_listener: TcpListener) -> Self {
98        let _ = tcp_listener;
99        unimplemented!()
100    }
101
102    /// Build a `Self` from a unix listener. This is called by
103    /// the [`Server::from_host_and_port`] default implementation. You
104    /// will want to tag an implementation of this with `#[cfg(unix)]`.
105    #[cfg(unix)]
106    fn from_unix(unix_listener: UnixListener) -> Self {
107        let _ = unix_listener;
108        unimplemented!()
109    }
110
111    /// Implementation hook for listening for any os signals and
112    /// stopping the provided [`Swansong`]. The returned future will be
113    /// spawned using [`RuntimeTrait::spawn`]
114    fn handle_signals(_swansong: Swansong) -> impl Future<Output = ()> + Send {
115        async {}
116    }
117}