Skip to main content

systemprompt_users/sessions/
store.rs

1//! Authoritative session persistence contracts.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use super::SessionRepository;
7use async_trait::async_trait;
8use chrono::{DateTime, Utc};
9use systemprompt_identifiers::{SessionId, UserId};
10use systemprompt_traits::session_store::{
11    ActiveSessionLookup, CreateSessionParams, SessionBehavioralData, SessionRecord, SessionSnapshot,
12};
13use systemprompt_traits::{AnalyticsProviderError, AnalyticsResult};
14#[async_trait]
15impl systemprompt_traits::SessionStore for SessionRepository {
16    async fn fingerprint_session_ids(
17        &self,
18        fingerprint: &str,
19        window_days: i64,
20    ) -> AnalyticsResult<Vec<SessionId>> {
21        Self::fingerprint_session_ids(self, fingerprint, window_days)
22            .await
23            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
24    }
25    async fn find_by_id(&self, session_id: &SessionId) -> AnalyticsResult<Option<SessionSnapshot>> {
26        Self::find_by_id(self, session_id)
27            .await
28            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
29    }
30    async fn find_active_by_id(
31        &self,
32        session_id: &SessionId,
33    ) -> AnalyticsResult<Option<ActiveSessionLookup>> {
34        Self::find_active_by_id(self, session_id)
35            .await
36            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
37    }
38    async fn revoke_all_for_user(&self, user_id: &UserId) -> AnalyticsResult<u64> {
39        Self::revoke_all_for_user(self, user_id)
40            .await
41            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
42    }
43    async fn find_by_fingerprint(
44        &self,
45        fingerprint_hash: &str,
46        user_id: &UserId,
47    ) -> AnalyticsResult<Option<SessionSnapshot>> {
48        Self::find_by_fingerprint(self, fingerprint_hash, user_id)
49            .await
50            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
51    }
52    async fn list_active_by_user(&self, user_id: &UserId) -> AnalyticsResult<Vec<SessionSnapshot>> {
53        Self::list_active_by_user(self, user_id)
54            .await
55            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
56    }
57    async fn update_activity(&self, session_id: &SessionId) -> AnalyticsResult<()> {
58        Self::update_activity(self, session_id)
59            .await
60            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
61    }
62    async fn increment_request_count(&self, session_id: &SessionId) -> AnalyticsResult<()> {
63        Self::increment_request_count(self, session_id)
64            .await
65            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
66    }
67    async fn end_session(&self, session_id: &SessionId) -> AnalyticsResult<()> {
68        Self::end_session(self, session_id)
69            .await
70            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
71    }
72    async fn mark_as_scanner(&self, session_id: &SessionId) -> AnalyticsResult<()> {
73        Self::mark_as_scanner(self, session_id)
74            .await
75            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
76    }
77    async fn mark_converted(&self, session_id: &SessionId) -> AnalyticsResult<()> {
78        Self::mark_converted(self, session_id)
79            .await
80            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
81    }
82    async fn mark_as_behavioral_bot(
83        &self,
84        session_id: &SessionId,
85        reason: &str,
86    ) -> AnalyticsResult<()> {
87        Self::mark_as_behavioral_bot(self, session_id, reason)
88            .await
89            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
90    }
91    async fn check_and_mark_behavioral_bot(
92        &self,
93        session_id: &SessionId,
94        request_count_threshold: i32,
95    ) -> AnalyticsResult<bool> {
96        Self::check_and_mark_behavioral_bot(self, session_id, request_count_threshold)
97            .await
98            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
99    }
100    async fn cleanup_inactive(&self, inactive_hours: i32) -> AnalyticsResult<u64> {
101        Self::cleanup_inactive(self, inactive_hours)
102            .await
103            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
104    }
105    async fn count_inactive(&self, inactive_hours: i32) -> AnalyticsResult<i64> {
106        Self::count_inactive(self, inactive_hours)
107            .await
108            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
109    }
110    async fn count_sessions_missing_geo(&self) -> AnalyticsResult<i64> {
111        Self::count_sessions_missing_geo(self)
112            .await
113            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
114    }
115    async fn insert_session(&self, params: &CreateSessionParams<'_>) -> AnalyticsResult<()> {
116        Self::create_session(self, params)
117            .await
118            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
119    }
120    async fn find_recent_by_fingerprint(
121        &self,
122        fingerprint_hash: &str,
123        max_age_seconds: i64,
124    ) -> AnalyticsResult<Option<SessionRecord>> {
125        Self::find_recent_by_fingerprint(self, fingerprint_hash, max_age_seconds)
126            .await
127            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
128    }
129    async fn increment_ai_usage(
130        &self,
131        session_id: &SessionId,
132        tokens: i32,
133        cost_microdollars: i64,
134    ) -> AnalyticsResult<()> {
135        Self::increment_ai_usage(self, session_id, tokens, cost_microdollars)
136            .await
137            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
138    }
139    async fn update_behavioral_detection(
140        &self,
141        session_id: &SessionId,
142        score: i32,
143        is_behavioral_bot: bool,
144        reason: Option<&str>,
145    ) -> AnalyticsResult<()> {
146        Self::update_behavioral_detection(self, session_id, score, is_behavioral_bot, reason)
147            .await
148            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
149    }
150    async fn count_sessions_by_fingerprint(
151        &self,
152        fingerprint_hash: &str,
153        window_hours: i64,
154    ) -> AnalyticsResult<i64> {
155        Self::count_sessions_by_fingerprint(self, fingerprint_hash, window_hours)
156            .await
157            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
158    }
159    async fn get_session_for_behavioral_analysis(
160        &self,
161        session_id: &SessionId,
162    ) -> AnalyticsResult<Option<SessionBehavioralData>> {
163        Self::get_session_for_behavioral_analysis(self, session_id)
164            .await
165            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
166    }
167    async fn count_unique_ips_by_fingerprint(
168        &self,
169        fingerprint_hash: &str,
170        window_days: i64,
171    ) -> AnalyticsResult<i64> {
172        Self::count_unique_ips_by_fingerprint(self, fingerprint_hash, window_days)
173            .await
174            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
175    }
176    async fn get_session_starts_by_fingerprint(
177        &self,
178        fingerprint_hash: &str,
179        window_days: i64,
180    ) -> AnalyticsResult<Vec<DateTime<Utc>>> {
181        Self::get_session_starts_by_fingerprint(self, fingerprint_hash, window_days)
182            .await
183            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
184    }
185    async fn get_session_velocity(
186        &self,
187        session_id: &SessionId,
188    ) -> AnalyticsResult<(Option<i64>, Option<i64>)> {
189        Self::get_session_velocity(self, session_id)
190            .await
191            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
192    }
193    async fn count_active_fingerprint_sessions(&self, fingerprint: &str) -> AnalyticsResult<i32> {
194        self.count_active_fingerprint(fingerprint)
195            .await
196            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
197    }
198    async fn find_reusable_fingerprint_session(
199        &self,
200        fingerprint: &str,
201    ) -> AnalyticsResult<Option<SessionId>> {
202        self.find_reusable_fingerprint(fingerprint)
203            .await
204            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
205    }
206    async fn sessions_missing_geo(
207        &self,
208        after: Option<&SessionId>,
209        limit: i64,
210    ) -> AnalyticsResult<Vec<(SessionId, String)>> {
211        self.missing_geo(after, limit)
212            .await
213            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
214    }
215    async fn set_session_geo(
216        &self,
217        session_id: &SessionId,
218        country: Option<&str>,
219        region: Option<&str>,
220        city: Option<&str>,
221    ) -> AnalyticsResult<u64> {
222        self.set_geo(session_id, country, region, city)
223            .await
224            .map_err(|e| AnalyticsProviderError::Internal(e.to_string()))
225    }
226}