use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use bytes::Bytes;
use http2::client::SendRequest;
use tokio::sync::Mutex;
const IDLE_TIMEOUT: Duration = Duration::from_secs(300);
struct PoolEntry {
sender: SendRequest<Bytes>,
last_used: Instant,
}
#[derive(Clone)]
pub struct ConnectionPool {
inner: Arc<Mutex<HashMap<(String, u16), PoolEntry>>>,
}
impl ConnectionPool {
pub fn new() -> Self {
Self {
inner: Arc::new(Mutex::new(HashMap::new())),
}
}
pub async fn get(&self, host: &str, port: u16) -> Option<SendRequest<Bytes>> {
let mut pool = self.inner.lock().await;
let key = (host.to_string(), port);
if let Some(entry) = pool.get(&key) {
if entry.last_used.elapsed() < IDLE_TIMEOUT {
return Some(entry.sender.clone());
}
pool.remove(&key);
}
None
}
pub async fn put(&self, host: &str, port: u16, sender: SendRequest<Bytes>) {
let mut pool = self.inner.lock().await;
let key = (host.to_string(), port);
pool.insert(
key,
PoolEntry {
sender,
last_used: Instant::now(),
},
);
}
pub async fn touch(&self, host: &str, port: u16) {
let mut pool = self.inner.lock().await;
let key = (host.to_string(), port);
if let Some(entry) = pool.get_mut(&key) {
entry.last_used = Instant::now();
}
}
pub async fn cleanup(&self) {
let mut pool = self.inner.lock().await;
pool.retain(|_, entry| entry.last_used.elapsed() < IDLE_TIMEOUT);
}
pub async fn evict(&self, host: &str, port: u16) {
let mut pool = self.inner.lock().await;
pool.remove(&(host.to_string(), port));
}
}
impl Default for ConnectionPool {
fn default() -> Self {
Self::new()
}
}