use std::sync::Arc;
use std::time::Duration;
use tokio::sync::{RwLock, Semaphore};
use axum::http::{Method, Uri};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Http2Client {
metrics: Arc<RwLock<Http2Metrics>>,
config: Arc<Http2Config>,
}
#[derive(Debug, Clone)]
pub struct Http2Config {
pub max_concurrent_streams: u32,
pub connection_timeout: Duration,
pub request_timeout: Duration,
pub enable_adaptive_flow_control: bool,
pub initial_window_size: u32,
pub enable_compression: bool,
pub max_frame_size: u32,
pub max_connections_per_host: usize,
}
impl Default for Http2Config {
fn default() -> Self {
Self {
max_concurrent_streams: 100,
connection_timeout: Duration::from_secs(30),
request_timeout: Duration::from_secs(10),
enable_adaptive_flow_control: true,
initial_window_size: 65535,
enable_compression: true,
max_frame_size: 16384,
max_connections_per_host: 10,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct Http2Metrics {
pub total_requests: u64,
pub successful_requests: u64,
pub failed_requests: u64,
pub avg_response_time_ms: f64,
pub active_connections: usize,
pub active_streams: u32,
pub throughput_rps: f64,
pub connection_reuse_rate: f64,
}
#[derive(Debug, Clone)]
pub struct Http2Response {
pub status_code: u16,
pub headers: HashMap<String, String>,
pub body: Vec<u8>,
pub stream_id: u32,
pub response_time_ms: u64,
}
impl Http2Client {
pub fn new(config: Http2Config) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
Ok(Self {
config: Arc::new(config.clone()),
metrics: Arc::new(RwLock::new(Http2Metrics::default())),
})
}
pub async fn execute_request(
&self,
_method: Method,
_uri: Uri,
_body: Option<Vec<u8>>,
_headers: Option<HashMap<String, String>>,
) -> crate::core::Result<Http2Response> {
Ok(Http2Response {
status_code: 200,
headers: HashMap::new(),
body: vec![],
stream_id: 0,
response_time_ms: 0,
})
}
pub async fn execute_batch(
&self,
requests: Vec<(Method, Uri, Option<Vec<u8>>, Option<HashMap<String, String>>)>,
) -> Vec<crate::core::Result<Http2Response>> {
let semaphore = Arc::new(Semaphore::new(self.config.max_concurrent_streams as usize));
let mut handles = Vec::new();
for (method, uri, body, headers) in requests {
let client = self.clone();
let permit = semaphore.clone().acquire_owned().await;
let handle = tokio::spawn(async move {
let _permit = permit;
client.execute_request(method, uri, body, headers).await
});
handles.push(handle);
}
let mut results = Vec::new();
for handle in handles {
match handle.await {
Ok(result) => results.push(result),
Err(_) => results.push(Err(crate::core::SolanaRecoverError::InternalError("Request failed".to_string()))),
}
}
results
}
pub async fn get_metrics(&self) -> Http2Metrics {
self.metrics.read().await.clone()
}
pub async fn reset_metrics(&self) {
let mut metrics = self.metrics.write().await;
*metrics = Http2Metrics::default();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_http2_client_creation() {
let config = Http2Config::default();
let client = Http2Client::new(config);
assert!(client.is_ok());
}
#[tokio::test]
async fn test_metrics_tracking() {
let client = Http2Client::new(Http2Config::default()).unwrap();
let initial_metrics = client.get_metrics().await;
assert_eq!(initial_metrics.total_requests, 0);
}
}