pass_it_on/
configuration.rs

1#[cfg(all(feature = "parse-cfg", feature = "client"))]
2pub mod client_configuration_file;
3#[cfg(all(feature = "parse-cfg", feature = "server"))]
4pub mod server_configuration_file;
5
6#[cfg(feature = "server")]
7use crate::endpoints::{Endpoint, EndpointChannel, EndpointConfig};
8use crate::interfaces::{Interface, InterfaceConfig};
9use crate::notifications::Key;
10use crate::Error;
11
12#[cfg(feature = "server")]
13/// Server configuration that can be used to start the server.
14#[derive(Debug)]
15pub struct ServerConfiguration {
16    key: Key,
17    interfaces: Vec<Box<dyn Interface + Send>>,
18    endpoints: Vec<Box<dyn Endpoint + Send>>,
19}
20
21#[cfg(feature = "server")]
22impl ServerConfiguration {
23    /// Create a new `ServerConfiguration`.
24    pub fn new<S: AsRef<str>>(
25        key: S,
26        interfaces: Vec<Box<dyn Interface + Send>>,
27        endpoints: Vec<Box<dyn Endpoint + Send>>,
28    ) -> Result<Self, Error> {
29        let key = Key::derive_shared_key(key);
30        let config = Self { key, interfaces, endpoints };
31        Self::validate(config)
32    }
33
34    pub(crate) fn endpoint_channels(&self) -> Vec<EndpointChannel> {
35        use crate::notifications::ValidatedNotification;
36        use crate::CHANNEL_BUFFER;
37        use tokio::sync::broadcast;
38        use tokio::sync::broadcast::{Receiver, Sender};
39
40        let mut endpoints = Vec::new();
41        for endpoint in &self.endpoints {
42            let (endpoint_tx, _endpoint_rx): (Sender<ValidatedNotification>, Receiver<ValidatedNotification>) =
43                broadcast::channel(CHANNEL_BUFFER);
44            let keys = endpoint.generate_keys(&self.key);
45            endpoints.push(EndpointChannel::from(endpoint.clone(), endpoint_tx, keys));
46        }
47        endpoints
48    }
49
50    /// Return server [`Key`] value.
51    pub fn key(&self) -> &Key {
52        &self.key
53    }
54
55    /// Return all server interfaces.
56    pub fn interfaces(&self) -> Vec<Box<dyn Interface + Send>> {
57        self.interfaces.clone()
58    }
59
60    /// Return all server endpoints.
61    pub fn endpoints(&self) -> &[Box<dyn Endpoint + Send>] {
62        &self.endpoints
63    }
64
65    fn validate(config: ServerConfiguration) -> Result<ServerConfiguration, Error> {
66        if config.interfaces.is_empty() {
67            return Err(Error::MissingInterface);
68        }
69
70        if config.endpoints.is_empty() {
71            return Err(Error::MissingEndpoint);
72        }
73
74        Ok(config)
75    }
76}
77
78#[cfg(all(feature = "parse-cfg", feature = "server"))]
79impl TryFrom<&str> for ServerConfiguration {
80    type Error = Error;
81
82    fn try_from(value: &str) -> Result<Self, Self::Error> {
83        server_configuration_file::ServerConfigFileParser::from(value)
84    }
85}
86
87#[cfg(feature = "client")]
88/// Client configuration that can be used to start the client.
89#[derive(Debug)]
90pub struct ClientConfiguration {
91    key: Key,
92    interfaces: Vec<Box<dyn Interface + Send>>,
93}
94
95#[cfg(feature = "client")]
96impl ClientConfiguration {
97    /// Create a new `ClientConfiguration`.
98    pub fn new<S: AsRef<str>>(key: S, interfaces: Vec<Box<dyn Interface + Send>>) -> Result<Self, Error> {
99        let key = Key::derive_shared_key(key);
100        let config = Self { key, interfaces };
101        Self::validate(config)
102    }
103
104    /// Return client [`Key`] value.
105    pub fn key(&self) -> &Key {
106        &self.key
107    }
108
109    /// Return all client interfaces.
110    pub fn interfaces(&self) -> Vec<Box<dyn Interface + Send>> {
111        self.interfaces.clone()
112    }
113
114    fn validate(config: ClientConfiguration) -> Result<ClientConfiguration, Error> {
115        if config.interfaces.is_empty() {
116            return Err(Error::MissingInterface);
117        }
118        Ok(config)
119    }
120}
121
122#[cfg(all(feature = "parse-cfg", feature = "client"))]
123impl TryFrom<&str> for ClientConfiguration {
124    type Error = Error;
125
126    fn try_from(value: &str) -> Result<Self, Self::Error> {
127        client_configuration_file::ClientConfigFileParser::from(value)
128    }
129}
130
131#[cfg(all(feature = "parse-cfg", any(feature = "client", feature = "server")))]
132fn collect_interfaces(
133    interface_configs: Vec<Box<dyn InterfaceConfig>>,
134) -> Result<Vec<Box<dyn Interface + Send>>, Error> {
135    interface_configs.iter().map(|cfg| cfg.to_interface()).collect()
136}
137
138#[cfg(all(feature = "parse-cfg", feature = "server"))]
139fn collect_endpoints(endpoint_configs: Vec<Box<dyn EndpointConfig>>) -> Result<Vec<Box<dyn Endpoint + Send>>, Error> {
140    endpoint_configs.iter().map(|cfg| cfg.to_endpoint()).collect()
141}