use reinhardt_http::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{Duration, SystemTime};
use uuid::Uuid;
use super::id::ActiveSessionId;
pub const USER_ID_SESSION_KEY: &str = "user_id";
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct SessionData {
pub id: String,
pub data: HashMap<String, serde_json::Value>,
pub created_at: SystemTime,
pub last_accessed: SystemTime,
pub expires_at: SystemTime,
#[serde(skip)]
pub id_holder: Option<ActiveSessionId>,
}
impl SessionData {
pub fn new(ttl: Duration) -> Self {
let now = SystemTime::now();
Self {
id: Uuid::new_v4().to_string(),
data: HashMap::new(),
created_at: now,
last_accessed: now,
expires_at: now + ttl,
id_holder: None,
}
}
pub fn regenerate_id(&mut self) -> String {
let old_id = std::mem::replace(&mut self.id, Uuid::now_v7().to_string());
if let Some(holder) = &self.id_holder {
holder.set(self.id.clone());
}
old_id
}
pub(super) fn is_valid(&self) -> bool {
SystemTime::now() < self.expires_at
}
pub fn touch(&mut self, ttl: Duration) {
let now = SystemTime::now();
self.last_accessed = now;
self.expires_at = now + ttl;
}
pub fn get<T>(&self, key: &str) -> Option<T>
where
T: for<'de> Deserialize<'de>,
{
self.data
.get(key)
.and_then(|v| serde_json::from_value(v.clone()).ok())
}
pub fn set<T>(&mut self, key: String, value: T) -> Result<()>
where
T: Serialize,
{
self.data.insert(
key,
serde_json::to_value(value)
.map_err(|e| reinhardt_core::exception::Error::Serialization(e.to_string()))?,
);
Ok(())
}
pub fn delete(&mut self, key: &str) {
self.data.remove(key);
}
pub fn contains_key(&self, key: &str) -> bool {
self.data.contains_key(key)
}
pub fn clear(&mut self) {
self.data.clear();
}
}