mcpr_integrations/store/query/
sessions.rs1use rusqlite::params;
4use serde::Serialize;
5
6use super::QueryEngine;
7
8const ACTIVE_SESSION_THRESHOLD_MS: i64 = 5 * 60 * 1000; pub struct SessionsParams {
14 pub proxy: Option<String>,
16 pub since_ts: i64,
18 pub limit: i64,
20 pub active_only: bool,
22 pub client: Option<String>,
24}
25
26#[derive(Debug, Clone, Serialize)]
28pub struct SessionRow {
29 pub session_id: String,
30 pub client_name: Option<String>,
31 pub client_version: Option<String>,
32 pub client_platform: Option<String>,
33 pub started_at: i64,
34 pub last_seen_at: i64,
35 pub ended_at: Option<i64>,
36 pub total_calls: i64,
37 pub total_errors: i64,
38 pub is_active: bool,
39}
40
41impl QueryEngine {
42 pub fn sessions(&self, params: &SessionsParams) -> Result<Vec<SessionRow>, rusqlite::Error> {
44 let now_ms = chrono::Utc::now().timestamp_millis();
45 let active_threshold = now_ms - ACTIVE_SESSION_THRESHOLD_MS;
46
47 let sql = "
48 SELECT
49 session_id, client_name, client_version, client_platform,
50 started_at, last_seen_at, ended_at, total_calls, total_errors,
51 (ended_at IS NULL AND last_seen_at > ?1) AS is_active
52 FROM sessions
53 WHERE (?2 IS NULL OR proxy = ?2)
54 AND (?3 IS NULL OR client_name = ?3)
55 AND (?4 = 0 OR (ended_at IS NULL AND last_seen_at > ?1))
56 AND started_at >= ?5
57 ORDER BY last_seen_at DESC
58 LIMIT ?6
59 ";
60
61 let active_flag: i64 = if params.active_only { 1 } else { 0 };
62
63 let mut stmt = self.conn().prepare(sql)?;
64 let rows = stmt.query_map(
65 params![
66 active_threshold,
67 params.proxy,
68 params.client,
69 active_flag,
70 params.since_ts,
71 params.limit,
72 ],
73 |row| {
74 Ok(SessionRow {
75 session_id: row.get(0)?,
76 client_name: row.get(1)?,
77 client_version: row.get(2)?,
78 client_platform: row.get(3)?,
79 started_at: row.get(4)?,
80 last_seen_at: row.get(5)?,
81 ended_at: row.get(6)?,
82 total_calls: row.get(7)?,
83 total_errors: row.get(8)?,
84 is_active: row.get(9)?,
85 })
86 },
87 )?;
88
89 rows.collect()
90 }
91}