use anyhow::Result;
use clap::Args;
use crate::config::load_config;
use crate::metrics::storage::MetricsStorage;
#[derive(Args)]
pub struct MetricsArgs {
#[arg(short, long)]
pub live: bool,
#[arg(short, long)]
pub json: bool,
#[arg(short, long, default_value = "1")]
pub interval: u64,
}
pub fn execute(args: &MetricsArgs) -> Result<()> {
let config = load_config()?;
let data_dir = match config.role() {
crate::config::Role::Client => {
dirs::config_dir()
.unwrap_or_else(|| std::path::PathBuf::from("."))
.join("porta")
.to_string_lossy()
.to_string()
}
crate::config::Role::Server => "/var/lib/porta".to_string(),
};
let storage = MetricsStorage::new(&data_dir);
let snapshots = storage.load()?;
println!("\n\x1b[1;36m╔══════════════════════════════════════════════════════════════╗\x1b[0m");
println!("\x1b[1;36m║ PORTA METRICS (v{}) ║\x1b[0m", env!("CARGO_PKG_VERSION"));
println!("\x1b[1;36m╚══════════════════════════════════════════════════════════════╝\x1b[0m\n");
println!(" \x1b[1;33mRole:\x1b[0m {:?}", config.role());
println!(" \x1b[1;33mInterface:\x1b[0m {}", config.interface());
match config.role() {
crate::config::Role::Client => {
println!(" \x1b[1;33mServer:\x1b[0m {}:{}", config.server_address(), config.server_port());
println!(" \x1b[1;33mPorts:\x1b[0m {}", config.ports().len());
}
crate::config::Role::Server => {
println!(" \x1b[1;33mListen:\x1b[0m port {}", config.listen_port());
}
}
println!();
if args.live {
println!(" \x1b[1;36mLive mode not yet implemented. Use: journalctl -u porta -f\x1b[0m\n");
}
if let Some(latest) = snapshots.last() {
if args.json {
println!("{}", serde_json::to_string_pretty(latest)?);
} else {
println!(" \x1b[1;33mLast Metrics:\x1b[0m");
println!(" Updated: {}", latest.timestamp.format("%Y-%m-%d %H:%M:%S UTC"));
println!(" Bytes sent: {}", format_bytes(latest.bytes_sent));
println!(" Bytes recv: {}", format_bytes(latest.bytes_received));
println!(" Packets sent: {}", latest.packets_sent);
println!(" Packets recv: {}", latest.packets_received);
println!(" Connections: {}", latest.active_connections);
if let Some(latency) = latest.latency_ms {
println!(" Latency: {:.2} ms", latency);
}
println!(" Data points: {}", snapshots.len());
}
} else {
println!(" \x1b[1;33mNo metrics data yet.\x1b[0m");
println!(" Metrics will appear after the service runs for a while.");
}
println!();
Ok(())
}
fn format_bytes(bytes: u64) -> String {
const KB: u64 = 1024;
const MB: u64 = 1024 * KB;
const GB: u64 = 1024 * MB;
if bytes >= GB {
format!("{:.2} GB", bytes as f64 / GB as f64)
} else if bytes >= MB {
format!("{:.2} MB", bytes as f64 / MB as f64)
} else if bytes >= KB {
format!("{:.2} KB", bytes as f64 / KB as f64)
} else {
format!("{} B", bytes)
}
}