Skip to main content

mcpr_integrations/store/query/
clients.rs

1//! Query: `mcpr proxy clients <proxy>` — aggregated client breakdown.
2
3use rusqlite::params;
4use serde::Serialize;
5
6use super::QueryEngine;
7
8/// Filter parameters for the clients query.
9pub struct ClientsParams {
10    /// Proxy name to filter by (None = all proxies).
11    pub proxy: Option<String>,
12    /// Only sessions started after this unix ms timestamp.
13    pub since_ts: i64,
14}
15
16/// Aggregated stats for one client identity (name + version + platform).
17#[derive(Debug, Clone, Serialize)]
18pub struct ClientRow {
19    pub client_name: Option<String>,
20    pub client_version: Option<String>,
21    pub client_platform: Option<String>,
22    pub sessions: i64,
23    pub total_calls: i64,
24    pub total_errors: i64,
25    pub error_pct: f64,
26    pub first_seen: i64,
27    pub last_seen: i64,
28}
29
30impl QueryEngine {
31    /// Aggregate client usage across sessions, sorted by total calls descending.
32    pub fn clients(&self, params: &ClientsParams) -> Result<Vec<ClientRow>, rusqlite::Error> {
33        let sql = "
34            SELECT
35                client_name, client_version, client_platform,
36                COUNT(DISTINCT session_id) AS sessions,
37                SUM(total_calls) AS total_calls,
38                SUM(total_errors) AS total_errors,
39                CASE WHEN SUM(total_calls) > 0
40                     THEN SUM(total_errors) * 100.0 / SUM(total_calls)
41                     ELSE 0.0
42                END AS error_pct,
43                MIN(started_at) AS first_seen,
44                MAX(last_seen_at) AS last_seen
45            FROM sessions
46            WHERE (?1 IS NULL OR proxy = ?1) AND started_at >= ?2
47            GROUP BY client_name, client_version, client_platform
48            ORDER BY total_calls DESC
49        ";
50
51        let mut stmt = self.conn().prepare(sql)?;
52        let rows = stmt.query_map(params![params.proxy, params.since_ts], |row| {
53            Ok(ClientRow {
54                client_name: row.get(0)?,
55                client_version: row.get(1)?,
56                client_platform: row.get(2)?,
57                sessions: row.get(3)?,
58                total_calls: row.get(4)?,
59                total_errors: row.get(5)?,
60                error_pct: row.get(6)?,
61                first_seen: row.get(7)?,
62                last_seen: row.get(8)?,
63            })
64        })?;
65
66        rows.collect()
67    }
68}