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