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