systemprompt_analytics/repository/session/
mod.rs1mod 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}