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 the URL of this server, derived from the bound address, if available
37    pub fn url(&self) -> Option<&url::Url> {
38        self.shared_state()
39    }
40
41    /// Returns the `local_addr` of a bound unix listener, if such a thing exists for this server
42    #[cfg(unix)]
43    pub fn unix_socket_addr(&self) -> Option<&std::os::unix::net::SocketAddr> {
44        self.shared_state()
45    }
46
47    /// Returns a clone of the underlying [`HttpContext`] for this server
48    pub fn context(&self) -> Arc<HttpContext> {
49        self.0.clone()
50    }
51}
52
53impl ServerHandle {
54    /// await server start and retrieve the server's [`Info`](trillium::Info)
55    pub async fn info(&self) -> BoundInfo {
56        if let Some(context) = self.received_context.get().cloned() {
57            return BoundInfo(context);
58        }
59        let arc_context = self.context.get().await;
60        let context = self.received_context.get_or_init(|| arc_context);
61
62        BoundInfo(Arc::clone(context))
63    }
64
65    /// stop server and return a future that can be awaited for it to shut down gracefully
66    pub fn shut_down(&self) -> ShutdownCompletion {
67        self.swansong.shut_down()
68    }
69
70    /// retrieves a clone of the [`Swansong`] used by this server
71    pub fn swansong(&self) -> Swansong {
72        self.swansong.clone()
73    }
74
75    /// retrieves a runtime
76    pub fn runtime(&self) -> Runtime {
77        self.runtime.clone()
78    }
79}
80
81impl IntoFuture for ServerHandle {
82    type IntoFuture = ShutdownCompletion;
83    type Output = ();
84
85    fn into_future(self) -> Self::IntoFuture {
86        self.swansong.into_future()
87    }
88}