rocket_session_store/
memory.rs

1//! An in-memory implementationof a session store.
2//!
3//! This module provides [MemoryStore], an implementation of [Store]
4//! to be used for testing and development. It is not optimized for production
5//! and thus you should use another store to use it in the real world.
6
7use std::{
8	collections::HashMap,
9	time::{
10		Duration,
11		Instant,
12	},
13};
14
15use rocket::tokio::sync::{
16	Mutex,
17	RwLock,
18};
19
20use crate::{
21	SessionResult,
22	Store,
23};
24
25/// An in memory implementation of a session store using hashmaps.
26/// Do note that this implementation is just for testing purposes,
27/// and should not be used in any real world application.
28pub struct MemoryStore<T> {
29	map: RwLock<HashMap<String, Mutex<MemoryStoreFrame<T>>>>,
30}
31
32struct MemoryStoreFrame<T> {
33	value: T,
34	expiry: Instant,
35}
36
37impl<T> Default for MemoryStore<T> {
38	fn default() -> Self {
39		Self::new()
40	}
41}
42
43impl<T> MemoryStore<T> {
44	/// Create a new in-memory store
45	pub fn new() -> Self {
46		Self {
47			map: RwLock::default(),
48		}
49	}
50}
51
52#[rocket::async_trait]
53impl<T> Store for MemoryStore<T>
54where
55	T: Send + Sync + Clone,
56{
57	type Value = T;
58
59	async fn get(&self, id: &str) -> SessionResult<Option<Self::Value>> {
60		let lock = self.map.read().await;
61		if let Some(frame) = lock.get(id) {
62			let frame_lock = frame.lock().await;
63			if frame_lock
64				.expiry
65				.checked_duration_since(Instant::now())
66				.is_some()
67			{
68				return Ok(Some(frame_lock.value.clone()));
69			};
70		};
71		Ok(None)
72	}
73
74	async fn set(&self, id: &str, value: Self::Value, expiry: Duration) -> SessionResult<()> {
75		let mut lock = self.map.write().await;
76		let frame = MemoryStoreFrame {
77			value,
78			expiry: Instant::now() + expiry,
79		};
80		lock.insert(id.into(), Mutex::new(frame));
81
82		Ok(())
83	}
84
85	async fn touch(&self, id: &str, duration: Duration) -> SessionResult<()> {
86		let lock = self.map.read().await;
87		if let Some(frame) = lock.get(id) {
88			let mut frame_lock = frame.lock().await;
89			frame_lock.expiry = Instant::now() + duration;
90		};
91		Ok(())
92	}
93
94	async fn remove(&self, id: &str) -> SessionResult<()> {
95		let mut lock = self.map.write().await;
96		lock.remove(id);
97
98		Ok(())
99	}
100}