punch_runtime/
http_pool.rs1use std::time::Duration;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct HttpPoolConfig {
14 pub pool_max_idle_per_host: usize,
16 pub pool_idle_timeout_secs: u64,
18 pub connect_timeout_secs: u64,
20 pub request_timeout_secs: u64,
22 pub user_agent: String,
24}
25
26impl Default for HttpPoolConfig {
27 fn default() -> Self {
28 Self {
29 pool_max_idle_per_host: 10,
30 pool_idle_timeout_secs: 90,
31 connect_timeout_secs: 10,
32 request_timeout_secs: 120,
33 user_agent: "Punch/0.1".to_string(),
34 }
35 }
36}
37
38#[derive(Debug, Clone)]
43pub struct HttpPool {
44 client: reqwest::Client,
45 config: HttpPoolConfig,
46}
47
48impl HttpPool {
49 pub fn new(config: HttpPoolConfig) -> Self {
51 let client = reqwest::Client::builder()
52 .pool_max_idle_per_host(config.pool_max_idle_per_host)
53 .pool_idle_timeout(Duration::from_secs(config.pool_idle_timeout_secs))
54 .connect_timeout(Duration::from_secs(config.connect_timeout_secs))
55 .timeout(Duration::from_secs(config.request_timeout_secs))
56 .user_agent(&config.user_agent)
57 .build()
58 .unwrap_or_default();
59
60 tracing::info!(
61 pool_max_idle = config.pool_max_idle_per_host,
62 idle_timeout_secs = config.pool_idle_timeout_secs,
63 connect_timeout_secs = config.connect_timeout_secs,
64 request_timeout_secs = config.request_timeout_secs,
65 user_agent = %config.user_agent,
66 "HTTP connection pool initialized"
67 );
68
69 Self { client, config }
70 }
71
72 pub fn client(&self) -> &reqwest::Client {
74 &self.client
75 }
76
77 pub fn config(&self) -> &HttpPoolConfig {
79 &self.config
80 }
81}
82
83impl Default for HttpPool {
84 fn default() -> Self {
85 Self::new(HttpPoolConfig::default())
86 }
87}
88
89#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn pool_creates_client_with_defaults() {
99 let pool = HttpPool::default();
100 let _client = pool.client();
101 }
102
103 #[test]
104 fn pool_creates_client_with_custom_config() {
105 let config = HttpPoolConfig {
106 pool_max_idle_per_host: 20,
107 pool_idle_timeout_secs: 30,
108 connect_timeout_secs: 5,
109 request_timeout_secs: 60,
110 user_agent: "TestAgent/1.0".to_string(),
111 };
112 let pool = HttpPool::new(config);
113 let _client = pool.client();
114 }
115
116 #[test]
117 fn default_config_values_are_sensible() {
118 let config = HttpPoolConfig::default();
119 assert_eq!(config.pool_max_idle_per_host, 10);
120 assert_eq!(config.pool_idle_timeout_secs, 90);
121 assert_eq!(config.connect_timeout_secs, 10);
122 assert_eq!(config.request_timeout_secs, 120);
123 assert_eq!(config.user_agent, "Punch/0.1");
124 }
125
126 #[test]
127 fn pool_is_clone() {
128 let pool = HttpPool::default();
129 let pool2 = pool.clone();
130 let _c1 = pool.client();
133 let _c2 = pool2.client();
134 }
135
136 #[test]
137 fn custom_config_overrides_work() {
138 let config = HttpPoolConfig {
139 pool_max_idle_per_host: 1,
140 pool_idle_timeout_secs: 1,
141 connect_timeout_secs: 1,
142 request_timeout_secs: 1,
143 user_agent: "Custom/2.0".to_string(),
144 };
145 let pool = HttpPool::new(config.clone());
146 assert_eq!(pool.config().pool_max_idle_per_host, 1);
147 assert_eq!(pool.config().request_timeout_secs, 1);
148 assert_eq!(pool.config().user_agent, "Custom/2.0");
149 }
150
151 #[test]
152 fn config_accessor_returns_stored_values() {
153 let pool = HttpPool::default();
154 assert_eq!(pool.config().pool_max_idle_per_host, 10);
155 }
156}