1use serde::{Deserialize, Serialize};
9use std::fmt;
10use std::str::FromStr;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum HttpMethod {
15 GET,
16 POST,
17 PUT,
18 DELETE,
19 HEAD,
20 OPTIONS,
21 PATCH,
22 CONNECT,
23 TRACE,
24 #[serde(untagged)]
25 Custom(String),
26}
27
28impl FromStr for HttpMethod {
29 type Err = std::convert::Infallible;
30
31 fn from_str(s: &str) -> Result<Self, Self::Err> {
32 Ok(match s.to_uppercase().as_str() {
33 "GET" => Self::GET,
34 "POST" => Self::POST,
35 "PUT" => Self::PUT,
36 "DELETE" => Self::DELETE,
37 "HEAD" => Self::HEAD,
38 "OPTIONS" => Self::OPTIONS,
39 "PATCH" => Self::PATCH,
40 "CONNECT" => Self::CONNECT,
41 "TRACE" => Self::TRACE,
42 other => Self::Custom(other.to_string()),
43 })
44 }
45}
46
47impl fmt::Display for HttpMethod {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 Self::GET => write!(f, "GET"),
51 Self::POST => write!(f, "POST"),
52 Self::PUT => write!(f, "PUT"),
53 Self::DELETE => write!(f, "DELETE"),
54 Self::HEAD => write!(f, "HEAD"),
55 Self::OPTIONS => write!(f, "OPTIONS"),
56 Self::PATCH => write!(f, "PATCH"),
57 Self::CONNECT => write!(f, "CONNECT"),
58 Self::TRACE => write!(f, "TRACE"),
59 Self::Custom(method) => write!(f, "{}", method),
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
66pub enum TlsVersion {
67 #[serde(rename = "TLS1.2")]
68 Tls12,
69 #[serde(rename = "TLS1.3")]
70 Tls13,
71}
72
73impl fmt::Display for TlsVersion {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 Self::Tls12 => write!(f, "TLS1.2"),
77 Self::Tls13 => write!(f, "TLS1.3"),
78 }
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
104#[serde(rename_all = "lowercase")]
105pub enum TraceIdFormat {
106 #[default]
108 TinyFlake,
109
110 Uuid,
112}
113
114impl TraceIdFormat {
115 pub fn from_str_loose(s: &str) -> Self {
117 match s.to_lowercase().as_str() {
118 "uuid" | "uuid4" | "uuidv4" => TraceIdFormat::Uuid,
119 _ => TraceIdFormat::TinyFlake, }
121 }
122}
123
124impl fmt::Display for TraceIdFormat {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 TraceIdFormat::TinyFlake => write!(f, "tinyflake"),
128 TraceIdFormat::Uuid => write!(f, "uuid"),
129 }
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
135#[serde(rename_all = "snake_case")]
136pub enum LoadBalancingAlgorithm {
137 RoundRobin,
138 LeastConnections,
139 Random,
140 IpHash,
141 Weighted,
142 ConsistentHash,
143 PowerOfTwoChoices,
144 Adaptive,
145 LeastTokensQueued,
151 Maglev,
157 LocalityAware,
163 PeakEwma,
169 DeterministicSubset,
175 WeightedLeastConnections,
181 Sticky,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
192#[serde(rename_all = "snake_case")]
193pub enum HealthCheckType {
194 Http {
195 path: String,
196 expected_status: u16,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 host: Option<String>,
199 },
200 Tcp,
201 Grpc {
202 service: String,
203 },
204 Inference {
210 endpoint: String,
212 #[serde(default, skip_serializing_if = "Vec::is_empty")]
214 expected_models: Vec<String>,
215 #[serde(default, skip_serializing_if = "Option::is_none")]
217 readiness: Option<Box<crate::inference::InferenceReadinessConfig>>,
218 },
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct RetryPolicy {
224 pub max_attempts: u32,
225}
226
227impl Default for RetryPolicy {
228 fn default() -> Self {
229 Self { max_attempts: 3 }
230 }
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize, Copy)]
235pub struct CircuitBreakerConfig {
236 pub failure_threshold: u32,
237 pub success_threshold: u32,
238 pub timeout_seconds: u64,
239 pub half_open_max_requests: u32,
240}
241
242impl Default for CircuitBreakerConfig {
243 fn default() -> Self {
244 Self {
245 failure_threshold: 5,
246 success_threshold: 2,
247 timeout_seconds: 30,
248 half_open_max_requests: 1,
249 }
250 }
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
255#[serde(rename_all = "snake_case")]
256pub enum CircuitBreakerState {
257 Closed,
258 Open,
259 HalfOpen,
260}
261
262#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
285#[serde(transparent)]
286pub struct Priority(pub i32);
287
288impl Priority {
289 pub const LOW: Self = Self(10);
291 pub const NORMAL: Self = Self(50);
294 pub const HIGH: Self = Self(100);
296 pub const CRITICAL: Self = Self(1000);
299
300 #[inline]
302 pub const fn as_i32(self) -> i32 {
303 self.0
304 }
305}
306
307impl Default for Priority {
308 fn default() -> Self {
309 Self::NORMAL
310 }
311}
312
313impl std::fmt::Display for Priority {
314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315 write!(f, "{}", self.0)
316 }
317}
318
319impl From<i32> for Priority {
320 fn from(value: i32) -> Self {
321 Self(value)
322 }
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
327pub struct TimeWindow {
328 pub seconds: u64,
329}
330
331impl TimeWindow {
332 pub fn new(seconds: u64) -> Self {
333 Self { seconds }
334 }
335
336 pub fn as_duration(&self) -> std::time::Duration {
337 std::time::Duration::from_secs(self.seconds)
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
343pub struct ByteSize(pub usize);
344
345impl ByteSize {
346 pub const KB: usize = 1024;
347 pub const MB: usize = 1024 * 1024;
348 pub const GB: usize = 1024 * 1024 * 1024;
349
350 pub fn from_kb(kb: usize) -> Self {
351 Self(kb * Self::KB)
352 }
353
354 pub fn from_mb(mb: usize) -> Self {
355 Self(mb * Self::MB)
356 }
357
358 pub fn from_gb(gb: usize) -> Self {
359 Self(gb * Self::GB)
360 }
361
362 pub fn as_bytes(&self) -> usize {
363 self.0
364 }
365}
366
367impl fmt::Display for ByteSize {
368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369 if self.0 >= Self::GB {
370 write!(f, "{:.2}GB", self.0 as f64 / Self::GB as f64)
371 } else if self.0 >= Self::MB {
372 write!(f, "{:.2}MB", self.0 as f64 / Self::MB as f64)
373 } else if self.0 >= Self::KB {
374 write!(f, "{:.2}KB", self.0 as f64 / Self::KB as f64)
375 } else {
376 write!(f, "{}B", self.0)
377 }
378 }
379}
380
381impl Serialize for ByteSize {
382 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
383 where
384 S: serde::Serializer,
385 {
386 serializer.serialize_str(&self.to_string())
387 }
388}
389
390impl<'de> Deserialize<'de> for ByteSize {
391 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
392 where
393 D: serde::Deserializer<'de>,
394 {
395 let s = String::deserialize(deserializer)?;
396 Self::from_str(&s).map_err(serde::de::Error::custom)
397 }
398}
399
400impl FromStr for ByteSize {
401 type Err = String;
402
403 fn from_str(s: &str) -> Result<Self, Self::Err> {
404 let s = s.trim();
405 if s.is_empty() {
406 return Err("Empty byte size string".to_string());
407 }
408
409 if let Ok(bytes) = s.parse::<usize>() {
411 return Ok(Self(bytes));
412 }
413
414 let (num_part, unit_part) = s
416 .chars()
417 .position(|c| c.is_alphabetic())
418 .map(|i| s.split_at(i))
419 .ok_or_else(|| format!("Invalid byte size format: {}", s))?;
420
421 let value: f64 = num_part
422 .trim()
423 .parse()
424 .map_err(|_| format!("Invalid number: {}", num_part))?;
425
426 let multiplier = match unit_part.to_uppercase().as_str() {
427 "B" => 1,
428 "KB" | "K" => Self::KB,
429 "MB" | "M" => Self::MB,
430 "GB" | "G" => Self::GB,
431 _ => return Err(format!("Invalid unit: {}", unit_part)),
432 };
433
434 Ok(Self((value * multiplier as f64) as usize))
435 }
436}
437
438#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
440pub struct ClientIp {
441 pub address: std::net::IpAddr,
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub forwarded_for: Option<Vec<std::net::IpAddr>>,
444}
445
446impl fmt::Display for ClientIp {
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 write!(f, "{}", self.address)
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::*;
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
486 #[test]
487 fn test_trace_id_format() {
488 assert_eq!(TraceIdFormat::from_str_loose("uuid"), TraceIdFormat::Uuid);
489 assert_eq!(
490 TraceIdFormat::from_str_loose("tinyflake"),
491 TraceIdFormat::TinyFlake
492 );
493 assert_eq!(
494 TraceIdFormat::from_str_loose("unknown"),
495 TraceIdFormat::TinyFlake
496 );
497 }
498}