use std::sync::{Mutex, OnceLock};
use slab::Slab;
use crate::endpoint::IrohEndpoint;
fn endpoint_slab() -> &'static Mutex<Slab<IrohEndpoint>> {
static S: OnceLock<Mutex<Slab<IrohEndpoint>>> = OnceLock::new();
S.get_or_init(|| Mutex::new(Slab::new()))
}
pub fn insert_endpoint(ep: IrohEndpoint) -> u64 {
endpoint_slab()
.lock()
.unwrap_or_else(|e| e.into_inner())
.insert(ep) as u64
}
pub fn get_endpoint(handle: u64) -> Option<IrohEndpoint> {
endpoint_slab()
.lock()
.unwrap_or_else(|e| e.into_inner())
.get(handle as usize)
.cloned()
}
pub fn remove_endpoint(handle: u64) -> Option<IrohEndpoint> {
let mut slab = endpoint_slab()
.lock()
.unwrap_or_else(|e| e.into_inner());
if slab.contains(handle as usize) {
Some(slab.remove(handle as usize))
} else {
None
}
}
pub fn close_all_endpoints() {
let endpoints: Vec<IrohEndpoint> = {
let mut slab = endpoint_slab()
.lock()
.unwrap_or_else(|e| e.into_inner());
let keys: Vec<usize> = slab.iter().map(|(k, _)| k).collect();
keys.into_iter()
.filter_map(|k| {
if slab.contains(k) {
Some(slab.remove(k))
} else {
None
}
})
.collect()
};
if endpoints.is_empty() {
return;
}
std::thread::spawn(move || {
if let Ok(rt) = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
{
rt.block_on(async move {
for ep in endpoints {
ep.close_force().await;
}
});
}
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn close_all_endpoints_is_idempotent_on_empty_registry() {
close_all_endpoints();
}
}