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 crate::repository::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.into()))
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.into()))
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.into()))
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.into()))
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.into()))
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.into()))
56    }
57    async fn increment_request_count(&self, session_id: &SessionId) -> AnalyticsResult<()> {
58        Self::increment_request_count(self, session_id)
59            .await
60            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
61    }
62    async fn end_session(&self, session_id: &SessionId) -> AnalyticsResult<()> {
63        Self::end_session(self, session_id)
64            .await
65            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
66    }
67    async fn mark_as_scanner(&self, session_id: &SessionId) -> AnalyticsResult<()> {
68        Self::mark_as_scanner(self, session_id)
69            .await
70            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
71    }
72    async fn mark_converted(&self, session_id: &SessionId) -> AnalyticsResult<()> {
73        Self::mark_converted(self, session_id)
74            .await
75            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
76    }
77    async fn mark_ghost_sessions_as_bots(&self) -> AnalyticsResult<u64> {
78        Self::mark_ghost_sessions_as_bots(self)
79            .await
80            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
81    }
82    async fn mark_no_js_sessions_as_bots(&self, engaged: &[SessionId]) -> AnalyticsResult<u64> {
83        Self::mark_no_js_sessions_as_bots(self, engaged)
84            .await
85            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
86    }
87    async fn check_and_mark_behavioral_bot(
88        &self,
89        session_id: &SessionId,
90        request_count_threshold: i32,
91    ) -> AnalyticsResult<bool> {
92        Self::check_and_mark_behavioral_bot(self, session_id, request_count_threshold)
93            .await
94            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
95    }
96    async fn cleanup_inactive(&self, inactive_hours: i32) -> AnalyticsResult<u64> {
97        Self::cleanup_inactive(self, inactive_hours)
98            .await
99            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
100    }
101    async fn count_inactive(&self, inactive_hours: i32) -> AnalyticsResult<i64> {
102        Self::count_inactive(self, inactive_hours)
103            .await
104            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
105    }
106    async fn count_sessions_missing_geo(&self) -> AnalyticsResult<i64> {
107        Self::count_sessions_missing_geo(self)
108            .await
109            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
110    }
111    async fn insert_session(&self, params: &CreateSessionParams<'_>) -> AnalyticsResult<()> {
112        Self::create_session(self, params)
113            .await
114            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
115    }
116    async fn find_recent_by_fingerprint(
117        &self,
118        fingerprint_hash: &str,
119        max_age_seconds: i64,
120    ) -> AnalyticsResult<Option<SessionRecord>> {
121        Self::find_recent_anonymous_by_fingerprint(self, fingerprint_hash, max_age_seconds)
122            .await
123            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
124    }
125    async fn increment_ai_usage(
126        &self,
127        session_id: &SessionId,
128        tokens: i32,
129        cost_microdollars: i64,
130    ) -> AnalyticsResult<()> {
131        Self::increment_ai_usage(self, session_id, tokens, cost_microdollars)
132            .await
133            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
134    }
135    async fn update_behavioral_detection(
136        &self,
137        session_id: &SessionId,
138        score: i32,
139        is_behavioral_bot: bool,
140        reason: Option<&str>,
141    ) -> AnalyticsResult<()> {
142        Self::update_behavioral_detection(self, session_id, score, is_behavioral_bot, reason)
143            .await
144            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
145    }
146    async fn count_sessions_by_fingerprint(
147        &self,
148        fingerprint_hash: &str,
149        window_hours: i64,
150    ) -> AnalyticsResult<i64> {
151        Self::count_sessions_by_fingerprint(self, fingerprint_hash, window_hours)
152            .await
153            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
154    }
155    async fn get_session_for_behavioral_analysis(
156        &self,
157        session_id: &SessionId,
158    ) -> AnalyticsResult<Option<SessionBehavioralData>> {
159        Self::get_session_for_behavioral_analysis(self, session_id)
160            .await
161            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
162    }
163    async fn count_unique_ips_by_fingerprint(
164        &self,
165        fingerprint_hash: &str,
166        window_days: i64,
167    ) -> AnalyticsResult<i64> {
168        Self::count_unique_ips_by_fingerprint(self, fingerprint_hash, window_days)
169            .await
170            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
171    }
172    async fn get_session_starts_by_fingerprint(
173        &self,
174        fingerprint_hash: &str,
175        window_days: i64,
176    ) -> AnalyticsResult<Vec<DateTime<Utc>>> {
177        Self::get_session_starts_by_fingerprint(self, fingerprint_hash, window_days)
178            .await
179            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
180    }
181    async fn get_session_velocity(
182        &self,
183        session_id: &SessionId,
184    ) -> AnalyticsResult<(Option<i64>, Option<i64>)> {
185        Self::get_session_velocity(self, session_id)
186            .await
187            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
188    }
189    async fn count_active_fingerprint_sessions(&self, fingerprint: &str) -> AnalyticsResult<i32> {
190        self.count_active_fingerprint(fingerprint)
191            .await
192            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
193    }
194    async fn find_reusable_fingerprint_session(
195        &self,
196        fingerprint: &str,
197    ) -> AnalyticsResult<Option<SessionId>> {
198        self.find_reusable_fingerprint(fingerprint)
199            .await
200            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
201    }
202    async fn sessions_missing_geo(
203        &self,
204        after: Option<&SessionId>,
205        limit: i64,
206    ) -> AnalyticsResult<Vec<(SessionId, String)>> {
207        self.missing_geo(after, limit)
208            .await
209            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
210    }
211    async fn set_session_geo(
212        &self,
213        session_id: &SessionId,
214        country: Option<&str>,
215        region: Option<&str>,
216        city: Option<&str>,
217    ) -> AnalyticsResult<u64> {
218        self.set_geo(session_id, country, region, city)
219            .await
220            .map_err(|e| AnalyticsProviderError::Internal(e.into()))
221    }
222}