mas_storage/
app_session.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7//! Repositories to interact with all kinds of sessions
8
9use async_trait::async_trait;
10use chrono::{DateTime, Utc};
11use mas_data_model::{BrowserSession, CompatSession, Device, Session, User};
12
13use crate::{Page, Pagination, repository_impl};
14
15/// The state of a session
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum AppSessionState {
18    /// The session is active
19    Active,
20    /// The session is finished
21    Finished,
22}
23
24impl AppSessionState {
25    /// Returns [`true`] if we're looking for active sessions
26    #[must_use]
27    pub fn is_active(self) -> bool {
28        matches!(self, Self::Active)
29    }
30
31    /// Returns [`true`] if we're looking for finished sessions
32    #[must_use]
33    pub fn is_finished(self) -> bool {
34        matches!(self, Self::Finished)
35    }
36}
37
38/// An [`AppSession`] is either a [`CompatSession`] or an OAuth 2.0 [`Session`]
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum AppSession {
41    /// A compatibility layer session
42    Compat(Box<CompatSession>),
43
44    /// An OAuth 2.0 session
45    OAuth2(Box<Session>),
46}
47
48/// Filtering parameters for application sessions
49#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
50pub struct AppSessionFilter<'a> {
51    user: Option<&'a User>,
52    browser_session: Option<&'a BrowserSession>,
53    state: Option<AppSessionState>,
54    device_id: Option<&'a Device>,
55    last_active_before: Option<DateTime<Utc>>,
56    last_active_after: Option<DateTime<Utc>>,
57}
58
59impl<'a> AppSessionFilter<'a> {
60    /// Create a new [`AppSessionFilter`] with default values
61    #[must_use]
62    pub fn new() -> Self {
63        Self::default()
64    }
65
66    /// Set the user who owns the sessions
67    #[must_use]
68    pub fn for_user(mut self, user: &'a User) -> Self {
69        self.user = Some(user);
70        self
71    }
72
73    /// Get the user filter
74    #[must_use]
75    pub fn user(&self) -> Option<&'a User> {
76        self.user
77    }
78
79    /// Set the browser session filter
80    #[must_use]
81    pub fn for_browser_session(mut self, browser_session: &'a BrowserSession) -> Self {
82        self.browser_session = Some(browser_session);
83        self
84    }
85
86    /// Get the browser session filter
87    #[must_use]
88    pub fn browser_session(&self) -> Option<&'a BrowserSession> {
89        self.browser_session
90    }
91
92    /// Set the device ID filter
93    #[must_use]
94    pub fn for_device(mut self, device_id: &'a Device) -> Self {
95        self.device_id = Some(device_id);
96        self
97    }
98
99    /// Get the device ID filter
100    #[must_use]
101    pub fn device(&self) -> Option<&'a Device> {
102        self.device_id
103    }
104
105    /// Only return sessions with a last active time before the given time
106    #[must_use]
107    pub fn with_last_active_before(mut self, last_active_before: DateTime<Utc>) -> Self {
108        self.last_active_before = Some(last_active_before);
109        self
110    }
111
112    /// Only return sessions with a last active time after the given time
113    #[must_use]
114    pub fn with_last_active_after(mut self, last_active_after: DateTime<Utc>) -> Self {
115        self.last_active_after = Some(last_active_after);
116        self
117    }
118
119    /// Get the last active before filter
120    ///
121    /// Returns [`None`] if no client filter was set
122    #[must_use]
123    pub fn last_active_before(&self) -> Option<DateTime<Utc>> {
124        self.last_active_before
125    }
126
127    /// Get the last active after filter
128    ///
129    /// Returns [`None`] if no client filter was set
130    #[must_use]
131    pub fn last_active_after(&self) -> Option<DateTime<Utc>> {
132        self.last_active_after
133    }
134
135    /// Only return active compatibility sessions
136    #[must_use]
137    pub fn active_only(mut self) -> Self {
138        self.state = Some(AppSessionState::Active);
139        self
140    }
141
142    /// Only return finished compatibility sessions
143    #[must_use]
144    pub fn finished_only(mut self) -> Self {
145        self.state = Some(AppSessionState::Finished);
146        self
147    }
148
149    /// Get the state filter
150    #[must_use]
151    pub fn state(&self) -> Option<AppSessionState> {
152        self.state
153    }
154}
155
156/// A [`AppSessionRepository`] helps interacting with both [`CompatSession`] and
157/// OAuth 2.0 [`Session`] at the same time saved in the storage backend
158#[async_trait]
159pub trait AppSessionRepository: Send + Sync {
160    /// The error type returned by the repository
161    type Error;
162
163    /// List [`AppSession`] with the given filter and pagination
164    ///
165    /// Returns a page of [`AppSession`] matching the given filter
166    ///
167    /// # Parameters
168    ///
169    /// * `filter`: The filter to apply
170    /// * `pagination`: The pagination parameters
171    ///
172    /// # Errors
173    ///
174    /// Returns [`Self::Error`] if the underlying repository fails
175    async fn list(
176        &mut self,
177        filter: AppSessionFilter<'_>,
178        pagination: Pagination,
179    ) -> Result<Page<AppSession>, Self::Error>;
180
181    /// Count the number of [`AppSession`] with the given filter
182    ///
183    /// # Parameters
184    ///
185    /// * `filter`: The filter to apply
186    ///
187    /// # Errors
188    ///
189    /// Returns [`Self::Error`] if the underlying repository fails
190    async fn count(&mut self, filter: AppSessionFilter<'_>) -> Result<usize, Self::Error>;
191}
192
193repository_impl!(AppSessionRepository:
194    async fn list(
195        &mut self,
196        filter: AppSessionFilter<'_>,
197        pagination: Pagination,
198    ) -> Result<Page<AppSession>, Self::Error>;
199
200    async fn count(&mut self, filter: AppSessionFilter<'_>) -> Result<usize, Self::Error>;
201);