Skip to main content

sova_scope/
cache.rs

1//! In-process positive membership cache for AuthorizeEngine.
2
3use crate::types::{Membership, ScopeRef};
4use std::collections::HashMap;
5use std::sync::{Arc, Mutex};
6
7type CacheKey = (String, i64, i64);
8
9#[derive(Clone, Default)]
10pub struct MembershipCache {
11    inner: Arc<Mutex<HashMap<CacheKey, Membership>>>,
12}
13
14impl MembershipCache {
15    pub fn new() -> Self {
16        Self::default()
17    }
18
19    fn key(scope: &ScopeRef, user_id: i64) -> CacheKey {
20        (scope.kind.clone(), scope.id, user_id)
21    }
22
23    pub fn get(&self, scope: &ScopeRef, user_id: i64) -> Option<Membership> {
24        self.inner
25            .lock()
26            .unwrap_or_else(|e| e.into_inner())
27            .get(&Self::key(scope, user_id))
28            .cloned()
29    }
30
31    pub fn put(&self, membership: Membership) {
32        let key = (
33            membership.scope_kind.clone(),
34            membership.scope_id,
35            membership.user_id,
36        );
37        self.inner
38            .lock()
39            .unwrap_or_else(|e| e.into_inner())
40            .insert(key, membership);
41    }
42
43    pub fn invalidate(&self, scope: &ScopeRef, user_id: i64) {
44        self.inner
45            .lock()
46            .unwrap_or_else(|e| e.into_inner())
47            .remove(&Self::key(scope, user_id));
48    }
49
50    pub fn invalidate_scope(&self, scope: &ScopeRef) {
51        let mut guard = self.inner.lock().unwrap_or_else(|e| e.into_inner());
52        guard.retain(|(kind, id, _), _| !(kind == &scope.kind && *id == scope.id));
53    }
54
55    pub fn clear(&self) {
56        self.inner
57            .lock()
58            .unwrap_or_else(|e| e.into_inner())
59            .clear();
60    }
61}
62
63/// Options for membership mutations (audit actor + cache invalidate).
64#[derive(Clone, Copy, Default)]
65pub struct MutateOpts<'a> {
66    pub actor_id: Option<i64>,
67    pub cache: Option<&'a MembershipCache>,
68}
69
70impl<'a> MutateOpts<'a> {
71    pub fn new() -> Self {
72        Self::default()
73    }
74
75    pub fn actor(mut self, actor_id: i64) -> Self {
76        self.actor_id = Some(actor_id);
77        self
78    }
79
80    pub fn cache(mut self, cache: &'a MembershipCache) -> Self {
81        self.cache = Some(cache);
82        self
83    }
84}