Skip to main content

axum_security/cookie/store/
mod.rs

1mod memory;
2
3use std::{error::Error, pin::Pin, sync::Arc};
4
5pub use memory::MemStore;
6
7use crate::cookie::{CookieSession, SessionId};
8
9pub trait CookieStore: Send + Sync + 'static {
10    type State: Send + Sync + 'static;
11    type Error: std::error::Error + Send + Sync + 'static;
12
13    fn spawn_maintenance_task(&self) -> bool {
14        true
15    }
16
17    fn store_session(
18        &self,
19        session: CookieSession<Self::State>,
20    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
21
22    fn remove_session(
23        &self,
24        id: &SessionId,
25    ) -> impl Future<Output = Result<Option<CookieSession<Self::State>>, Self::Error>> + Send;
26
27    fn load_session(
28        &self,
29        id: &SessionId,
30    ) -> impl Future<Output = Result<Option<CookieSession<Self::State>>, Self::Error>> + Send;
31
32    fn remove_before(&self, deadline: u64) -> impl Future<Output = Result<(), Self::Error>> + Send;
33}
34
35pub type BoxDynError = Box<dyn Error + Send + 'static>;
36
37#[allow(clippy::type_complexity)]
38trait DynStore<S>: Send + Sync + 'static {
39    fn spawn_maintenance_task(&self) -> bool;
40
41    fn store_session(
42        &self,
43        session: CookieSession<S>,
44    ) -> Pin<Box<dyn Future<Output = Result<(), BoxDynError>> + Send + '_>>;
45
46    fn remove_session<'a>(
47        &'a self,
48        id: &'a SessionId,
49    ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<S>>, BoxDynError>> + Send + 'a>>;
50
51    fn load_session<'a>(
52        &'a self,
53        id: &'a SessionId,
54    ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<S>>, BoxDynError>> + Send + 'a>>;
55
56    fn remove_before(
57        &self,
58        deadline: u64,
59    ) -> Pin<Box<dyn Future<Output = Result<(), BoxDynError>> + Send + '_>>;
60}
61
62impl<T> DynStore<T::State> for T
63where
64    T: CookieStore,
65{
66    fn spawn_maintenance_task(&self) -> bool {
67        <T as CookieStore>::spawn_maintenance_task(self)
68    }
69
70    fn store_session(
71        &self,
72        session: CookieSession<T::State>,
73    ) -> Pin<Box<dyn Future<Output = Result<(), BoxDynError>> + Send + '_>> {
74        Box::pin(async move {
75            <T as CookieStore>::store_session(self, session)
76                .await
77                .map_err(|e| Box::new(e) as Box<dyn Error + Send>)
78        })
79    }
80
81    fn remove_session<'a>(
82        &'a self,
83        id: &'a SessionId,
84    ) -> Pin<
85        Box<dyn Future<Output = Result<Option<CookieSession<T::State>>, BoxDynError>> + Send + 'a>,
86    > {
87        Box::pin(async move {
88            <T as CookieStore>::remove_session(self, id)
89                .await
90                .map_err(|e| Box::new(e) as Box<dyn Error + Send>)
91        })
92    }
93
94    fn load_session<'a>(
95        &'a self,
96        id: &'a SessionId,
97    ) -> Pin<
98        Box<dyn Future<Output = Result<Option<CookieSession<T::State>>, BoxDynError>> + Send + 'a>,
99    > {
100        Box::pin(async move {
101            <T as CookieStore>::load_session(self, id)
102                .await
103                .map_err(|e| Box::new(e) as Box<dyn Error + Send>)
104        })
105    }
106
107    fn remove_before(
108        &self,
109        deadline: u64,
110    ) -> Pin<Box<dyn Future<Output = Result<(), BoxDynError>> + Send + '_>> {
111        Box::pin(async move {
112            <T as CookieStore>::remove_before(self, deadline)
113                .await
114                .map_err(|e| Box::new(e) as Box<dyn Error + Send>)
115        })
116    }
117}
118
119pub(crate) struct ErasedStore<S>(Arc<dyn DynStore<S>>);
120
121impl<S: 'static> ErasedStore<S> {
122    pub fn new(store: S) -> ErasedStore<S::State>
123    where
124        S: CookieStore,
125    {
126        ErasedStore(Arc::new(store))
127    }
128
129    pub fn spawn_maintenance_task(&self) -> bool {
130        self.0.spawn_maintenance_task()
131    }
132
133    pub async fn store_session(
134        &self,
135        session: CookieSession<S>,
136    ) -> Result<(), Box<dyn Error + Send + 'static>> {
137        self.0.store_session(session).await
138    }
139
140    pub async fn remove_session(
141        &self,
142        id: &SessionId,
143    ) -> Result<Option<CookieSession<S>>, BoxDynError> {
144        self.0.remove_session(id).await
145    }
146
147    pub async fn load_session(
148        &self,
149        id: &SessionId,
150    ) -> Result<Option<CookieSession<S>>, BoxDynError> {
151        self.0.load_session(id).await
152    }
153
154    pub async fn remove_before(&self, deadline: u64) -> Result<(), BoxDynError> {
155        self.0.remove_before(deadline).await
156    }
157}
158
159impl<S> Clone for ErasedStore<S> {
160    fn clone(&self) -> Self {
161        ErasedStore(self.0.clone())
162    }
163}