brainwires_proxy/
config.rs1use std::collections::HashMap;
2use std::net::SocketAddr;
3use std::path::PathBuf;
4use std::time::Duration;
5
6#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
8pub struct ProxyConfig {
9 pub listener: ListenerConfig,
11 pub upstream: UpstreamConfig,
13 #[serde(default = "default_max_body_size")]
15 pub max_body_size: usize,
16 #[serde(with = "humantime_serde", default = "default_timeout")]
18 pub timeout: Duration,
19 #[serde(default)]
21 pub inspector: InspectorConfig,
22 #[serde(default)]
24 pub metadata: HashMap<String, String>,
25}
26
27fn default_max_body_size() -> usize {
28 10 * 1024 * 1024 }
30
31fn default_timeout() -> Duration {
32 Duration::from_secs(30)
33}
34
35impl Default for ProxyConfig {
36 fn default() -> Self {
37 Self {
38 listener: ListenerConfig::default(),
39 upstream: UpstreamConfig::default(),
40 max_body_size: default_max_body_size(),
41 timeout: default_timeout(),
42 inspector: InspectorConfig::default(),
43 metadata: HashMap::new(),
44 }
45 }
46}
47
48#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
50#[serde(tag = "type", rename_all = "snake_case")]
51pub enum ListenerConfig {
52 Tcp { addr: SocketAddr },
54 Unix { path: PathBuf },
56}
57
58impl Default for ListenerConfig {
59 fn default() -> Self {
60 Self::Tcp {
61 addr: SocketAddr::from(([127, 0, 0, 1], 8080)),
62 }
63 }
64}
65
66#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
68#[serde(tag = "type", rename_all = "snake_case")]
69pub enum UpstreamConfig {
70 Url { url: String },
72 Tcp { host: String, port: u16 },
74 Unix { path: PathBuf },
76}
77
78impl Default for UpstreamConfig {
79 fn default() -> Self {
80 Self::Url {
81 url: "http://localhost:3000".to_string(),
82 }
83 }
84}
85
86#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
88pub struct InspectorConfig {
89 #[serde(default)]
91 pub enabled: bool,
92 #[serde(default = "default_event_capacity")]
94 pub event_capacity: usize,
95 #[serde(default = "default_broadcast_capacity")]
97 pub broadcast_capacity: usize,
98 pub api_addr: Option<SocketAddr>,
100}
101
102fn default_event_capacity() -> usize {
103 10_000
104}
105
106fn default_broadcast_capacity() -> usize {
107 256
108}
109
110impl Default for InspectorConfig {
111 fn default() -> Self {
112 Self {
113 enabled: false,
114 event_capacity: default_event_capacity(),
115 broadcast_capacity: default_broadcast_capacity(),
116 api_addr: None,
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn default_config() {
127 let config = ProxyConfig::default();
128 assert_eq!(config.max_body_size, 10 * 1024 * 1024);
129 assert_eq!(config.timeout, Duration::from_secs(30));
130 assert!(!config.inspector.enabled);
131 assert!(config.metadata.is_empty());
132 }
133
134 #[test]
135 fn config_serde_roundtrip() {
136 let config = ProxyConfig::default();
137 let json = serde_json::to_string(&config).unwrap();
138 let deserialized: ProxyConfig = serde_json::from_str(&json).unwrap();
139 assert_eq!(deserialized.max_body_size, config.max_body_size);
140 assert_eq!(deserialized.timeout, config.timeout);
141 }
142
143 #[test]
144 fn listener_config_tcp() {
145 let listener = ListenerConfig::Tcp {
146 addr: "0.0.0.0:9090".parse().unwrap(),
147 };
148 let json = serde_json::to_string(&listener).unwrap();
149 assert!(json.contains("tcp"));
150 assert!(json.contains("9090"));
151 }
152
153 #[test]
154 fn upstream_config_url() {
155 let upstream = UpstreamConfig::Url {
156 url: "https://api.example.com".to_string(),
157 };
158 let json = serde_json::to_string(&upstream).unwrap();
159 assert!(json.contains("api.example.com"));
160 }
161
162 #[test]
163 fn inspector_config_defaults() {
164 let config = InspectorConfig::default();
165 assert!(!config.enabled);
166 assert_eq!(config.event_capacity, 10_000);
167 assert_eq!(config.broadcast_capacity, 256);
168 assert!(config.api_addr.is_none());
169 }
170}
171
172mod humantime_serde {
174 use serde::{Deserialize, Deserializer, Serializer};
175 use std::time::Duration;
176
177 pub fn serialize<S: Serializer>(d: &Duration, s: S) -> Result<S::Ok, S::Error> {
178 s.serialize_u64(d.as_secs())
179 }
180
181 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Duration, D::Error> {
182 let secs = u64::deserialize(d)?;
183 Ok(Duration::from_secs(secs))
184 }
185}