hydrant/
filter.rs

1use jacquard_common::types::nsid::Nsid;
2use serde::{Deserialize, Serialize};
3use std::sync::Arc;
4
5pub(crate) type FilterHandle = Arc<arc_swap::ArcSwap<FilterConfig>>;
6
7pub(crate) fn new_handle(config: FilterConfig) -> FilterHandle {
8    Arc::new(arc_swap::ArcSwap::new(Arc::new(config)))
9}
10
11/// apply a bool patch or set replacement for a single set update.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(untagged)]
14pub(crate) enum SetUpdate {
15    /// replace the entire set with this list
16    Set(Vec<String>),
17    /// patch: true = add, false = remove
18    Patch(std::collections::HashMap<String, bool>),
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(rename_all = "snake_case")]
23pub enum FilterMode {
24    Filter = 0,
25    Full = 2,
26}
27
28#[derive(Debug, Clone, Serialize)]
29pub(crate) struct FilterConfig {
30    pub mode: FilterMode,
31    pub signals: Vec<Nsid<'static>>,
32    pub collections: Vec<Nsid<'static>>,
33}
34
35impl FilterConfig {
36    pub fn new(mode: FilterMode) -> Self {
37        Self {
38            mode,
39            signals: Vec::new(),
40            collections: Vec::new(),
41        }
42    }
43
44    pub fn matches_collection(&self, collection: &str) -> bool {
45        if self.collections.is_empty() {
46            return true;
47        }
48        self.collections.iter().any(|p| nsid_matches(p, collection))
49    }
50
51    pub fn matches_signal(&self, collection: &str) -> bool {
52        self.signals.iter().any(|p| nsid_matches(p, collection))
53    }
54
55    pub fn check_signals(&self) -> bool {
56        self.mode == FilterMode::Filter && !self.signals.is_empty()
57    }
58}
59
60fn nsid_matches(pattern: &str, collection: &str) -> bool {
61    if let Some(prefix) = pattern.strip_suffix(".*") {
62        collection == prefix || collection.starts_with(prefix)
63    } else {
64        collection == pattern
65    }
66}