syncweb-core 0.1.1-alpha.4

delay-tolerant web surfing
Documentation
use std::sync::{Mutex, OnceLock};

use iroh_docs::NamespaceId;
use tokio::sync::mpsc;

use super::SyncCommand;

type CancelSender = mpsc::UnboundedSender<SyncCommand>;
type Registry = Vec<(NamespaceId, CancelSender)>;

static REGISTRY: OnceLock<Mutex<Registry>> = OnceLock::new();

fn registry() -> &'static Mutex<Registry> {
    REGISTRY.get_or_init(|| Mutex::new(Vec::new()))
}

pub struct ActiveSession {
    namespace: NamespaceId,
}

fn lock_registry() -> std::sync::MutexGuard<'static, Registry> {
    registry().lock().unwrap_or_else(std::sync::PoisonError::into_inner)
}

impl ActiveSession {
    #[must_use]
    pub fn register(namespace: NamespaceId, cancel: CancelSender) -> Self {
        let mut guard = lock_registry();
        guard.retain(|(id, _)| *id != namespace);
        guard.push((namespace, cancel));
        drop(guard);
        Self { namespace }
    }
}

impl Drop for ActiveSession {
    fn drop(&mut self) {
        if let Ok(mut guard) = registry().lock() {
            guard.retain(|(id, _)| *id != self.namespace);
        }
    }
}

#[must_use]
pub fn cancel_session(namespace: NamespaceId) -> bool {
    let mut guard = lock_registry();
    if let Some(pos) = guard.iter().position(|(id, _)| *id == namespace) {
        let (_, cancel) = guard.remove(pos);
        drop(guard);
        return cancel.send(SyncCommand::Cancel).is_ok();
    }
    false
}

#[must_use]
pub fn is_active(namespace: NamespaceId) -> bool {
    let guard = lock_registry();
    let active = guard.iter().any(|(id, _)| *id == namespace);
    drop(guard);
    active
}