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