pipedash_core/infrastructure/
http_client.rs1use std::sync::Arc;
2use std::time::Duration;
3
4use dashmap::DashMap;
5use reqwest::Client;
6
7use crate::domain::{
8 DomainError,
9 DomainResult,
10};
11
12pub struct HttpClientManager {
13 default_client: Arc<Client>,
14 custom_clients: DashMap<String, Arc<Client>>,
15}
16
17impl HttpClientManager {
18 pub fn new() -> DomainResult<Self> {
19 let default_client = Self::create_optimized_client()?;
20 Ok(Self {
21 default_client: Arc::new(default_client),
22 custom_clients: DashMap::new(),
23 })
24 }
25
26 pub fn default_client(&self) -> Arc<Client> {
27 Arc::clone(&self.default_client)
28 }
29
30 pub fn client_for_url(&self, base_url: &str) -> DomainResult<Arc<Client>> {
31 if let Some(client) = self.custom_clients.get(base_url) {
32 return Ok(Arc::clone(client.value()));
33 }
34
35 let client = Self::create_optimized_client()?;
36 let client = Arc::new(client);
37 self.custom_clients
38 .insert(base_url.to_string(), Arc::clone(&client));
39 Ok(client)
40 }
41
42 fn create_optimized_client() -> DomainResult<Client> {
43 let pool_size = std::env::var("PIPEDASH_HTTP_POOL_SIZE")
44 .ok()
45 .and_then(|s| s.parse().ok())
46 .unwrap_or(10);
47
48 Client::builder()
49 .use_rustls_tls()
50 .pool_max_idle_per_host(pool_size)
51 .pool_idle_timeout(Duration::from_secs(90))
52 .tcp_keepalive(Duration::from_secs(60))
53 .timeout(Duration::from_secs(30))
54 .connect_timeout(Duration::from_secs(10))
55 .build()
56 .map_err(|e| DomainError::InternalError(format!("Failed to create HTTP client: {}", e)))
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn test_http_client_manager_creation() {
66 let manager = HttpClientManager::new().unwrap();
67 let client = manager.default_client();
68 assert!(Arc::strong_count(&client) >= 1);
69 }
70
71 #[test]
72 fn test_client_caching() {
73 let manager = HttpClientManager::new().unwrap();
74
75 let client1 = manager.client_for_url("https://api.github.com").unwrap();
76 let client2 = manager.client_for_url("https://api.github.com").unwrap();
77
78 assert!(Arc::ptr_eq(&client1, &client2));
79 }
80
81 #[test]
82 fn test_different_urls_different_clients() {
83 let manager = HttpClientManager::new().unwrap();
84
85 let client1 = manager.client_for_url("https://api.github.com").unwrap();
86 let client2 = manager.client_for_url("https://gitlab.com").unwrap();
87
88 assert!(!Arc::ptr_eq(&client1, &client2));
89 }
90
91 #[test]
92 fn test_default_client_separate_from_custom() {
93 let manager = HttpClientManager::new().unwrap();
94
95 let default_client = manager.default_client();
96 let custom_client = manager.client_for_url("https://api.github.com").unwrap();
97
98 assert!(!Arc::ptr_eq(&default_client, &custom_client));
99 }
100}