Skip to main content

systemprompt_analytics/repository/session/
mod.rs

1mod behavioral;
2mod mutations;
3mod queries;
4mod types;
5
6use anyhow::Result;
7use chrono::{DateTime, Utc};
8use systemprompt_database::DbPool;
9use systemprompt_identifiers::{SessionId, UserId};
10
11use crate::models::AnalyticsSession;
12
13pub use types::{
14    CreateSessionParams, SessionBehavioralData, SessionMigrationResult, SessionRecord,
15};
16
17#[derive(Clone, Debug)]
18pub struct SessionRepository {
19    pool: DbPool,
20}
21
22impl SessionRepository {
23    pub const fn new(pool: DbPool) -> Self {
24        Self { pool }
25    }
26
27    pub async fn find_by_id(&self, session_id: &SessionId) -> Result<Option<AnalyticsSession>> {
28        queries::find_by_id(&self.pool, session_id).await
29    }
30
31    pub async fn find_by_fingerprint(
32        &self,
33        fingerprint_hash: &str,
34        user_id: &UserId,
35    ) -> Result<Option<AnalyticsSession>> {
36        queries::find_by_fingerprint(&self.pool, fingerprint_hash, user_id).await
37    }
38
39    pub async fn list_active_by_user(&self, user_id: &UserId) -> Result<Vec<AnalyticsSession>> {
40        queries::list_active_by_user(&self.pool, user_id).await
41    }
42
43    pub async fn update_activity(&self, session_id: &SessionId) -> Result<()> {
44        mutations::update_activity(&self.pool, session_id).await
45    }
46
47    pub async fn increment_request_count(&self, session_id: &SessionId) -> Result<()> {
48        mutations::increment_request_count(&self.pool, session_id).await
49    }
50
51    pub async fn increment_task_count(&self, session_id: &SessionId) -> Result<()> {
52        mutations::increment_task_count(&self.pool, session_id).await
53    }
54
55    pub async fn increment_ai_request_count(&self, session_id: &SessionId) -> Result<()> {
56        mutations::increment_ai_request_count(&self.pool, session_id).await
57    }
58
59    pub async fn increment_message_count(&self, session_id: &SessionId) -> Result<()> {
60        mutations::increment_message_count(&self.pool, session_id).await
61    }
62
63    pub async fn end_session(&self, session_id: &SessionId) -> Result<()> {
64        mutations::end_session(&self.pool, session_id).await
65    }
66
67    pub async fn mark_as_scanner(&self, session_id: &SessionId) -> Result<()> {
68        mutations::mark_as_scanner(&self.pool, session_id).await
69    }
70
71    pub async fn mark_as_behavioral_bot(&self, session_id: &SessionId, reason: &str) -> Result<()> {
72        behavioral::mark_as_behavioral_bot(&self.pool, session_id, reason).await
73    }
74
75    pub async fn check_and_mark_behavioral_bot(
76        &self,
77        session_id: &SessionId,
78        request_count_threshold: i32,
79    ) -> Result<bool> {
80        behavioral::check_and_mark_behavioral_bot(&self.pool, session_id, request_count_threshold)
81            .await
82    }
83
84    pub async fn cleanup_inactive(&self, inactive_hours: i32) -> Result<u64> {
85        mutations::cleanup_inactive(&self.pool, inactive_hours).await
86    }
87
88    pub async fn migrate_user_sessions(
89        &self,
90        old_user_id: &UserId,
91        new_user_id: &UserId,
92    ) -> Result<u64> {
93        mutations::migrate_user_sessions(&self.pool, old_user_id, new_user_id).await
94    }
95
96    pub async fn create_session(&self, params: &CreateSessionParams<'_>) -> Result<()> {
97        mutations::create_session(&self.pool, params).await
98    }
99
100    pub async fn find_recent_by_fingerprint(
101        &self,
102        fingerprint_hash: &str,
103        max_age_seconds: i64,
104    ) -> Result<Option<SessionRecord>> {
105        queries::find_recent_by_fingerprint(&self.pool, fingerprint_hash, max_age_seconds).await
106    }
107
108    pub async fn exists(&self, session_id: &SessionId) -> Result<bool> {
109        queries::exists(&self.pool, session_id).await
110    }
111
112    pub async fn increment_ai_usage(
113        &self,
114        session_id: &SessionId,
115        tokens: i32,
116        cost_cents: i32,
117    ) -> Result<()> {
118        mutations::increment_ai_usage(&self.pool, session_id, tokens, cost_cents).await
119    }
120
121    pub async fn update_behavioral_detection(
122        &self,
123        session_id: &SessionId,
124        score: i32,
125        is_behavioral_bot: bool,
126        reason: Option<&str>,
127    ) -> Result<()> {
128        behavioral::update_behavioral_detection(
129            &self.pool,
130            session_id,
131            score,
132            is_behavioral_bot,
133            reason,
134        )
135        .await
136    }
137
138    pub async fn escalate_throttle(&self, session_id: &SessionId, new_level: i32) -> Result<()> {
139        mutations::escalate_throttle(&self.pool, session_id, new_level).await
140    }
141
142    pub async fn get_throttle_level(&self, session_id: &SessionId) -> Result<i32> {
143        queries::get_throttle_level(&self.pool, session_id).await
144    }
145
146    pub async fn count_sessions_by_fingerprint(
147        &self,
148        fingerprint_hash: &str,
149        window_hours: i64,
150    ) -> Result<i64> {
151        queries::count_sessions_by_fingerprint(&self.pool, fingerprint_hash, window_hours).await
152    }
153
154    pub async fn get_endpoint_sequence(&self, session_id: &SessionId) -> Result<Vec<String>> {
155        queries::get_endpoint_sequence(&self.pool, session_id).await
156    }
157
158    pub async fn get_request_timestamps(
159        &self,
160        session_id: &SessionId,
161    ) -> Result<Vec<DateTime<Utc>>> {
162        queries::get_request_timestamps(&self.pool, session_id).await
163    }
164
165    pub async fn get_total_content_pages(&self) -> Result<i64> {
166        queries::get_total_content_pages(&self.pool).await
167    }
168
169    pub async fn get_session_for_behavioral_analysis(
170        &self,
171        session_id: &SessionId,
172    ) -> Result<Option<SessionBehavioralData>> {
173        queries::get_session_for_behavioral_analysis(&self.pool, session_id).await
174    }
175
176    pub async fn has_analytics_events(&self, session_id: &SessionId) -> Result<bool> {
177        queries::has_analytics_events(&self.pool, session_id).await
178    }
179
180    pub async fn get_session_velocity(
181        &self,
182        session_id: &SessionId,
183    ) -> Result<(Option<i64>, Option<i64>)> {
184        queries::get_session_velocity(&self.pool, session_id).await
185    }
186}