relay_knowledge/net/
mod.rs1use std::{
8 error::Error,
9 fmt,
10 sync::{Arc, RwLock},
11};
12
13use crate::env::{EnvError, EnvironmentConfig, NetworkEnvOverrides};
14
15pub mod http;
16pub mod qos;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct NetworkConfig {
21 pub http: http::HttpConfig,
22 pub qos: qos::QosPolicy,
23}
24
25impl NetworkConfig {
26 pub fn from_overrides(overrides: &NetworkEnvOverrides) -> Result<Self, NetworkConfigError> {
28 Ok(Self {
29 http: http::HttpConfig::from_overrides(overrides).map_err(NetworkConfigError::Http)?,
30 qos: qos::QosPolicy::from_overrides(overrides).map_err(NetworkConfigError::Qos)?,
31 })
32 }
33}
34
35#[derive(Debug, Clone)]
37pub struct NetworkRuntime {
38 inner: Arc<RwLock<NetworkConfig>>,
39}
40
41impl NetworkRuntime {
42 pub fn from_config(config: NetworkConfig) -> Self {
44 Self {
45 inner: Arc::new(RwLock::new(config)),
46 }
47 }
48
49 pub fn from_overrides(overrides: &NetworkEnvOverrides) -> Result<Self, NetworkConfigError> {
51 NetworkConfig::from_overrides(overrides).map(Self::from_config)
52 }
53
54 pub fn current(&self) -> NetworkConfig {
56 self.inner
57 .read()
58 .unwrap_or_else(|poisoned| poisoned.into_inner())
59 .clone()
60 }
61
62 pub fn refresh_from_overrides(
64 &self,
65 overrides: &NetworkEnvOverrides,
66 ) -> Result<NetworkConfig, NetworkConfigError> {
67 let config = NetworkConfig::from_overrides(overrides)?;
68
69 *self
70 .inner
71 .write()
72 .unwrap_or_else(|poisoned| poisoned.into_inner()) = config.clone();
73
74 Ok(config)
75 }
76
77 pub fn refresh_from_environment(
79 &self,
80 environment: &EnvironmentConfig,
81 ) -> Result<NetworkConfig, NetworkConfigError> {
82 self.refresh_from_overrides(&environment.network)
83 }
84
85 pub fn refresh_from_process_environment(&self) -> Result<NetworkConfig, NetworkRuntimeError> {
87 let environment =
88 EnvironmentConfig::from_process().map_err(NetworkRuntimeError::Environment)?;
89
90 self.refresh_from_environment(&environment)
91 .map_err(NetworkRuntimeError::Config)
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq)]
97pub enum NetworkConfigError {
98 Http(http::HttpConfigError),
99 Qos(qos::QosPolicyError),
100}
101
102impl fmt::Display for NetworkConfigError {
103 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 Self::Http(error) => write!(formatter, "invalid HTTP configuration: {error}"),
106 Self::Qos(error) => write!(formatter, "invalid QoS policy: {error}"),
107 }
108 }
109}
110
111impl Error for NetworkConfigError {}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
115pub enum NetworkRuntimeError {
116 Environment(EnvError),
117 Config(NetworkConfigError),
118}
119
120impl fmt::Display for NetworkRuntimeError {
121 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self {
123 Self::Environment(error) => write!(formatter, "{error}"),
124 Self::Config(error) => write!(formatter, "{error}"),
125 }
126 }
127}
128
129impl Error for NetworkRuntimeError {}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::env::PlatformKind;
135
136 #[test]
137 fn resolves_default_network_configuration() {
138 let config = NetworkConfig::from_overrides(&NetworkEnvOverrides::default())
139 .expect("defaults should resolve");
140
141 assert_eq!(config.http.bind_address.to_string(), "127.0.0.1:8791");
142 assert!(!config.http.proxy.is_proxy_configured());
143 assert!(config.http.proxy.ssl_verify);
144 assert_eq!(config.qos.max_connections, 1024);
145 assert_eq!(config.qos.max_in_flight_requests, 256);
146 assert_eq!(config.qos.max_queue_depth, 512);
147 }
148
149 #[test]
150 fn refreshes_runtime_network_config_from_environment_snapshot() {
151 let runtime = NetworkRuntime::from_overrides(&NetworkEnvOverrides::default())
152 .expect("runtime should build");
153 let environment = EnvironmentConfig::from_pairs(
154 PlatformKind::Unix,
155 [
156 ("HTTP_PROXY", "http://relay-proxy:8080"),
157 ("NO_PROXY", "localhost"),
158 ("SSL_VERIFY", "false"),
159 ("RELAY_KNOWLEDGE_QOS_MAX_CONNECTIONS", "8"),
160 ],
161 )
162 .expect("environment should parse");
163
164 runtime
165 .refresh_from_environment(&environment)
166 .expect("network refresh should succeed");
167 let config = runtime.current();
168
169 assert_eq!(
170 config.http.proxy.proxy,
171 Some("http://relay-proxy:8080".to_owned())
172 );
173 assert_eq!(config.http.proxy.no_proxy_rules, ["localhost"]);
174 assert!(!config.http.proxy.ssl_verify);
175 assert_eq!(config.qos.max_connections, 8);
176 }
177}