mas_axum_utils/
session.rs1use mas_data_model::BrowserSession;
8use mas_storage::RepositoryAccess;
9use serde::{Deserialize, Serialize};
10use ulid::Ulid;
11
12use crate::cookies::CookieJar;
13
14#[derive(Serialize, Deserialize, Debug, Default, Clone)]
16pub struct SessionInfo {
17 current: Option<Ulid>,
18}
19
20impl SessionInfo {
21 #[must_use]
23 pub fn from_session(session: &BrowserSession) -> Self {
24 Self {
25 current: Some(session.id),
26 }
27 }
28
29 #[must_use]
31 pub fn mark_session_ended(mut self) -> Self {
32 self.current = None;
33 self
34 }
35
36 pub async fn load_active_session<E>(
42 &self,
43 repo: &mut impl RepositoryAccess<Error = E>,
44 ) -> Result<Option<BrowserSession>, E> {
45 let Some(session_id) = self.current else {
46 return Ok(None);
47 };
48
49 let maybe_session = repo
50 .browser_session()
51 .lookup(session_id)
52 .await?
53 .filter(BrowserSession::active);
55
56 Ok(maybe_session)
57 }
58
59 #[must_use]
61 pub fn current_session_id(&self) -> Option<Ulid> {
62 self.current
63 }
64}
65
66pub trait SessionInfoExt {
67 #[must_use]
68 fn session_info(self) -> (SessionInfo, Self);
69
70 #[must_use]
71 fn update_session_info(self, info: &SessionInfo) -> Self;
72
73 #[must_use]
74 fn set_session(self, session: &BrowserSession) -> Self
75 where
76 Self: Sized,
77 {
78 let session_info = SessionInfo::from_session(session);
79 self.update_session_info(&session_info)
80 }
81}
82
83impl SessionInfoExt for CookieJar {
84 fn session_info(self) -> (SessionInfo, Self) {
85 let info = match self.load("session") {
86 Ok(Some(s)) => s,
87 Ok(None) => SessionInfo::default(),
88 Err(e) => {
89 tracing::error!("failed to load session cookie: {}", e);
90 SessionInfo::default()
91 }
92 };
93
94 let jar = self.update_session_info(&info);
95 (info, jar)
96 }
97
98 fn update_session_info(self, info: &SessionInfo) -> Self {
99 self.save("session", info, true)
100 }
101}