1use std::{
2 fmt::Debug,
3 io::{Error, ErrorKind, Result},
4 time::Duration,
5};
6
7use redis::{aio::ConnectionLike, AsyncCommands};
8use sessions_core::{Data, Storage};
9
10#[derive(Clone, Debug)]
11pub struct RedisStorage<T> {
12 inner: T,
13}
14
15impl<T> RedisStorage<T> {
16 #[must_use]
17 pub fn new(client: T) -> Self {
18 Self { inner: client }
19 }
20
21 #[must_use]
23 pub fn get_ref(&self) -> &T {
24 &self.inner
25 }
26}
27
28impl<T> Storage for RedisStorage<T>
29where
30 T: ConnectionLike + Clone + Send + Sync,
31{
32 async fn get(&self, key: &str) -> Result<Option<Data>> {
33 Ok(serde_json::from_slice(
34 &self
35 .get_ref()
36 .clone()
37 .get::<&str, Vec<u8>>(key)
38 .await
39 .map_err(into_io_error)?,
40 )
41 .ok())
42 }
43
44 async fn set(&self, key: &str, val: Data, exp: &Duration) -> Result<()> {
45 self.get_ref()
46 .clone()
47 .set_ex(key, serde_json::to_vec(&val)?, exp.as_secs())
48 .await
49 .map_err(into_io_error)
50 }
51
52 async fn remove(&self, key: &str) -> Result<()> {
53 self.get_ref().clone().del(key).await.map_err(into_io_error)
54 }
55
56 async fn reset(&self) -> Result<()> {
57 redis::cmd("FLASHDB")
58 .query_async(&mut self.get_ref().clone())
59 .await
60 .map_err(into_io_error)
61 }
62}
63
64#[inline]
65fn into_io_error<E: std::error::Error + Send + Sync + 'static>(e: E) -> Error {
66 Error::new(ErrorKind::Other, e)
67}