1use core::service::ServiceConf;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct MiddlewaresConf {
7 #[serde(default = "default_true")]
8 pub trace: bool,
9 #[serde(default = "default_true")]
10 pub log: bool,
11 #[serde(default = "default_true")]
12 pub prometheus: bool,
13 #[serde(default = "default_true")]
14 pub max_connections: bool,
15 #[serde(default = "default_true")]
16 pub breaker: bool,
17 #[serde(default = "default_true")]
18 pub shedding: bool,
19 #[serde(default = "default_true")]
20 pub timeout: bool,
21 #[serde(default = "default_true")]
22 pub recover: bool,
23 #[serde(default = "default_true")]
24 pub metrics: bool,
25 #[serde(default = "default_true")]
26 pub max_bytes: bool,
27 #[serde(default = "default_true")]
28 pub gzip: bool,
29}
30
31fn default_true() -> bool {
32 true
33}
34
35impl Default for MiddlewaresConf {
36 fn default() -> Self {
37 Self {
38 trace: true,
39 log: true,
40 prometheus: true,
41 max_connections: true,
42 breaker: true,
43 shedding: true,
44 timeout: true,
45 recover: true,
46 metrics: true,
47 max_bytes: true,
48 gzip: true,
49 }
50 }
51}
52
53#[derive(Debug, Clone, Default, Serialize, Deserialize)]
55pub struct PrivateKeyConf {
56 #[serde(default)]
57 pub fingerprint: String,
58 #[serde(default)]
59 pub key_file: String,
60}
61
62fn default_signature_strict() -> bool {
63 false
64}
65
66fn default_signature_expiry_secs() -> u64 {
68 3600
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct SignatureConf {
74 #[serde(default = "default_signature_strict")]
75 pub strict: bool,
76 #[serde(default = "default_signature_expiry_secs")]
78 pub expiry_secs: u64,
79 #[serde(default)]
80 pub private_keys: Vec<PrivateKeyConf>,
81}
82
83impl Default for SignatureConf {
84 fn default() -> Self {
85 Self {
86 strict: false,
87 expiry_secs: 3600,
88 private_keys: Vec::new(),
89 }
90 }
91}
92
93fn default_host() -> String {
94 "0.0.0.0".to_string()
95}
96fn default_port() -> u16 {
97 8888
98}
99fn default_max_connections() -> i64 {
100 10_000
101}
102fn default_max_bytes() -> i64 {
103 16 * 1_048_576 }
105fn default_timeout_ms() -> Option<u64> {
106 Some(3_000)
107}
108fn default_cpu_threshold() -> i64 {
109 900
110}
111fn default_reuse_port() -> bool {
112 false
113}
114fn default_workers() -> Option<usize> {
115 None
116}
117fn default_cpu_affinity() -> Option<Vec<usize>> {
118 None
119}
120fn default_http2() -> bool {
121 false
122}
123fn default_http2_h2c() -> bool {
124 false
125}
126fn default_http1_keep_alive() -> bool {
127 true
128}
129fn default_http1_max_buf_size() -> Option<usize> {
130 None
131}
132fn default_tcp_keepalive_secs() -> Option<u64> {
133 None
134}
135fn default_rate_limit() -> Option<RateLimitConf> {
136 None
137}
138fn default_concurrency_limit() -> Option<usize> {
139 None
140}
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct RateLimitConf {
143 pub permits_per_second: u64,
145 pub burst: u64,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct RestConf {
152 #[serde(flatten, default)]
154 pub service: ServiceConf,
155
156 #[serde(default = "default_host")]
157 pub host: String,
158 #[serde(default = "default_port")]
159 pub port: u16,
160
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub cert_file: Option<String>,
163 #[serde(default, skip_serializing_if = "Option::is_none")]
164 pub key_file: Option<String>,
165
166 #[serde(default = "default_max_connections")]
167 pub max_connections: i64,
168 #[serde(default = "default_max_bytes")]
169 pub max_bytes: i64,
170
171 #[serde(
173 default = "default_timeout_ms",
174 alias = "RequestTimeoutMs",
175 skip_serializing_if = "Option::is_none"
176 )]
177 pub timeout: Option<u64>,
178
179 #[serde(default = "default_cpu_threshold")]
181 pub cpu_threshold: i64,
182
183 #[serde(default, skip_serializing_if = "Option::is_none")]
184 pub signature: Option<SignatureConf>,
185
186 #[serde(default)]
188 pub middlewares: MiddlewaresConf,
189
190 #[serde(default)]
192 pub trace_ignore_paths: Vec<String>,
193
194 #[serde(default = "default_workers", skip_serializing_if = "Option::is_none")]
196 pub workers: Option<usize>,
197
198 #[serde(default = "default_reuse_port")]
200 pub reuse_port: bool,
201
202 #[serde(
204 default = "default_cpu_affinity",
205 skip_serializing_if = "Option::is_none"
206 )]
207 pub cpu_affinity: Option<Vec<usize>>,
208
209 #[serde(default = "default_http2")]
211 pub http2: bool,
212 #[serde(default = "default_http2_h2c")]
214 pub h2c: bool,
215 #[serde(default = "default_http1_keep_alive")]
217 pub http1_keep_alive: bool,
218 #[serde(
220 default = "default_http1_max_buf_size",
221 skip_serializing_if = "Option::is_none"
222 )]
223 pub http1_max_buf_size: Option<usize>,
224 #[serde(
226 default = "default_tcp_keepalive_secs",
227 skip_serializing_if = "Option::is_none"
228 )]
229 pub tcp_keepalive_secs: Option<u64>,
230
231 #[serde(
233 default = "default_rate_limit",
234 skip_serializing_if = "Option::is_none"
235 )]
236 pub rate_limit: Option<RateLimitConf>,
237
238 #[serde(
240 default = "default_concurrency_limit",
241 skip_serializing_if = "Option::is_none"
242 )]
243 pub concurrency_limit: Option<usize>,
244}
245
246impl Default for RestConf {
247 fn default() -> Self {
248 Self::new()
249 }
250}
251
252impl RestConf {
253 pub fn new() -> Self {
254 let conf = Self {
255 service: ServiceConf::default(),
256 host: default_host(),
257 port: default_port(),
258 cert_file: None,
259 key_file: None,
260 max_connections: default_max_connections(),
261 max_bytes: default_max_bytes(),
262 timeout: default_timeout_ms(),
263 cpu_threshold: default_cpu_threshold(),
264 signature: None,
265 middlewares: MiddlewaresConf::default(),
266 trace_ignore_paths: Vec::new(),
267 workers: default_workers(),
268 reuse_port: default_reuse_port(),
269 cpu_affinity: default_cpu_affinity(),
270 http2: default_http2(),
271 h2c: default_http2_h2c(),
272 http1_keep_alive: default_http1_keep_alive(),
273 http1_max_buf_size: default_http1_max_buf_size(),
274 tcp_keepalive_secs: default_tcp_keepalive_secs(),
275 rate_limit: default_rate_limit(),
276 concurrency_limit: default_concurrency_limit(),
277 };
278 conf.validate().expect("RestConf::new validation failed");
279 conf
280 }
281}
282
283impl RestConf {
284 pub fn addr_string(&self) -> String {
285 format!("{}:{}", self.host, self.port)
286 }
287
288 pub fn validate(&self) -> Result<(), String> {
289 if !(0..1000).contains(&self.cpu_threshold) {
290 return Err(format!(
291 "CpuThreshold out of range [0,1000): {}",
292 self.cpu_threshold
293 ));
294 }
295 if self.port == 0 {
296 return Err("Port must be > 0".to_string());
297 }
298 if let Some(w) = self.workers
299 && w == 0
300 {
301 return Err("Workers must be >= 1".to_string());
302 }
303 if let Some(aff) = &self.cpu_affinity
304 && aff.is_empty()
305 {
306 return Err("CpuAffinity cannot be empty when set".to_string());
307 }
308 if self.h2c && !self.http2 {
309 return Err("h2c requires http2=true".to_string());
310 }
311 if let Some(rl) = &self.rate_limit
312 && (rl.permits_per_second == 0 || rl.burst == 0)
313 {
314 return Err("RateLimit permits_per_second and burst must be > 0".to_string());
315 }
316 if let Some(c) = self.concurrency_limit
317 && c == 0
318 {
319 return Err("ConcurrencyLimit must be > 0".to_string());
320 }
321 Ok(())
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328 use core::service::Mode;
329
330 #[test]
331 fn defaults_should_work() {
332 let c = RestConf::default();
333 assert_eq!(c.host, "0.0.0.0");
334 assert!(c.port > 0);
335 assert_eq!(c.max_connections, 10_000);
336 assert_eq!(c.max_bytes, 16 * 1_048_576);
337 assert_eq!(c.timeout, Some(3_000));
338 assert_eq!(c.cpu_threshold, 900);
339 assert_eq!(c.service.mode, Mode::Pro);
340 assert!(c.middlewares.trace);
341 assert!(c.middlewares.gzip);
342 }
343}