use std::collections::HashMap;
use std::sync::RwLock;
use std::time::{SystemTime, UNIX_EPOCH};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::error::Result;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsentGrant {
pub purpose: String,
pub version: String,
pub granted: bool,
pub timestamp: u64,
}
#[async_trait]
pub trait ConsentStore: Send + Sync + 'static {
async fn record(&self, user_id: &str, grant: ConsentGrant) -> Result<()>;
async fn current(&self, user_id: &str) -> Result<Vec<ConsentGrant>>;
async fn has_consent(&self, user_id: &str, purpose: &str) -> Result<bool> {
Ok(self
.current(user_id)
.await?
.into_iter()
.find(|g| g.purpose == purpose)
.map(|g| g.granted)
.unwrap_or(false))
}
}
pub fn now() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
}
#[derive(Default)]
pub struct MemoryConsentStore {
inner: RwLock<HashMap<String, Vec<ConsentGrant>>>,
}
impl MemoryConsentStore {
pub fn new() -> Self {
Self::default()
}
}
#[async_trait]
impl ConsentStore for MemoryConsentStore {
async fn record(&self, user_id: &str, grant: ConsentGrant) -> Result<()> {
self.inner
.write()
.unwrap()
.entry(user_id.to_owned())
.or_default()
.push(grant);
Ok(())
}
async fn current(&self, user_id: &str) -> Result<Vec<ConsentGrant>> {
let guard = self.inner.read().unwrap();
let Some(history) = guard.get(user_id) else {
return Ok(Vec::new());
};
let mut latest: HashMap<&str, &ConsentGrant> = HashMap::new();
for g in history {
latest
.entry(g.purpose.as_str())
.and_modify(|cur| {
if g.timestamp >= cur.timestamp {
*cur = g;
}
})
.or_insert(g);
}
Ok(latest.into_values().cloned().collect())
}
}