Files
yaak-mountain-loop/crates/yaak-http/src/manager.rs
T

54 lines
1.9 KiB
Rust

use crate::client::{ConfiguredClient, HttpConnectionOptions};
use crate::dns::LocalhostResolver;
use crate::error::Result;
use std::collections::BTreeMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
/// A cached HTTP client along with its DNS resolver.
/// The resolver is needed to set the event sender per-request.
pub struct CachedClient {
pub client: ConfiguredClient,
pub resolver: Arc<LocalhostResolver>,
}
pub struct HttpConnectionManager {
connections: Arc<RwLock<BTreeMap<String, (CachedClient, Instant)>>>,
ttl: Duration,
}
impl HttpConnectionManager {
pub fn new() -> Self {
Self {
connections: Arc::new(RwLock::new(BTreeMap::new())),
ttl: Duration::from_secs(10 * 60),
}
}
pub async fn get_client(&self, opt: &HttpConnectionOptions) -> Result<CachedClient> {
let mut connections = self.connections.write().await;
// The key must include any per-request option that changes how the
// client is built, or a send after a settings change reuses a client
// built with the old value for up to the cache TTL.
let id = format!("{}::{}::{}", opt.id, opt.validate_certificates, opt.http_version);
// Clean old connections
connections.retain(|_, (_, last_used)| last_used.elapsed() <= self.ttl);
if let Some((cached, last_used)) = connections.get_mut(&id) {
*last_used = Instant::now();
return Ok(CachedClient {
client: cached.client.clone(),
resolver: cached.resolver.clone(),
});
}
let (client, resolver) = opt.build_client()?;
let cached = CachedClient { client: client.clone(), resolver: resolver.clone() };
connections.insert(id.into(), (cached, Instant::now()));
Ok(CachedClient { client, resolver })
}
}