use crate::plugin::SwitchKey;
use nagisa_types::id::Peer;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Mutex, RwLock};
#[derive(Default)]
struct Inner {
global: HashMap<String, bool>,
per_peer: HashMap<(String, Peer), bool>,
}
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct EnabledOverrides {
pub global: HashMap<String, bool>,
pub per_peer: Vec<(String, Peer, bool)>,
}
type ChangeFn = dyn Fn(&str, Option<Peer>, bool) + Send + Sync;
pub struct EnabledSet {
inner: RwLock<Inner>,
on_change: Mutex<Option<Box<ChangeFn>>>,
}
impl EnabledSet {
pub fn new() -> Self {
Self { inner: RwLock::new(Inner::default()), on_change: Mutex::new(None) }
}
pub fn set(&self, key: impl Into<SwitchKey>, peer: Option<Peer>, enabled: bool) {
let name = key.into().resolve();
{
let mut g = self.inner.write().unwrap_or_else(|e| e.into_inner());
match peer {
None => {
g.global.insert(name.to_string(), enabled);
}
Some(p) => {
g.per_peer.insert((name.to_string(), p), enabled);
}
}
}
self.fire(name, peer, enabled);
}
pub fn reset(&self, key: impl Into<SwitchKey>, peer: Option<Peer>) {
let name = key.into().resolve();
let mut g = self.inner.write().unwrap_or_else(|e| e.into_inner());
match peer {
None => {
g.global.remove(name);
}
Some(p) => {
g.per_peer.remove(&(name.to_string(), p));
}
}
}
fn key_on(&self, key: &str, default: bool, peer: Option<Peer>) -> bool {
let g = self.inner.read().unwrap_or_else(|e| e.into_inner());
if let Some(p) = peer {
if let Some(v) = g.per_peer.get(&(key.to_string(), p)) {
return *v;
}
}
if let Some(v) = g.global.get(key) {
return *v;
}
default
}
#[allow(clippy::too_many_arguments)]
pub fn is_enabled_keyed(
&self,
plugin_key: &str,
trigger_key: &str,
plugin_default: bool,
plugin_can_disable: bool,
trigger_default: bool,
trigger_can_disable: bool,
peer: Option<Peer>,
) -> bool {
if !trigger_can_disable {
return true;
}
if plugin_can_disable && !self.key_on(plugin_key, plugin_default, peer) {
return false;
}
self.key_on(trigger_key, trigger_default, peer)
}
pub fn is_enabled(&self, name: &str, default_enable: bool, peer: Option<Peer>) -> bool {
self.key_on(name, default_enable, peer)
}
pub fn on_change<F>(&self, f: F)
where
F: Fn(&str, Option<Peer>, bool) + Send + Sync + 'static,
{
*self.on_change.lock().unwrap_or_else(|e| e.into_inner()) = Some(Box::new(f));
}
fn fire(&self, key: &str, peer: Option<Peer>, enabled: bool) {
if let Some(cb) = self.on_change.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
cb(key, peer, enabled);
}
}
pub fn snapshot(&self) -> EnabledOverrides {
let g = self.inner.read().unwrap_or_else(|e| e.into_inner());
EnabledOverrides {
global: g.global.clone(),
per_peer: g.per_peer.iter().map(|((k, p), v)| (k.clone(), *p, *v)).collect(),
}
}
pub fn restore(&self, ov: EnabledOverrides) {
let mut g = self.inner.write().unwrap_or_else(|e| e.into_inner());
g.global = ov.global;
g.per_peer = ov.per_peer.into_iter().map(|(k, p, v)| ((k, p), v)).collect();
}
}
impl Default for EnabledSet {
fn default() -> Self {
Self::new()
}
}