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