tower_sessions_moka_store/
lib.rs1use std::time::{Duration as StdDuration, Instant as StdInstant};
2
3use async_trait::async_trait;
4use moka::{future::Cache, Expiry};
5use time::OffsetDateTime;
6use tower_sessions_core::{
7 session::{Id, Record},
8 session_store, SessionStore,
9};
10
11#[derive(Debug, Clone)]
17pub struct MokaStore {
18 cache: Cache<Id, Record>,
19}
20
21impl MokaStore {
22 pub fn new(max_capacity: Option<u64>) -> Self {
32 let cache_builder = match max_capacity {
35 Some(capacity) => Cache::builder().max_capacity(capacity),
36 None => Cache::builder(),
37 }
38 .expire_after(SessionExpiry);
39
40 Self {
41 cache: cache_builder.build(),
42 }
43 }
44}
45
46#[async_trait]
47impl SessionStore for MokaStore {
48 async fn create(&self, record: &mut Record) -> session_store::Result<()> {
49 while self.cache.contains_key(&record.id) {
50 record.id = Id::default();
51 }
52 self.cache.insert(record.id, record.clone()).await;
53 Ok(())
54 }
55
56 async fn save(&self, record: &Record) -> session_store::Result<()> {
57 self.cache.insert(record.id, record.clone()).await;
58 Ok(())
59 }
60
61 async fn load(&self, session_id: &Id) -> session_store::Result<Option<Record>> {
62 Ok(self.cache.get(session_id).await)
65 }
66
67 async fn delete(&self, session_id: &Id) -> session_store::Result<()> {
68 self.cache.invalidate(session_id).await;
69 Ok(())
70 }
71}
72
73struct SessionExpiry;
75
76impl SessionExpiry {
77 fn expiry_date_to_duration(record: &Record) -> StdDuration {
83 let now = OffsetDateTime::now_utc();
87 let expiry_date = record.expiry_date;
88
89 if expiry_date > now {
90 (expiry_date - now).unsigned_abs()
91 } else {
92 StdDuration::default()
93 }
94 }
95}
96
97impl Expiry<Id, Record> for SessionExpiry {
98 fn expire_after_create(
99 &self,
100 _id: &Id,
101 record: &Record,
102 _created_at: StdInstant,
103 ) -> Option<StdDuration> {
104 Some(Self::expiry_date_to_duration(record))
105 }
106
107 fn expire_after_update(
108 &self,
109 _id: &Id,
110 record: &Record,
111 _updated_at: StdInstant,
112 _duration_until_expiry: Option<StdDuration>,
113 ) -> Option<StdDuration> {
114 Some(Self::expiry_date_to_duration(record))
116 }
117}