1use serde::{Deserialize, Serialize};
7use std::fmt;
8use std::str::FromStr;
9use uuid::Uuid;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct CorrelationId(String);
14
15impl CorrelationId {
16 pub fn new() -> Self {
18 Self(Uuid::new_v4().to_string())
19 }
20
21 pub fn from_string(s: impl Into<String>) -> Self {
23 Self(s.into())
24 }
25
26 pub fn as_str(&self) -> &str {
28 &self.0
29 }
30
31 pub fn into_string(self) -> String {
33 self.0
34 }
35}
36
37impl Default for CorrelationId {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl fmt::Display for CorrelationId {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 write!(f, "{}", self.0)
46 }
47}
48
49impl From<String> for CorrelationId {
50 fn from(s: String) -> Self {
51 Self(s)
52 }
53}
54
55impl From<&str> for CorrelationId {
56 fn from(s: &str) -> Self {
57 Self(s.to_string())
58 }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
63pub struct RequestId(String);
64
65impl RequestId {
66 pub fn new() -> Self {
68 Self(Uuid::new_v4().to_string())
69 }
70
71 pub fn as_str(&self) -> &str {
73 &self.0
74 }
75}
76
77impl Default for RequestId {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl fmt::Display for RequestId {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 write!(f, "{}", self.0)
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
91pub struct RouteId(String);
92
93impl RouteId {
94 pub fn new(id: impl Into<String>) -> Self {
95 Self(id.into())
96 }
97
98 pub fn as_str(&self) -> &str {
99 &self.0
100 }
101}
102
103impl fmt::Display for RouteId {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 write!(f, "{}", self.0)
106 }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
111pub struct UpstreamId(String);
112
113impl UpstreamId {
114 pub fn new(id: impl Into<String>) -> Self {
115 Self(id.into())
116 }
117
118 pub fn as_str(&self) -> &str {
119 &self.0
120 }
121}
122
123impl fmt::Display for UpstreamId {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 write!(f, "{}", self.0)
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
131pub struct AgentId(String);
132
133impl AgentId {
134 pub fn new(id: impl Into<String>) -> Self {
135 Self(id.into())
136 }
137
138 pub fn as_str(&self) -> &str {
139 &self.0
140 }
141}
142
143impl fmt::Display for AgentId {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "{}", self.0)
146 }
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
151pub enum HttpMethod {
152 GET,
153 POST,
154 PUT,
155 DELETE,
156 HEAD,
157 OPTIONS,
158 PATCH,
159 CONNECT,
160 TRACE,
161 #[serde(untagged)]
162 Custom(String),
163}
164
165impl FromStr for HttpMethod {
166 type Err = std::convert::Infallible;
167
168 fn from_str(s: &str) -> Result<Self, Self::Err> {
169 Ok(match s.to_uppercase().as_str() {
170 "GET" => Self::GET,
171 "POST" => Self::POST,
172 "PUT" => Self::PUT,
173 "DELETE" => Self::DELETE,
174 "HEAD" => Self::HEAD,
175 "OPTIONS" => Self::OPTIONS,
176 "PATCH" => Self::PATCH,
177 "CONNECT" => Self::CONNECT,
178 "TRACE" => Self::TRACE,
179 other => Self::Custom(other.to_string()),
180 })
181 }
182}
183
184impl fmt::Display for HttpMethod {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 match self {
187 Self::GET => write!(f, "GET"),
188 Self::POST => write!(f, "POST"),
189 Self::PUT => write!(f, "PUT"),
190 Self::DELETE => write!(f, "DELETE"),
191 Self::HEAD => write!(f, "HEAD"),
192 Self::OPTIONS => write!(f, "OPTIONS"),
193 Self::PATCH => write!(f, "PATCH"),
194 Self::CONNECT => write!(f, "CONNECT"),
195 Self::TRACE => write!(f, "TRACE"),
196 Self::Custom(method) => write!(f, "{}", method),
197 }
198 }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
203pub enum TlsVersion {
204 #[serde(rename = "TLS1.2")]
205 Tls12,
206 #[serde(rename = "TLS1.3")]
207 Tls13,
208}
209
210impl fmt::Display for TlsVersion {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 match self {
213 Self::Tls12 => write!(f, "TLS1.2"),
214 Self::Tls13 => write!(f, "TLS1.3"),
215 }
216 }
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
221#[serde(rename_all = "snake_case")]
222pub enum LoadBalancingAlgorithm {
223 RoundRobin,
224 LeastConnections,
225 Random,
226 IpHash,
227 Weighted,
228 ConsistentHash,
229 PowerOfTwoChoices,
230 Adaptive,
231}
232
233#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
235#[serde(rename_all = "snake_case")]
236pub enum HealthCheckType {
237 Http {
238 path: String,
239 expected_status: u16,
240 #[serde(skip_serializing_if = "Option::is_none")]
241 host: Option<String>,
242 },
243 Tcp,
244 Grpc {
245 service: String,
246 },
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct RetryPolicy {
252 pub max_attempts: u32,
253 pub timeout_ms: u64,
254 pub backoff_base_ms: u64,
255 pub backoff_max_ms: u64,
256 pub retryable_status_codes: Vec<u16>,
257}
258
259impl Default for RetryPolicy {
260 fn default() -> Self {
261 Self {
262 max_attempts: 3,
263 timeout_ms: 30000,
264 backoff_base_ms: 100,
265 backoff_max_ms: 10000,
266 retryable_status_codes: vec![502, 503, 504],
267 }
268 }
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct CircuitBreakerConfig {
274 pub failure_threshold: u32,
275 pub success_threshold: u32,
276 pub timeout_seconds: u64,
277 pub half_open_max_requests: u32,
278}
279
280impl Default for CircuitBreakerConfig {
281 fn default() -> Self {
282 Self {
283 failure_threshold: 5,
284 success_threshold: 2,
285 timeout_seconds: 30,
286 half_open_max_requests: 1,
287 }
288 }
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
293#[serde(rename_all = "snake_case")]
294pub enum CircuitBreakerState {
295 Closed,
296 Open,
297 HalfOpen,
298}
299
300#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
302#[serde(rename_all = "snake_case")]
303pub enum Priority {
304 Low = 0,
305 Normal = 1,
306 High = 2,
307 Critical = 3,
308}
309
310impl Default for Priority {
311 fn default() -> Self {
312 Self::Normal
313 }
314}
315
316#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
318pub struct TimeWindow {
319 pub seconds: u64,
320}
321
322impl TimeWindow {
323 pub fn new(seconds: u64) -> Self {
324 Self { seconds }
325 }
326
327 pub fn as_duration(&self) -> std::time::Duration {
328 std::time::Duration::from_secs(self.seconds)
329 }
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
334pub struct ByteSize(pub usize);
335
336impl ByteSize {
337 pub const KB: usize = 1024;
338 pub const MB: usize = 1024 * 1024;
339 pub const GB: usize = 1024 * 1024 * 1024;
340
341 pub fn from_kb(kb: usize) -> Self {
342 Self(kb * Self::KB)
343 }
344
345 pub fn from_mb(mb: usize) -> Self {
346 Self(mb * Self::MB)
347 }
348
349 pub fn from_gb(gb: usize) -> Self {
350 Self(gb * Self::GB)
351 }
352
353 pub fn as_bytes(&self) -> usize {
354 self.0
355 }
356}
357
358impl fmt::Display for ByteSize {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 if self.0 >= Self::GB {
361 write!(f, "{:.2}GB", self.0 as f64 / Self::GB as f64)
362 } else if self.0 >= Self::MB {
363 write!(f, "{:.2}MB", self.0 as f64 / Self::MB as f64)
364 } else if self.0 >= Self::KB {
365 write!(f, "{:.2}KB", self.0 as f64 / Self::KB as f64)
366 } else {
367 write!(f, "{}B", self.0)
368 }
369 }
370}
371
372impl Serialize for ByteSize {
373 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
374 where
375 S: serde::Serializer,
376 {
377 serializer.serialize_str(&self.to_string())
378 }
379}
380
381impl<'de> Deserialize<'de> for ByteSize {
382 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
383 where
384 D: serde::Deserializer<'de>,
385 {
386 let s = String::deserialize(deserializer)?;
387 Self::from_str(&s).map_err(serde::de::Error::custom)
388 }
389}
390
391impl FromStr for ByteSize {
392 type Err = String;
393
394 fn from_str(s: &str) -> Result<Self, Self::Err> {
395 let s = s.trim();
396 if s.is_empty() {
397 return Err("Empty byte size string".to_string());
398 }
399
400 if let Ok(bytes) = s.parse::<usize>() {
402 return Ok(Self(bytes));
403 }
404
405 let (num_part, unit_part) = s
407 .chars()
408 .position(|c| c.is_alphabetic())
409 .map(|i| s.split_at(i))
410 .ok_or_else(|| format!("Invalid byte size format: {}", s))?;
411
412 let value: f64 = num_part
413 .trim()
414 .parse()
415 .map_err(|_| format!("Invalid number: {}", num_part))?;
416
417 let multiplier = match unit_part.to_uppercase().as_str() {
418 "B" => 1,
419 "KB" | "K" => Self::KB,
420 "MB" | "M" => Self::MB,
421 "GB" | "G" => Self::GB,
422 _ => return Err(format!("Invalid unit: {}", unit_part)),
423 };
424
425 Ok(Self((value * multiplier as f64) as usize))
426 }
427}
428
429#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
431pub struct ClientIp {
432 pub address: std::net::IpAddr,
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub forwarded_for: Option<Vec<std::net::IpAddr>>,
435}
436
437impl fmt::Display for ClientIp {
438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 write!(f, "{}", self.address)
440 }
441}
442
443#[cfg(test)]
444mod tests {
445 use super::*;
446
447 #[test]
448 fn test_correlation_id() {
449 let id1 = CorrelationId::new();
450 let id2 = CorrelationId::from_string("test-id");
451
452 assert_ne!(id1, id2);
453 assert_eq!(id2.as_str(), "test-id");
454 }
455
456 #[test]
457 fn test_http_method_parsing() {
458 assert_eq!(HttpMethod::from_str("GET").unwrap(), HttpMethod::GET);
459 assert_eq!(HttpMethod::from_str("post").unwrap(), HttpMethod::POST);
460 assert_eq!(
461 HttpMethod::from_str("PROPFIND").unwrap(),
462 HttpMethod::Custom("PROPFIND".to_string())
463 );
464 }
465
466 #[test]
467 fn test_byte_size_parsing() {
468 assert_eq!(ByteSize::from_str("1024").unwrap().0, 1024);
469 assert_eq!(ByteSize::from_str("10KB").unwrap().0, 10 * 1024);
470 assert_eq!(
471 ByteSize::from_str("5.5MB").unwrap().0,
472 (5.5 * 1024.0 * 1024.0) as usize
473 );
474 assert_eq!(ByteSize::from_str("2GB").unwrap().0, 2 * 1024 * 1024 * 1024);
475 assert_eq!(ByteSize::from_str("100 B").unwrap().0, 100);
476 }
477
478 #[test]
479 fn test_byte_size_display() {
480 assert_eq!(ByteSize(512).to_string(), "512B");
481 assert_eq!(ByteSize(2048).to_string(), "2.00KB");
482 assert_eq!(ByteSize(1024 * 1024).to_string(), "1.00MB");
483 assert_eq!(ByteSize(1024 * 1024 * 1024).to_string(), "1.00GB");
484 }
485}