systemprompt_cli/commands/analytics/traffic/
mod.rs1mod bots;
2mod devices;
3mod geo;
4mod sources;
5
6use anyhow::Result;
7use clap::Subcommand;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use systemprompt_runtime::DatabaseContext;
11
12use crate::shared::render_result;
13use crate::CliConfig;
14
15#[derive(Debug, Subcommand)]
16pub enum TrafficCommands {
17 #[command(about = "Traffic source breakdown")]
18 Sources(sources::SourcesArgs),
19
20 #[command(about = "Geographic distribution")]
21 Geo(geo::GeoArgs),
22
23 #[command(about = "Device and browser breakdown")]
24 Devices(devices::DevicesArgs),
25
26 #[command(about = "Bot traffic analysis")]
27 Bots(bots::BotsArgs),
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
31pub struct TrafficSourceRow {
32 pub source: String,
33 pub session_count: i64,
34 pub percentage: f64,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
38pub struct TrafficSourcesOutput {
39 pub period: String,
40 pub sources: Vec<TrafficSourceRow>,
41 pub total_sessions: i64,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
45pub struct GeoRow {
46 pub country: String,
47 pub session_count: i64,
48 pub percentage: f64,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct GeoOutput {
53 pub period: String,
54 pub countries: Vec<GeoRow>,
55 pub total_sessions: i64,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct DeviceRow {
60 pub device_type: String,
61 pub browser: String,
62 pub session_count: i64,
63 pub percentage: f64,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
67pub struct DevicesOutput {
68 pub period: String,
69 pub devices: Vec<DeviceRow>,
70 pub total_sessions: i64,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
74pub struct BotRow {
75 pub bot_type: String,
76 pub request_count: i64,
77 pub percentage: f64,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
81pub struct BotsOutput {
82 pub period: String,
83 pub human_sessions: i64,
84 pub bot_sessions: i64,
85 pub bot_percentage: f64,
86 pub bot_breakdown: Vec<BotRow>,
87}
88
89pub async fn execute(command: TrafficCommands, config: &CliConfig) -> Result<()> {
90 match command {
91 TrafficCommands::Sources(args) => {
92 let result = sources::execute(args, config).await?;
93 render_result(&result);
94 Ok(())
95 },
96 TrafficCommands::Geo(args) => {
97 let result = geo::execute(args, config).await?;
98 render_result(&result);
99 Ok(())
100 },
101 TrafficCommands::Devices(args) => {
102 let result = devices::execute(args, config).await?;
103 render_result(&result);
104 Ok(())
105 },
106 TrafficCommands::Bots(args) => {
107 let result = bots::execute(args, config).await?;
108 render_result(&result);
109 Ok(())
110 },
111 }
112}
113
114pub async fn execute_with_pool(
115 command: TrafficCommands,
116 db_ctx: &DatabaseContext,
117 config: &CliConfig,
118) -> Result<()> {
119 match command {
120 TrafficCommands::Sources(args) => {
121 let result = sources::execute_with_pool(args, db_ctx, config).await?;
122 render_result(&result);
123 Ok(())
124 },
125 TrafficCommands::Geo(args) => {
126 let result = geo::execute_with_pool(args, db_ctx, config).await?;
127 render_result(&result);
128 Ok(())
129 },
130 TrafficCommands::Devices(args) => {
131 let result = devices::execute_with_pool(args, db_ctx, config).await?;
132 render_result(&result);
133 Ok(())
134 },
135 TrafficCommands::Bots(args) => {
136 let result = bots::execute_with_pool(args, db_ctx, config).await?;
137 render_result(&result);
138 Ok(())
139 },
140 }
141}