1use std::time::{Duration, Instant};
2
3use chrono::Local;
4use colored::Colorize;
5use sysinfo::{Pid, System};
6
7pub struct StatsCollector {
9 pub start_time: Instant,
10 pub file_changes: usize,
11 pub watcher_calls: usize,
12 pub last_memory_usage: u64,
13 pub last_cpu_usage: f32,
14 system: System,
15}
16
17impl Default for StatsCollector {
18 fn default() -> Self {
19 Self::new()
20 }
21}
22
23impl StatsCollector {
24 pub fn new() -> Self {
25 Self {
26 start_time: Instant::now(),
27 file_changes: 0,
28 watcher_calls: 0,
29 last_memory_usage: 0,
30 last_cpu_usage: 0.0,
31 system: System::new_all(),
32 }
33 }
34
35 pub fn record_file_change(&mut self) {
36 self.file_changes += 1;
37 }
38
39 pub fn record_watcher_call(&mut self) {
40 self.watcher_calls += 1;
41 }
42
43 pub fn update_resource_usage(&mut self) {
44 self.system.refresh_all();
45
46 let pid = std::process::id();
47 if let Some(process) = self.system.process(Pid::from_u32(pid)) {
48 self.last_memory_usage = process.memory() / 1024; self.last_cpu_usage = process.cpu_usage();
50 }
51 }
52
53 pub fn display_stats(&self) {
54 let elapsed = self.start_time.elapsed();
55 let timestamp = Local::now().format("%H:%M:%S").to_string();
56
57 println!("{}", "── Flash Performance Stats ──".bright_green());
58 println!("{} {}", "Time:".bright_blue(), timestamp);
59 println!("{} {}", "Uptime:".bright_blue(), format_duration(elapsed));
60 println!("{} {}", "File changes:".bright_blue(), self.file_changes);
61 println!("{} {}", "Watcher calls:".bright_blue(), self.watcher_calls);
62 println!(
63 "{} {} KB",
64 "Memory usage:".bright_blue(),
65 self.last_memory_usage
66 );
67 println!("{} {:.1}%", "CPU usage:".bright_blue(), self.last_cpu_usage);
68 println!("{}", "────────────────────────────".bright_green());
69 }
70}
71
72pub fn format_duration(duration: Duration) -> String {
73 let seconds = duration.as_secs();
74 if seconds < 60 {
75 format!("{}s", seconds)
76 } else if seconds < 3600 {
77 format!("{}m {}s", seconds / 60, seconds % 60)
78 } else {
79 format!(
80 "{}h {}m {}s",
81 seconds / 3600,
82 (seconds % 3600) / 60,
83 seconds % 60
84 )
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use std::time::Duration;
92
93 #[test]
94 fn test_stats_collector_new() {
95 let stats = StatsCollector::new();
96 assert_eq!(stats.file_changes, 0);
97 assert_eq!(stats.watcher_calls, 0);
98 assert_eq!(stats.last_memory_usage, 0);
99 assert_eq!(stats.last_cpu_usage, 0.0);
100 }
101
102 #[test]
103 fn test_record_file_change() {
104 let mut stats = StatsCollector::new();
105 assert_eq!(stats.file_changes, 0);
106
107 stats.record_file_change();
108 assert_eq!(stats.file_changes, 1);
109
110 stats.record_file_change();
111 assert_eq!(stats.file_changes, 2);
112 }
113
114 #[test]
115 fn test_record_watcher_call() {
116 let mut stats = StatsCollector::new();
117 assert_eq!(stats.watcher_calls, 0);
118
119 stats.record_watcher_call();
120 assert_eq!(stats.watcher_calls, 1);
121
122 stats.record_watcher_call();
123 assert_eq!(stats.watcher_calls, 2);
124 }
125
126 #[test]
127 fn test_format_duration_seconds() {
128 assert_eq!(format_duration(Duration::from_secs(0)), "0s");
129 assert_eq!(format_duration(Duration::from_secs(30)), "30s");
130 assert_eq!(format_duration(Duration::from_secs(59)), "59s");
131 }
132
133 #[test]
134 fn test_format_duration_minutes() {
135 assert_eq!(format_duration(Duration::from_secs(60)), "1m 0s");
136 assert_eq!(format_duration(Duration::from_secs(90)), "1m 30s");
137 assert_eq!(format_duration(Duration::from_secs(3599)), "59m 59s");
138 }
139
140 #[test]
141 fn test_format_duration_hours() {
142 assert_eq!(format_duration(Duration::from_secs(3600)), "1h 0m 0s");
143 assert_eq!(format_duration(Duration::from_secs(3661)), "1h 1m 1s");
144 assert_eq!(format_duration(Duration::from_secs(7323)), "2h 2m 3s");
145 }
146
147 #[test]
148 fn test_update_resource_usage() {
149 let mut stats = StatsCollector::new();
150 stats.update_resource_usage();
153 }
156}