use std::{cell::UnsafeCell, collections::HashMap, path::PathBuf};
use rar_common::{
Cred,
database::score::{CmdMin, Score},
};
use serde_json::Value;
use crate::{Cli, error::SrResult};
use super::{
BestExecSettings,
de::{DConfigFinder, DLinkedRole, DLinkedTask},
options::BorrowedOptStack,
};
#[cfg(feature = "hashchecker")]
mod hashchecker;
#[cfg(feature = "hierarchy")]
mod hierarchy;
#[cfg(feature = "landlock")]
pub mod landlock;
#[cfg(feature = "ssd")]
mod ssd;
thread_local! {
static API: UnsafeCell<Api> = UnsafeCell::new(Api::new());
}
pub type EventCallbackFunction = dyn Fn(&mut ApiEvent) -> SrResult<()>;
pub struct Api {
callbacks: HashMap<EventKey, Vec<Box<EventCallbackFunction>>>,
}
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum EventKey {
BestGlobalSettings,
BestRoleSettings,
BestTaskSettings,
NewComplexCommand,
ActorMatching,
PreExec,
}
#[allow(dead_code)]
pub enum ApiEvent<'a, 't, 'c, 'f, 'g, 'h, 'i, 'j, 'k> {
BestGlobalSettingsFound(
&'f Cli,
&'g DConfigFinder<'a>,
&'j mut BorrowedOptStack<'a>,
&'h mut BestExecSettings,
&'i mut bool,
),
BestRoleSettingsFound(
&'f Cli,
&'k Cred,
&'g DLinkedRole<'c, 'a>,
&'h mut BorrowedOptStack<'a>,
&'k &'k [&'k str],
&'i mut BestExecSettings,
&'j mut bool,
),
BestTaskSettingsFound(
&'f Cli,
&'g DLinkedTask<'t, 'c, 'a>,
&'j mut BorrowedOptStack<'a>,
&'h mut BestExecSettings,
&'i mut Score,
),
ProcessComplexCommand(
&'f Value,
&'g [&'g str],
&'h PathBuf,
&'i [String],
&'j mut CmdMin,
&'k mut Option<PathBuf>,
),
ActorMatching(
&'f DLinkedRole<'c, 'a>,
&'g mut BestExecSettings,
&'h mut bool,
),
PreExec(&'f Cli, &'h BestExecSettings),
}
impl ApiEvent<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
const fn get_key(&self) -> EventKey {
match self {
ApiEvent::BestGlobalSettingsFound(..) => EventKey::BestGlobalSettings,
ApiEvent::BestRoleSettingsFound(..) => EventKey::BestRoleSettings,
ApiEvent::BestTaskSettingsFound(..) => EventKey::BestTaskSettings,
ApiEvent::ProcessComplexCommand(..) => EventKey::NewComplexCommand,
ApiEvent::ActorMatching(..) => EventKey::ActorMatching,
ApiEvent::PreExec(..) => EventKey::PreExec,
}
}
}
impl Api {
fn new() -> Self {
Self {
callbacks: HashMap::new(),
}
}
#[cfg(feature = "plugins")]
pub fn notify(mut event: ApiEvent) -> SrResult<()> {
let key = event.get_key();
API.with(|api| -> SrResult<()> {
let api = unsafe { &mut *api.get() };
if let Some(callbacks) = api.callbacks.get(&key) {
for callback in callbacks {
callback(&mut event)?;
}
}
Ok(())
})?;
Ok(())
}
#[cfg(feature = "plugins")]
pub fn register<F>(event: EventKey, function: F)
where
F: Fn(&mut ApiEvent) -> SrResult<()> + Send + 'static,
{
API.with(|api| unsafe {
let api = &mut *api.get();
let callbacks = api.callbacks.entry(event).or_default();
callbacks.push(Box::new(function));
});
}
}
pub fn register_plugins() {
#[cfg(feature = "ssd")]
ssd::register();
#[cfg(feature = "hashchecker")]
hashchecker::register();
#[cfg(feature = "hierarchy")]
hierarchy::register();
#[cfg(feature = "landlock")]
landlock::register();
}