turbo_cdn/
http_client_manager.rs1use crate::config::TurboCdnConfig;
10use crate::error::Result;
11use crate::http_client::HttpClient;
12use std::sync::Arc;
13use std::time::Duration;
14use tracing::info;
15
16#[derive(Debug, Clone)]
18pub struct ClientMetrics {
19 pub avg_response_time: Duration,
20 pub success_rate: f64,
21 pub throughput_mbps: f64,
22 pub last_updated: std::time::Instant,
23}
24
25#[derive(Debug, Clone)]
27pub struct RequestConfig {
28 pub url: String,
29 pub method: String,
30 pub headers: Vec<(String, String)>,
31 pub timeout: Duration,
32 pub follow_redirects: bool,
33 pub max_redirects: u32,
34 pub enable_compression: bool,
35 pub enable_http2: bool,
36}
37
38impl Default for RequestConfig {
39 fn default() -> Self {
40 Self {
41 url: String::new(),
42 method: "GET".to_string(),
43 headers: Vec::new(),
44 timeout: Duration::from_secs(30),
45 follow_redirects: true,
46 max_redirects: 10,
47 enable_compression: true,
48 enable_http2: true,
49 }
50 }
51}
52
53#[derive(Debug)]
55pub struct HttpResponse {
56 pub status: u16,
57 pub headers: Vec<(String, String)>,
58 pub body: Vec<u8>,
59 pub response_time: Duration,
60 pub content_length: Option<u64>,
61 pub supports_ranges: bool,
62}
63
64#[derive(Debug)]
66pub struct HttpClientManager {
67 #[allow(dead_code)]
68 config: Arc<TurboCdnConfig>,
69 client: HttpClient,
70 metrics: Arc<std::sync::Mutex<ClientMetrics>>,
71}
72
73impl HttpClientManager {
74 pub fn new(config: Arc<TurboCdnConfig>) -> Result<Self> {
76 let timeout = Duration::from_secs(config.performance.timeout);
77 let client = HttpClient::new(timeout)?;
78
79 let metrics = ClientMetrics {
80 avg_response_time: Duration::from_millis(0),
81 success_rate: 1.0,
82 throughput_mbps: 0.0,
83 last_updated: std::time::Instant::now(),
84 };
85
86 info!("HTTP client manager initialized with reqwest client");
87
88 Ok(Self {
89 config,
90 client,
91 metrics: Arc::new(std::sync::Mutex::new(metrics)),
92 })
93 }
94
95 pub async fn get(&self, url: &str) -> Result<HttpResponse> {
97 let start_time = std::time::Instant::now();
98
99 let response = self.client.get(url).await?;
100 let response_time = start_time.elapsed();
101
102 self.update_metrics(response_time, true);
104
105 Ok(HttpResponse {
106 status: response.status,
107 headers: response.headers.into_iter().collect(),
108 body: response.body,
109 response_time,
110 content_length: None, supports_ranges: false, })
113 }
114
115 pub async fn get_with_headers(
117 &self,
118 url: &str,
119 headers: &std::collections::HashMap<String, String>,
120 ) -> Result<HttpResponse> {
121 let start_time = std::time::Instant::now();
122
123 let response = self.client.get_with_headers(url, headers).await?;
124 let response_time = start_time.elapsed();
125
126 self.update_metrics(response_time, true);
128
129 Ok(HttpResponse {
130 status: response.status,
131 headers: response.headers.into_iter().collect(),
132 body: response.body,
133 response_time,
134 content_length: None, supports_ranges: false, })
137 }
138
139 pub async fn head(&self, url: &str) -> Result<HttpResponse> {
141 let start_time = std::time::Instant::now();
142
143 let response = self.client.head(url).await?;
144 let response_time = start_time.elapsed();
145
146 self.update_metrics(response_time, true);
148
149 Ok(HttpResponse {
150 status: response.status,
151 headers: response.headers.into_iter().collect(),
152 body: response.body,
153 response_time,
154 content_length: None, supports_ranges: false, })
157 }
158
159 fn update_metrics(&self, response_time: Duration, success: bool) {
161 if let Ok(mut metrics) = self.metrics.lock() {
162 let alpha = 0.1;
164 let new_avg = metrics.avg_response_time.as_millis() as f64 * (1.0 - alpha)
165 + response_time.as_millis() as f64 * alpha;
166 metrics.avg_response_time = Duration::from_millis(new_avg as u64);
167
168 if success {
170 metrics.success_rate = metrics.success_rate * 0.99 + 0.01;
171 } else {
172 metrics.success_rate *= 0.99;
173 }
174
175 metrics.last_updated = std::time::Instant::now();
176 }
177 }
178
179 pub fn get_metrics(&self) -> Option<ClientMetrics> {
181 self.metrics.lock().ok().map(|m| m.clone())
182 }
183}