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