senax_common/session/
interface.rs1use 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}