Skip to main content

ferrum_server/
types.rs

1//! Type definitions for HTTP server
2//!
3//! This module defines the core types used throughout the server system.
4
5use crate::middleware::{AuthConfig, CompressionConfig, CorsConfig};
6use chrono::{DateTime, Utc};
7use ferrum_types::RequestId;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::time::{Duration, Instant};
11
12/// HTTP request representation
13#[derive(Debug, Clone)]
14pub struct HttpRequest {
15    /// HTTP method
16    pub method: HttpMethod,
17
18    /// Request path
19    pub path: String,
20
21    /// Query parameters
22    pub query: HashMap<String, String>,
23
24    /// Request headers
25    pub headers: Headers,
26
27    /// Request body
28    pub body: Vec<u8>,
29
30    /// Client IP address
31    pub client_ip: Option<std::net::IpAddr>,
32
33    /// Request timestamp
34    pub timestamp: DateTime<Utc>,
35
36    /// Request ID for tracking
37    pub request_id: RequestId,
38}
39
40/// HTTP response representation
41#[derive(Debug, Clone)]
42pub struct HttpResponse {
43    /// Status code
44    pub status: StatusCode,
45
46    /// Response headers
47    pub headers: Headers,
48
49    /// Response body
50    pub body: Vec<u8>,
51
52    /// Content type
53    pub content_type: String,
54}
55
56/// HTTP methods
57#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
58pub enum HttpMethod {
59    GET,
60    POST,
61    PUT,
62    DELETE,
63    PATCH,
64    HEAD,
65    OPTIONS,
66}
67
68/// HTTP status codes
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
70pub enum StatusCode {
71    OK = 200,
72    Created = 201,
73    NoContent = 204,
74    BadRequest = 400,
75    Unauthorized = 401,
76    Forbidden = 403,
77    NotFound = 404,
78    MethodNotAllowed = 405,
79    TooManyRequests = 429,
80    InternalServerError = 500,
81    BadGateway = 502,
82    ServiceUnavailable = 503,
83    GatewayTimeout = 504,
84}
85
86/// HTTP headers
87pub type Headers = HashMap<String, String>;
88
89/// Request context for passing data between middleware
90#[derive(Debug, Clone)]
91pub struct RequestContext {
92    /// Client information
93    pub client_info: Option<ClientInfo>,
94
95    /// Authentication result
96    pub auth_result: Option<AuthResult>,
97
98    /// Request start time
99    pub start_time: Instant,
100
101    /// Custom context data
102    pub data: HashMap<String, serde_json::Value>,
103
104    /// Request tracing ID
105    pub trace_id: String,
106}
107
108impl Default for RequestContext {
109    fn default() -> Self {
110        Self {
111            client_info: None,
112            auth_result: None,
113            start_time: Instant::now(),
114            data: HashMap::new(),
115            trace_id: uuid::Uuid::new_v4().to_string(),
116        }
117    }
118}
119
120/// Server configuration
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ServerConfig {
123    /// Server host
124    pub host: String,
125
126    /// Server port
127    pub port: u16,
128
129    /// Maximum concurrent connections
130    pub max_connections: usize,
131
132    /// Request timeout
133    pub request_timeout: Duration,
134
135    /// Keep-alive timeout
136    pub keep_alive_timeout: Duration,
137
138    /// Enable TLS
139    pub enable_tls: bool,
140
141    /// TLS certificate path
142    pub tls_cert_path: Option<String>,
143
144    /// TLS private key path
145    pub tls_key_path: Option<String>,
146
147    /// CORS configuration
148    pub cors: Option<CorsConfig>,
149
150    /// Compression configuration
151    pub compression: Option<CompressionConfig>,
152
153    /// Authentication configuration
154    pub auth: Option<AuthConfig>,
155
156    /// API versioning
157    pub api_version: ApiVersion,
158}
159
160/// API version
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
162pub enum ApiVersion {
163    V1,
164    V2,
165}
166
167/// Server metrics
168#[derive(Debug, Clone, Default, Serialize, Deserialize)]
169pub struct ServerMetrics {
170    /// Total requests handled
171    pub total_requests: u64,
172
173    /// Requests by endpoint
174    pub requests_by_endpoint: HashMap<String, u64>,
175
176    /// Requests by status code
177    pub requests_by_status: HashMap<u16, u64>,
178
179    /// Average response time in milliseconds
180    pub avg_response_time_ms: f64,
181
182    /// 95th percentile response time
183    pub p95_response_time_ms: f64,
184
185    /// 99th percentile response time
186    pub p99_response_time_ms: f64,
187
188    /// Current active connections
189    pub active_connections: usize,
190
191    /// Total bytes sent
192    pub bytes_sent: u64,
193
194    /// Total bytes received
195    pub bytes_received: u64,
196
197    /// Error rate (0.0 - 1.0)
198    pub error_rate: f32,
199
200    /// Uptime in seconds
201    pub uptime_seconds: u64,
202}
203
204/// Health status
205#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
206pub enum HealthStatus {
207    Healthy,
208    Degraded,
209    Unhealthy,
210    Unknown,
211}
212
213/// Component health
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct ComponentHealth {
216    pub name: String,
217    pub status: HealthStatus,
218    pub message: Option<String>,
219    pub last_check: DateTime<Utc>,
220    pub response_time_ms: Option<u64>,
221}
222
223/// Authentication result
224#[derive(Debug, Clone)]
225pub struct AuthResult {
226    pub success: bool,
227    pub client_info: Option<ClientInfo>,
228    pub token_claims: Option<TokenClaims>,
229    pub error: Option<String>,
230}
231
232/// Client information
233#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct ClientInfo {
235    pub client_id: String,
236    pub api_key: Option<String>,
237    pub organization_id: Option<String>,
238    pub rate_limit_tier: RateLimitTier,
239    pub permissions: Vec<String>,
240}
241
242/// JWT token claims
243#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct TokenClaims {
245    pub sub: String,
246    pub exp: u64,
247    pub iat: u64,
248    pub iss: String,
249    pub aud: String,
250    pub permissions: Vec<String>,
251}
252
253/// Authentication schemes
254#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
255pub enum AuthScheme {
256    ApiKey,
257    Bearer,
258    Basic,
259    Custom(String),
260}
261
262/// Rate limit tiers
263#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
264pub enum RateLimitTier {
265    Free,
266    Pro,
267    Enterprise,
268    Custom(String),
269}
270
271/// Rate limit result
272#[derive(Debug, Clone)]
273pub struct RateLimitResult {
274    pub allowed: bool,
275    pub limit: u32,
276    pub remaining: u32,
277    pub reset_time: DateTime<Utc>,
278    pub retry_after: Option<Duration>,
279}
280
281/// Rate limit status
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct RateLimitStatus {
284    pub requests_per_minute: u32,
285    pub requests_per_hour: u32,
286    pub tokens_per_minute: u32,
287    pub current_usage: RateLimitUsage,
288    pub reset_times: RateLimitResetTimes,
289}
290
291/// Rate limit usage
292#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct RateLimitUsage {
294    pub requests_this_minute: u32,
295    pub requests_this_hour: u32,
296    pub tokens_this_minute: u32,
297}
298
299/// Rate limit reset times
300#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct RateLimitResetTimes {
302    pub requests_reset_minute: DateTime<Utc>,
303    pub requests_reset_hour: DateTime<Utc>,
304    pub tokens_reset_minute: DateTime<Utc>,
305}
306
307/// Validation rules
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct ValidationRules {
310    /// Maximum prompt length
311    pub max_prompt_length: usize,
312
313    /// Maximum completion tokens
314    pub max_completion_tokens: usize,
315
316    /// Allowed models
317    pub allowed_models: Option<Vec<String>>,
318
319    /// Required parameters
320    pub required_params: Vec<String>,
321
322    /// Parameter constraints
323    pub param_constraints: HashMap<String, ParameterConstraint>,
324}
325
326/// Parameter constraint
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub enum ParameterConstraint {
329    Range { min: f64, max: f64 },
330    OneOf(Vec<serde_json::Value>),
331    Regex(String),
332    Custom(String),
333}
334
335/// Health check configuration
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct HealthCheckConfig {
338    /// Health check interval
339    pub interval: Duration,
340
341    /// Components to check
342    pub components: Vec<String>,
343
344    /// Timeout for health checks
345    pub timeout: Duration,
346
347    /// Number of retries
348    pub retries: u32,
349}
350
351/// Stream configuration
352#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct StreamConfig {
354    /// Chunk size for streaming
355    pub chunk_size: usize,
356
357    /// Buffer size
358    pub buffer_size: usize,
359
360    /// Flush interval
361    pub flush_interval: Duration,
362
363    /// Enable compression
364    pub enable_compression: bool,
365
366    /// Stream timeout
367    pub timeout: Duration,
368}
369
370/// Shutdown signal types
371#[derive(Debug, Clone, Copy, PartialEq, Eq)]
372pub enum ShutdownSignal {
373    SIGTERM,
374    SIGINT,
375    SIGQUIT,
376    Custom,
377}
378
379/// Server lifecycle state
380#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
381pub enum LifecycleState {
382    Starting,
383    Running,
384    Stopping,
385    Stopped,
386    Error,
387}
388
389impl Default for ServerConfig {
390    fn default() -> Self {
391        Self {
392            host: "0.0.0.0".to_string(),
393            port: 8000,
394            max_connections: 10000,
395            request_timeout: Duration::from_secs(30),
396            keep_alive_timeout: Duration::from_secs(60),
397            enable_tls: false,
398            tls_cert_path: None,
399            tls_key_path: None,
400            cors: None,
401            compression: None,
402            auth: None,
403            api_version: ApiVersion::V1,
404        }
405    }
406}
407
408impl Default for StreamConfig {
409    fn default() -> Self {
410        Self {
411            chunk_size: 1024,
412            buffer_size: 8192,
413            flush_interval: Duration::from_millis(50),
414            enable_compression: false,
415            timeout: Duration::from_secs(300),
416        }
417    }
418}
419
420impl Default for HealthCheckConfig {
421    fn default() -> Self {
422        Self {
423            interval: Duration::from_secs(30),
424            components: vec![
425                "inference_engine".to_string(),
426                "scheduler".to_string(),
427                "cache".to_string(),
428            ],
429            timeout: Duration::from_secs(5),
430            retries: 3,
431        }
432    }
433}
434
435// ============================================================================
436// 内联单元测试
437// ============================================================================
438
439#[cfg(test)]
440mod tests {
441    use super::*;
442
443    #[test]
444    fn test_http_method_eq() {
445        assert_eq!(HttpMethod::GET, HttpMethod::GET);
446        assert_ne!(HttpMethod::GET, HttpMethod::POST);
447    }
448
449    #[test]
450    fn test_http_method_clone() {
451        let method = HttpMethod::POST;
452        let cloned = method.clone();
453        assert_eq!(method, cloned);
454    }
455
456    #[test]
457    fn test_http_method_debug() {
458        let method = HttpMethod::GET;
459        let debug_str = format!("{:?}", method);
460        assert!(debug_str.contains("GET"));
461    }
462
463    #[test]
464    fn test_status_code_values() {
465        assert_eq!(StatusCode::OK as u16, 200);
466        assert_eq!(StatusCode::BadRequest as u16, 400);
467        assert_eq!(StatusCode::InternalServerError as u16, 500);
468    }
469
470    #[test]
471    fn test_status_code_eq() {
472        assert_eq!(StatusCode::OK, StatusCode::OK);
473        assert_ne!(StatusCode::OK, StatusCode::Created);
474    }
475
476    #[test]
477    fn test_http_request_creation() {
478        let request = HttpRequest {
479            method: HttpMethod::GET,
480            path: "/api/v1/test".to_string(),
481            query: HashMap::new(),
482            headers: HashMap::new(),
483            body: vec![],
484            client_ip: None,
485            timestamp: Utc::now(),
486            request_id: RequestId::new(),
487        };
488
489        assert_eq!(request.method, HttpMethod::GET);
490        assert_eq!(request.path, "/api/v1/test");
491    }
492
493    #[test]
494    fn test_http_request_clone() {
495        let request = HttpRequest {
496            method: HttpMethod::POST,
497            path: "/test".to_string(),
498            query: HashMap::new(),
499            headers: HashMap::new(),
500            body: b"test body".to_vec(),
501            client_ip: None,
502            timestamp: Utc::now(),
503            request_id: RequestId::new(),
504        };
505
506        let cloned = request.clone();
507        assert_eq!(request.method, cloned.method);
508        assert_eq!(request.body, cloned.body);
509    }
510
511    #[test]
512    fn test_http_response_creation() {
513        let response = HttpResponse {
514            status: StatusCode::OK,
515            headers: HashMap::new(),
516            body: b"success".to_vec(),
517            content_type: "application/json".to_string(),
518        };
519
520        assert_eq!(response.status, StatusCode::OK);
521        assert_eq!(response.content_type, "application/json");
522    }
523
524    #[test]
525    fn test_request_context_default() {
526        let context = RequestContext {
527            client_info: None,
528            auth_result: None,
529            start_time: Instant::now(),
530            data: HashMap::new(),
531            trace_id: "test-trace".to_string(),
532        };
533
534        assert!(context.client_info.is_none());
535        assert_eq!(context.trace_id, "test-trace");
536    }
537
538    #[test]
539    fn test_server_config_default() {
540        let config = ServerConfig::default();
541
542        assert_eq!(config.host, "0.0.0.0");
543        assert_eq!(config.port, 8000); // 默认端口是 8000
544    }
545
546    #[test]
547    fn test_server_metrics_default() {
548        let metrics = ServerMetrics::default();
549
550        assert_eq!(metrics.total_requests, 0);
551        // ServerMetrics 只有 total_requests 和其他字段
552    }
553
554    #[test]
555    fn test_health_status_creation() {
556        // HealthStatus 在 types.rs 中定义,简单测试创建
557        let _status = HealthStatus::Healthy;
558        let _status2 = HealthStatus::Degraded;
559        assert!(true);
560    }
561
562    #[test]
563    fn test_api_version_eq() {
564        assert_eq!(ApiVersion::V1, ApiVersion::V1);
565        assert_ne!(ApiVersion::V1, ApiVersion::V2);
566    }
567
568    #[test]
569    fn test_api_version_eq_only() {
570        // ApiVersion 不实现 Display,所以只测试相等性
571        assert_eq!(ApiVersion::V1, ApiVersion::V1);
572        assert_ne!(ApiVersion::V1, ApiVersion::V2);
573    }
574
575    #[test]
576    fn test_component_health_healthy() {
577        let health = ComponentHealth {
578            name: "test".to_string(),
579            status: HealthStatus::Healthy,
580            message: Some("OK".to_string()),
581            last_check: Utc::now(),
582            response_time_ms: Some(10),
583        };
584
585        assert_eq!(health.status, HealthStatus::Healthy);
586        assert!(health.message.is_some());
587    }
588
589    #[test]
590    fn test_component_health_unhealthy() {
591        let health = ComponentHealth {
592            name: "test".to_string(),
593            status: HealthStatus::Unhealthy,
594            message: Some("Connection failed".to_string()),
595            last_check: Utc::now(),
596            response_time_ms: None,
597        };
598
599        assert_eq!(health.status, HealthStatus::Unhealthy);
600        assert!(health.message.is_some());
601    }
602
603    #[test]
604    fn test_client_info_creation() {
605        let info = ClientInfo {
606            client_id: "client123".to_string(),
607            api_key: Some("key123".to_string()),
608            organization_id: None,
609            rate_limit_tier: RateLimitTier::Free,
610            permissions: vec!["read".to_string()],
611        };
612
613        assert_eq!(info.client_id, "client123");
614        assert!(info.api_key.is_some());
615    }
616
617    #[test]
618    fn test_auth_result_success() {
619        let result = AuthResult {
620            success: true,
621            client_info: None,
622            token_claims: None,
623            error: None,
624        };
625
626        assert!(result.success);
627        assert!(result.error.is_none());
628    }
629
630    #[test]
631    fn test_health_check_config_default() {
632        let config = HealthCheckConfig::default();
633
634        assert_eq!(config.interval, Duration::from_secs(30));
635        assert_eq!(config.timeout, Duration::from_secs(5));
636        assert_eq!(config.retries, 3);
637        assert!(config.components.len() >= 3);
638    }
639
640    #[test]
641    fn test_server_config_clone() {
642        let config = ServerConfig::default();
643        let cloned = config.clone();
644
645        assert_eq!(config.host, cloned.host);
646        assert_eq!(config.port, cloned.port);
647    }
648
649    #[test]
650    fn test_server_metrics_clone() {
651        let metrics = ServerMetrics::default();
652        let cloned = metrics.clone();
653
654        assert_eq!(metrics.total_requests, cloned.total_requests);
655    }
656
657    #[test]
658    fn test_http_request_with_headers() {
659        let mut headers = HashMap::new();
660        headers.insert("Content-Type".to_string(), "application/json".to_string());
661        headers.insert("Authorization".to_string(), "Bearer token".to_string());
662
663        let request = HttpRequest {
664            method: HttpMethod::POST,
665            path: "/api/v1/completions".to_string(),
666            query: HashMap::new(),
667            headers,
668            body: vec![],
669            client_ip: None,
670            timestamp: Utc::now(),
671            request_id: RequestId::new(),
672        };
673
674        assert_eq!(request.headers.len(), 2);
675        assert!(request.headers.contains_key("Content-Type"));
676    }
677
678    #[test]
679    fn test_http_response_with_body() {
680        let body = serde_json::json!({"message": "success"}).to_string();
681
682        let response = HttpResponse {
683            status: StatusCode::OK,
684            headers: HashMap::new(),
685            body: body.as_bytes().to_vec(),
686            content_type: "application/json".to_string(),
687        };
688
689        assert!(!response.body.is_empty());
690        assert_eq!(response.status, StatusCode::OK);
691    }
692}