use std::{
collections::HashSet,
hash::{DefaultHasher, Hash, Hasher},
};
use log::debug;
use serde_json::Value;
use crate::{
error::{SrError, SrResult},
finder::de::DLinkedRole,
};
use super::{Api, ApiEvent};
fn calculate_hash<T: Hash>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
fn check_ssd_recursive(role: &DLinkedRole, visited: &mut HashSet<u64>) -> SrResult<bool> {
if let Some(Value::Array(ssd)) = role.role().extra_values.get("ssd") {
for ssd in ssd {
if let Value::String(ssd) = ssd {
if visited.contains(&calculate_hash(ssd)) {
continue; }
visited.insert(calculate_hash(ssd));
if let Some(r) = role.config().role(ssd) {
if r.role().user_min.matching() {
return Ok(true);
}
if check_ssd_recursive(&r, visited)? {
return Ok(true);
}
}
}
}
} else if let Some(Value::String(ssd)) = role.role().extra_values.get("ssd") {
if visited.contains(&calculate_hash(ssd)) {
return Ok(false); }
visited.insert(calculate_hash(ssd));
if let Some(r) = role.config().role(ssd) {
if r.role().user_min.matching() {
return Ok(true);
}
if check_ssd_recursive(&r, visited)? {
return Ok(true);
}
}
} else if let Some(e) = role.role().extra_values.get("ssd") {
debug!("Invalid SSD value: {e:?}");
return Err(SrError::ConfigurationError);
}
Ok(false)
}
fn check_ssd(event: &mut ApiEvent) -> SrResult<()> {
if let ApiEvent::ActorMatching(role, _settings, matching) = event
&& role.role().user_min.matching()
{
let mut visited: HashSet<u64> = HashSet::new();
if check_ssd_recursive(role, &mut visited)? {
**matching = false;
return Ok(());
}
}
Ok(())
}
pub fn register() {
Api::register(super::EventKey::ActorMatching, check_ssd);
}