use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use crate::client::ClientHandle;
pub(crate) struct ConnRegistry {
next_id: AtomicU64,
conns: parking_lot::Mutex<rustc_hash::FxHashMap<u64, ConnMeta>>,
}
struct ConnMeta {
identity: Option<mineral_protocol::ClientInfo>,
connected_at: std::time::Instant,
concurrent_at_connect: usize,
}
impl ConnRegistry {
pub(crate) fn new() -> Self {
Self {
next_id: AtomicU64::new(0),
conns: parking_lot::Mutex::new(rustc_hash::FxHashMap::default()),
}
}
pub(super) fn register(&self) -> u64 {
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
let mut conns = self.conns.lock();
let concurrent_at_connect = conns.len() + 1;
conns.insert(
id,
ConnMeta {
identity: None,
connected_at: std::time::Instant::now(),
concurrent_at_connect,
},
);
id
}
pub(super) fn set_identity(&self, id: u64, info: mineral_protocol::ClientInfo) {
if let Some(meta) = self.conns.lock().get_mut(&id) {
meta.identity = Some(info);
}
}
fn unregister(&self, id: u64) -> Option<ConnMeta> {
self.conns.lock().remove(&id)
}
pub(crate) fn online(&self) -> usize {
self.conns.lock().len()
}
}
pub(super) struct ConnGuard {
pub(super) registry: Arc<ConnRegistry>,
pub(super) id: u64,
pub(super) client: ClientHandle,
}
impl Drop for ConnGuard {
fn drop(&mut self) {
let Some(meta) = self.registry.unregister(self.id) else {
return;
};
let Some(identity) = meta.identity else {
return; };
let duration_ms =
i64::try_from(meta.connected_at.elapsed().as_millis()).unwrap_or(i64::MAX);
let concurrent = i64::try_from(meta.concurrent_at_connect).unwrap_or(i64::MAX);
self.client
.record_client_connection(identity.name, duration_ms, concurrent);
}
}