assistant_daemon 0.1.0

Daemon program for providing many features.
use std::{
    cell::{LazyCell, RefCell},
    collections::HashMap,
    error::Error,
    sync::Arc,
};

use tokio::runtime::Handle;
use tracing::info;

use crate::feature::FeatureManager;

extern "C" {
    pub fn register_callback_for_clamshell_change(callback: extern "C" fn(bool));
    fn unregister_callback_for_clamshell_change();
}

struct Registry {
    callbacks: HashMap<u32, Box<dyn Fn(bool)>>,
    next_id: u32,
    activated: bool,
}

static mut REGISTRY: LazyCell<RefCell<Registry>> = LazyCell::new(|| RefCell::new(Registry::new()));

#[no_mangle]
extern "C" fn on_receive_laptoplid_change(open: bool) {
    let r = unsafe { REGISTRY.borrow() };
    if !r.activated {
        return;
    }
    r.callbacks.values().for_each(|f| f(open))
}

impl Registry {
    fn new() -> Self {
        return Self {
            callbacks: HashMap::new(),
            next_id: 0,
            activated: false,
        };
    }

    pub fn register(&mut self, callback: Box<dyn Fn(bool)>) -> u32 {
        let id = self.next_id;
        self.callbacks.insert(id, callback);
        self.next_id += 1;
        return id;
    }

    pub fn unregister(&mut self, id: u32) -> Result<(), Box<dyn Error>> {
        self.callbacks.remove(&id);
        Ok(())
    }
}

pub fn turn_on_laptoplid_change(
    fm: Arc<dyn FeatureManager>,
    runtime: Handle,
) -> Result<(), String> {
    info!("turn on laptoplid change detection");
    unsafe {
        if REGISTRY.borrow().activated {
            return Ok(());
        }
        REGISTRY.borrow_mut().activated = true;

        if REGISTRY.borrow().callbacks.len() == 0 {
            REGISTRY.borrow_mut().register(Box::new(move |open| {
                let runtime = runtime.clone();
                let fm = fm.clone();
                runtime.spawn(async move {
                    fm.lid_change(open).await;
                });
            }));
        }

        register_callback_for_clamshell_change(on_receive_laptoplid_change);
    }
    return Ok(());
}

pub fn turn_off_laptoplid_change() -> Result<(), String> {
    info!("turn off laptoplid change detection");

    unsafe {
        REGISTRY.borrow_mut().activated = false;
        unregister_callback_for_clamshell_change();
    }
    return Ok(());
}