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