Skip to main content

trillium_server_common/
server_handle.rs

1use crate::Runtime;
2use async_cell::sync::AsyncCell;
3use std::{cell::OnceCell, future::IntoFuture, net::SocketAddr, sync::Arc};
4use swansong::{ShutdownCompletion, Swansong};
5use trillium_http::HttpContext;
6
7/// A handle for a spawned trillium server. Returned by
8/// [`Config::handle`][crate::Config::handle] and
9/// [`Config::spawn`][crate::Config::spawn]
10#[derive(Clone, Debug)]
11pub struct ServerHandle {
12    pub(crate) swansong: Swansong,
13    pub(crate) context: Arc<AsyncCell<Arc<HttpContext>>>,
14    pub(crate) received_context: OnceCell<Arc<HttpContext>>,
15    pub(crate) runtime: Runtime,
16}
17
18/// Immutable snapshot of server state after initialization.
19///
20/// Returned by [`ServerHandle::info`]. Contains the bound address, derived URL, and any
21/// values inserted into shared state during [`Handler::init`](trillium::Handler::init).
22#[derive(Debug)]
23pub struct BoundInfo(Arc<HttpContext>);
24
25impl BoundInfo {
26    /// Borrow a type from the [`TypeSet`](trillium::TypeSet) on this `BoundInfo`.
27    pub fn shared_state<T: Send + Sync + 'static>(&self) -> Option<&T> {
28        self.0.shared_state().get()
29    }
30
31    /// Returns the `local_addr` of a bound tcp listener, if such a thing exists for this server
32    pub fn tcp_socket_addr(&self) -> Option<&SocketAddr> {
33        self.shared_state()
34    }
35
36    /// Returns every [`Listener`](trillium::Listener) this server is bound to, in registration
37    /// order. Empty if the server has not populated its listener set.
38    pub fn listeners(&self) -> &[trillium::Listener] {
39        self.shared_state::<trillium::Listeners>()
40            .map_or(&[], |l| &l.0)
41    }
42
43    /// Returns the URL of this server, derived from the bound address, if available
44    pub fn url(&self) -> Option<&url::Url> {
45        self.shared_state()
46    }
47
48    /// Returns the `local_addr` of a bound unix listener, if such a thing exists for this server
49    #[cfg(unix)]
50    pub fn unix_socket_addr(&self) -> Option<&std::os::unix::net::SocketAddr> {
51        self.shared_state()
52    }
53
54    /// Returns a clone of the underlying [`HttpContext`] for this server
55    pub fn context(&self) -> Arc<HttpContext> {
56        self.0.clone()
57    }
58}
59
60impl ServerHandle {
61    /// await server start and retrieve the server's [`Info`](trillium::Info)
62    pub async fn info(&self) -> BoundInfo {
63        if let Some(context) = self.received_context.get().cloned() {
64            return BoundInfo(context);
65        }
66        let arc_context = self.context.get().await;
67        let context = self.received_context.get_or_init(|| arc_context);
68
69        BoundInfo(Arc::clone(context))
70    }
71
72    /// stop server and return a future that can be awaited for it to shut down gracefully
73    pub fn shut_down(&self) -> ShutdownCompletion {
74        self.swansong.shut_down()
75    }
76
77    /// retrieves a clone of the [`Swansong`] used by this server
78    pub fn swansong(&self) -> Swansong {
79        self.swansong.clone()
80    }
81
82    /// retrieves a runtime
83    pub fn runtime(&self) -> Runtime {
84        self.runtime.clone()
85    }
86
87    /// park the current thread until this server shuts down
88    pub fn block(self) {
89        self.into_future().block()
90    }
91}
92
93impl IntoFuture for ServerHandle {
94    type IntoFuture = ShutdownCompletion;
95    type Output = ();
96
97    fn into_future(self) -> Self::IntoFuture {
98        self.swansong.into_future()
99    }
100}