Skip to main content

clawdentity_core/runtime/
trusted_receipts.rs

1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4use crate::db::now_utc_ms;
5
6#[derive(Clone, Default)]
7pub struct TrustedReceiptsStore {
8    inner: Arc<Mutex<HashMap<String, i64>>>,
9}
10
11impl TrustedReceiptsStore {
12    /// TODO(clawdentity): document `new`.
13    pub fn new() -> Self {
14        Self::default()
15    }
16
17    /// TODO(clawdentity): document `mark_trusted`.
18    pub fn mark_trusted(&self, frame_id: impl Into<String>) {
19        let frame_id = frame_id.into();
20        if frame_id.trim().is_empty() {
21            return;
22        }
23        if let Ok(mut guard) = self.inner.lock() {
24            guard.insert(frame_id, now_utc_ms());
25        }
26    }
27
28    /// TODO(clawdentity): document `is_trusted`.
29    pub fn is_trusted(&self, frame_id: &str) -> bool {
30        if frame_id.trim().is_empty() {
31            return false;
32        }
33        match self.inner.lock() {
34            Ok(guard) => guard.contains_key(frame_id),
35            Err(_) => false,
36        }
37    }
38
39    /// TODO(clawdentity): document `purge_before`.
40    pub fn purge_before(&self, cutoff_ms: i64) -> usize {
41        let Ok(mut guard) = self.inner.lock() else {
42            return 0;
43        };
44
45        let initial_len = guard.len();
46        guard.retain(|_, marked_at_ms| *marked_at_ms >= cutoff_ms);
47        initial_len.saturating_sub(guard.len())
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::TrustedReceiptsStore;
54
55    #[test]
56    fn marks_checks_and_purges_receipts() {
57        let store = TrustedReceiptsStore::new();
58        store.mark_trusted("frame-1");
59        assert!(store.is_trusted("frame-1"));
60        let purged = store.purge_before(i64::MAX);
61        assert_eq!(purged, 1);
62        assert!(!store.is_trusted("frame-1"));
63    }
64}