use std::collections::BTreeMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, LazyLock, Mutex, PoisonError};
pub type SessionReclaimHook = Arc<dyn Fn(&str) + Send + Sync>;
static NEXT_HOOK_ID: AtomicU64 = AtomicU64::new(1);
static HOOKS: LazyLock<Mutex<BTreeMap<u64, SessionReclaimHook>>> =
LazyLock::new(|| Mutex::new(BTreeMap::new()));
#[must_use = "dropping the registration unregisters the session reclaim hook"]
pub struct SessionReclaimHookRegistration {
id: u64,
}
impl Drop for SessionReclaimHookRegistration {
fn drop(&mut self) {
HOOKS
.lock()
.unwrap_or_else(PoisonError::into_inner)
.remove(&self.id);
}
}
pub fn register_session_reclaim_hook(hook: SessionReclaimHook) -> SessionReclaimHookRegistration {
let id = NEXT_HOOK_ID.fetch_add(1, Ordering::Relaxed);
HOOKS
.lock()
.unwrap_or_else(PoisonError::into_inner)
.insert(id, hook);
SessionReclaimHookRegistration { id }
}
pub(super) fn release_closed_session(session_id: &str) {
super::clear_session_changed_paths(session_id);
fire(session_id);
}
pub(crate) fn fire(session_id: &str) {
let hooks = HOOKS
.lock()
.unwrap_or_else(PoisonError::into_inner)
.values()
.cloned()
.collect::<Vec<_>>();
for hook in hooks {
hook(session_id);
}
}