Skip to main content

soli_proxy/
pool.rs

1use hyper::body::Incoming;
2use hyper_util::client::legacy::connect::HttpConnector;
3use hyper_util::client::legacy::Client;
4use hyper_util::rt::TokioExecutor;
5use std::time::Duration;
6
7/// The hyper client type used to proxy requests to backends.
8pub type ProxyClient = Client<HttpConnector, Incoming>;
9
10/// A shared connection pool for proxying HTTP requests to backends.
11///
12/// Wraps a hyper `Client` which maintains its own internal pool of
13/// keep-alive connections (configured via `pool_max_idle_per_host` and
14/// `pool_idle_timeout`). Cloning is cheap — all clones share the same
15/// underlying pool — so a single `ConnectionPool` can be handed out
16/// to every accept loop / task.
17#[derive(Clone)]
18pub struct ConnectionPool {
19    client: ProxyClient,
20}
21
22impl ConnectionPool {
23    /// Create a new connection pool with sensible defaults for reverse proxying.
24    pub fn new() -> Self {
25        let mut connector = HttpConnector::new();
26        connector.set_nodelay(true);
27        connector.set_keepalive(Some(Duration::from_secs(30)));
28        connector.set_connect_timeout(Some(Duration::from_secs(5)));
29
30        let client = Client::builder(TokioExecutor::new())
31            .pool_max_idle_per_host(256)
32            .pool_idle_timeout(Duration::from_secs(60))
33            .build(connector);
34
35        Self { client }
36    }
37
38    /// Get a clone of the underlying hyper client.
39    ///
40    /// The returned client shares the same connection pool as all other
41    /// clones, so idle connections are reused transparently.
42    pub fn client(&self) -> ProxyClient {
43        self.client.clone()
44    }
45}
46
47impl Default for ConnectionPool {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_pool_creation_and_clone() {
59        let pool = ConnectionPool::new();
60        // Cloning should be cheap (Arc under the hood)
61        let _pool2 = pool.clone();
62        // Getting a client should succeed
63        let _client = pool.client();
64    }
65}