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<crate::inference::InferenceReadinessConfig>,
218 },
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct RetryPolicy {
224 pub max_attempts: u32,
225 pub timeout_ms: u64,
226 pub backoff_base_ms: u64,
227 pub backoff_max_ms: u64,
228 pub retryable_status_codes: Vec<u16>,
229}
230
231impl Default for RetryPolicy {
232 fn default() -> Self {
233 Self {
234 max_attempts: 3,
235 timeout_ms: 30000,
236 backoff_base_ms: 100,
237 backoff_max_ms: 10000,
238 retryable_status_codes: vec![502, 503, 504],
239 }
240 }
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct CircuitBreakerConfig {
246 pub failure_threshold: u32,
247 pub success_threshold: u32,
248 pub timeout_seconds: u64,
249 pub half_open_max_requests: u32,
250}
251
252impl Default for CircuitBreakerConfig {
253 fn default() -> Self {
254 Self {
255 failure_threshold: 5,
256 success_threshold: 2,
257 timeout_seconds: 30,
258 half_open_max_requests: 1,
259 }
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
265#[serde(rename_all = "snake_case")]
266pub enum CircuitBreakerState {
267 Closed,
268 Open,
269 HalfOpen,
270}
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
274#[serde(rename_all = "snake_case")]
275pub enum Priority {
276 Low = 0,
277 #[default]
278 Normal = 1,
279 High = 2,
280 Critical = 3,
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
285pub struct TimeWindow {
286 pub seconds: u64,
287}
288
289impl TimeWindow {
290 pub fn new(seconds: u64) -> Self {
291 Self { seconds }
292 }
293
294 pub fn as_duration(&self) -> std::time::Duration {
295 std::time::Duration::from_secs(self.seconds)
296 }
297}
298
299#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
301pub struct ByteSize(pub usize);
302
303impl ByteSize {
304 pub const KB: usize = 1024;
305 pub const MB: usize = 1024 * 1024;
306 pub const GB: usize = 1024 * 1024 * 1024;
307
308 pub fn from_kb(kb: usize) -> Self {
309 Self(kb * Self::KB)
310 }
311
312 pub fn from_mb(mb: usize) -> Self {
313 Self(mb * Self::MB)
314 }
315
316 pub fn from_gb(gb: usize) -> Self {
317 Self(gb * Self::GB)
318 }
319
320 pub fn as_bytes(&self) -> usize {
321 self.0
322 }
323}
324
325impl fmt::Display for ByteSize {
326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327 if self.0 >= Self::GB {
328 write!(f, "{:.2}GB", self.0 as f64 / Self::GB as f64)
329 } else if self.0 >= Self::MB {
330 write!(f, "{:.2}MB", self.0 as f64 / Self::MB as f64)
331 } else if self.0 >= Self::KB {
332 write!(f, "{:.2}KB", self.0 as f64 / Self::KB as f64)
333 } else {
334 write!(f, "{}B", self.0)
335 }
336 }
337}
338
339impl Serialize for ByteSize {
340 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
341 where
342 S: serde::Serializer,
343 {
344 serializer.serialize_str(&self.to_string())
345 }
346}
347
348impl<'de> Deserialize<'de> for ByteSize {
349 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
350 where
351 D: serde::Deserializer<'de>,
352 {
353 let s = String::deserialize(deserializer)?;
354 Self::from_str(&s).map_err(serde::de::Error::custom)
355 }
356}
357
358impl FromStr for ByteSize {
359 type Err = String;
360
361 fn from_str(s: &str) -> Result<Self, Self::Err> {
362 let s = s.trim();
363 if s.is_empty() {
364 return Err("Empty byte size string".to_string());
365 }
366
367 if let Ok(bytes) = s.parse::<usize>() {
369 return Ok(Self(bytes));
370 }
371
372 let (num_part, unit_part) = s
374 .chars()
375 .position(|c| c.is_alphabetic())
376 .map(|i| s.split_at(i))
377 .ok_or_else(|| format!("Invalid byte size format: {}", s))?;
378
379 let value: f64 = num_part
380 .trim()
381 .parse()
382 .map_err(|_| format!("Invalid number: {}", num_part))?;
383
384 let multiplier = match unit_part.to_uppercase().as_str() {
385 "B" => 1,
386 "KB" | "K" => Self::KB,
387 "MB" | "M" => Self::MB,
388 "GB" | "G" => Self::GB,
389 _ => return Err(format!("Invalid unit: {}", unit_part)),
390 };
391
392 Ok(Self((value * multiplier as f64) as usize))
393 }
394}
395
396#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
398pub struct ClientIp {
399 pub address: std::net::IpAddr,
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub forwarded_for: Option<Vec<std::net::IpAddr>>,
402}
403
404impl fmt::Display for ClientIp {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 write!(f, "{}", self.address)
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413
414 #[test]
415 fn test_http_method_parsing() {
416 assert_eq!(HttpMethod::from_str("GET").unwrap(), HttpMethod::GET);
417 assert_eq!(HttpMethod::from_str("post").unwrap(), HttpMethod::POST);
418 assert_eq!(
419 HttpMethod::from_str("PROPFIND").unwrap(),
420 HttpMethod::Custom("PROPFIND".to_string())
421 );
422 }
423
424 #[test]
425 fn test_byte_size_parsing() {
426 assert_eq!(ByteSize::from_str("1024").unwrap().0, 1024);
427 assert_eq!(ByteSize::from_str("10KB").unwrap().0, 10 * 1024);
428 assert_eq!(
429 ByteSize::from_str("5.5MB").unwrap().0,
430 (5.5 * 1024.0 * 1024.0) as usize
431 );
432 assert_eq!(ByteSize::from_str("2GB").unwrap().0, 2 * 1024 * 1024 * 1024);
433 assert_eq!(ByteSize::from_str("100 B").unwrap().0, 100);
434 }
435
436 #[test]
437 fn test_byte_size_display() {
438 assert_eq!(ByteSize(512).to_string(), "512B");
439 assert_eq!(ByteSize(2048).to_string(), "2.00KB");
440 assert_eq!(ByteSize(1024 * 1024).to_string(), "1.00MB");
441 assert_eq!(ByteSize(1024 * 1024 * 1024).to_string(), "1.00GB");
442 }
443
444 #[test]
445 fn test_trace_id_format() {
446 assert_eq!(TraceIdFormat::from_str_loose("uuid"), TraceIdFormat::Uuid);
447 assert_eq!(
448 TraceIdFormat::from_str_loose("tinyflake"),
449 TraceIdFormat::TinyFlake
450 );
451 assert_eq!(
452 TraceIdFormat::from_str_loose("unknown"),
453 TraceIdFormat::TinyFlake
454 );
455 }
456}