Skip to main content

axum_rh/router/utils/
session_manager.rs

1use axum::{
2    extract::FromRequestParts,
3    http::{request::Parts, StatusCode},
4};
5use serde::{Deserialize, Serialize};
6use time::OffsetDateTime;
7use tower_sessions::Session;
8
9pub trait SessionTrait: Send + Sync + Serialize + for<'de> Deserialize<'de> + Default {
10    fn key(&self) -> Option<String>;
11    fn set_key(&mut self, key: String);
12    fn has_key(&self) -> bool {
13        self.key().is_some()
14    }
15}
16
17#[derive(Serialize, Deserialize, Debug, Clone)]
18pub struct SessionData {
19    pub user_id: Option<String>,
20    pub created_at: OffsetDateTime,
21    pub end_at: OffsetDateTime,
22}
23
24impl SessionTrait for SessionData {
25    fn key(&self) -> Option<String> {
26        self.user_id.clone()
27    }
28
29    fn set_key(&mut self, key: String) {
30        self.user_id = Some(key);
31    }
32}
33
34impl Default for SessionData {
35    fn default() -> Self {
36        Self {
37            user_id: None,
38            created_at: OffsetDateTime::now_utc(),
39            end_at: OffsetDateTime::now_utc(),
40        }
41    }
42}
43pub struct SessionObject<T>
44where
45    T: SessionTrait,
46{
47    pub session: Session,
48    pub data: T,
49}
50
51impl<T> SessionObject<T>
52where
53    T: SessionTrait,
54{
55    const DATA_KEY: &'static str = "data";
56
57    pub async fn update(&mut self) {
58        Self::update_session(&self.session, &self.data).await;
59    }
60
61    pub async fn update_key(&mut self, key: String) {
62        self.data.set_key(key);
63        self.update().await;
64    }
65
66    async fn update_session(session: &Session, session_data: &T) {
67        match session.insert(Self::DATA_KEY, session_data).await {
68            Ok(_) => {}
69            Err(e) => {
70                log::error!("Error updating session: {:?}", e);
71            }
72        };
73        match session.save().await {
74            Ok(_) => {}
75            Err(e) => {
76                log::error!("Error saving session: {:?}", e);
77            }
78        };
79    }
80
81    pub async fn clear(&mut self) {
82        self.data = T::default();
83        self.session.clear().await;
84    }
85}
86
87impl<S, T> FromRequestParts<S> for SessionObject<T>
88where
89    S: Send + Sync,
90    T: SessionTrait,
91{
92    type Rejection = (StatusCode, &'static str);
93
94    async fn from_request_parts(req: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
95        let session = Session::from_request_parts(req, state).await?;
96
97        let data: T = session
98            .get(Self::DATA_KEY)
99            .await
100            .expect("session data not found")
101            .unwrap_or_default();
102
103        Self::update_session(&session, &data).await;
104        Ok(Self { session, data })
105    }
106}