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
101
102
103
104
105
106
107
108
use std::{
    fmt::{Display, Formatter, Result},
    net::SocketAddr,
};

const DEFAULT_SERVER_DESCRIPTION: &str = concat!("trillium v", env!("CARGO_PKG_VERSION"));

/**
This struct represents information about the currently connected
server.

It is passed to [`Handler::init`](crate::Handler::init) and the [`Init`](crate::Init) handler.
*/

#[derive(Debug, Clone)]
pub struct Info {
    server_description: String,
    listener_description: String,
    tcp_socket_addr: Option<SocketAddr>,
}

impl Default for Info {
    fn default() -> Self {
        Self {
            server_description: DEFAULT_SERVER_DESCRIPTION.into(),
            listener_description: String::new(),
            tcp_socket_addr: None,
        }
    }
}

impl Display for Info {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        f.write_fmt(format_args!(
            "{} listening on {}",
            self.server_description(),
            self.listener_description(),
        ))
    }
}

impl Info {
    /// Returns a user-displayable description of the server. This
    /// might be a string like "trillium x.y.z (trillium-tokio x.y.z)" or "my
    /// special application".
    pub fn server_description(&self) -> &str {
        &self.server_description
    }

    /// Returns a user-displayable string description of the location
    /// or port the listener is bound to, potentially as a url. Do not
    /// rely on the format of this string, as it will vary between
    /// server implementations and is intended for user
    /// display. Instead, use [`Info::tcp_socket_addr`] for any
    /// processing.
    pub fn listener_description(&self) -> &str {
        &self.listener_description
    }

    /// Returns the `local_addr` of a bound tcp listener, if such a
    /// thing exists for this server
    pub const fn tcp_socket_addr(&self) -> Option<&SocketAddr> {
        self.tcp_socket_addr.as_ref()
    }

    /// obtain a mutable borrow of the server description, suitable
    /// for appending information or replacing it
    pub fn server_description_mut(&mut self) -> &mut String {
        &mut self.server_description
    }

    /// obtain a mutable borrow of the listener description, suitable
    /// for appending information or replacing it
    pub fn listener_description_mut(&mut self) -> &mut String {
        &mut self.listener_description
    }
}

impl From<&str> for Info {
    fn from(description: &str) -> Self {
        Self {
            server_description: String::from(DEFAULT_SERVER_DESCRIPTION),
            listener_description: String::from(description),
            ..Self::default()
        }
    }
}

impl From<SocketAddr> for Info {
    fn from(socket_addr: SocketAddr) -> Self {
        Self {
            server_description: String::from(DEFAULT_SERVER_DESCRIPTION),
            listener_description: socket_addr.to_string(),
            tcp_socket_addr: Some(socket_addr),
        }
    }
}

#[cfg(unix)]
impl From<std::os::unix::net::SocketAddr> for Info {
    fn from(s: std::os::unix::net::SocketAddr) -> Self {
        Self {
            server_description: String::from(DEFAULT_SERVER_DESCRIPTION),
            listener_description: format!("{s:?}"),
            tcp_socket_addr: None,
        }
    }
}