Skip to main content

senax_common/session/
interface.rs

1use anyhow::Result;
2use derive_more::Display;
3use std::time::{SystemTime, UNIX_EPOCH};
4use time::Duration;
5use zstd::{decode_all, stream::copy_encode};
6
7use crate::session::SessionKey;
8
9#[derive(Default, Clone)]
10pub struct SessionData {
11    pub(crate) data: Vec<u8>,
12    pub(crate) ttl: Duration,
13    pub(crate) version: u32,
14}
15
16impl SessionData {
17    pub fn new(data: &[u8], eol: u64, version: u32) -> SessionData {
18        let data = if data.len() > 1 && data[0] == 0 {
19            decode_all(&data[1..]).unwrap_or_default()
20        } else {
21            data.to_vec()
22        };
23        let now = SystemTime::now()
24            .duration_since(UNIX_EPOCH)
25            .unwrap()
26            .as_secs() as i64;
27        SessionData {
28            data,
29            ttl: Duration::new((eol as i64) - now, 0),
30            version,
31        }
32    }
33    pub fn is_empty_data(&self) -> bool {
34        self.data.is_empty()
35    }
36    pub fn data(&self) -> &[u8] {
37        &self.data
38    }
39    pub fn compressed_data(&self) -> Vec<u8> {
40        let mut enc = Vec::<u8>::with_capacity(self.data.len() + 100);
41        enc.push(0);
42        copy_encode(&*self.data, &mut enc, 1).unwrap();
43        if enc.len() < self.data.len() {
44            enc
45        } else {
46            self.data.clone()
47        }
48    }
49    pub fn ttl(&self) -> i64 {
50        self.ttl.whole_seconds()
51    }
52    pub fn ttl_as_duration(&self) -> Duration {
53        self.ttl
54    }
55    pub fn set_ttl(&mut self, ttl: Duration) {
56        self.ttl = ttl;
57    }
58    pub fn eol(&self) -> u64 {
59        let now = SystemTime::now()
60            .duration_since(UNIX_EPOCH)
61            .unwrap()
62            .as_secs() as i64;
63        (now + self.ttl.whole_seconds()) as u64
64    }
65    pub fn version(&self) -> u32 {
66        self.version
67    }
68    pub fn set_version(&mut self, version: u32) {
69        self.version = version;
70    }
71}
72
73impl From<(Vec<u8>, Duration, u32)> for SessionData {
74    fn from(v: (Vec<u8>, Duration, u32)) -> Self {
75        Self {
76            data: v.0,
77            ttl: v.1,
78            version: v.2,
79        }
80    }
81}
82
83#[async_trait::async_trait]
84pub trait SessionStore {
85    async fn load(&self, session_key: &SessionKey) -> Result<Option<SessionData>>;
86    async fn reload(&self, session_key: &SessionKey) -> Result<Option<SessionData>>;
87    async fn save(
88        &self,
89        session_key: Option<SessionKey>,
90        data: SessionData,
91    ) -> Result<SessionKey, SaveError>;
92    async fn update_ttl(&self, session_key: &SessionKey, data: &SessionData) -> Result<()>;
93    async fn delete(&self, session_key: &SessionKey) -> Result<()>;
94    async fn gc(&self, start_key: &SessionKey) -> Result<()>;
95}
96
97#[derive(Display)]
98#[display("")]
99pub enum SaveError {
100    Retryable,
101    RetryableWithData(SessionData),
102    Other(anyhow::Error),
103}
104impl std::fmt::Debug for SaveError {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        f.debug_struct("SaveError").finish()
107    }
108}
109
110impl std::error::Error for SaveError {
111    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
112        match self {
113            Self::Retryable => None,
114            Self::RetryableWithData(_) => None,
115            Self::Other(err) => Some(err.as_ref()),
116        }
117    }
118}