memory_monitor/
monitor.rs1use chrono::Local;
8use crossterm::{
9 cursor,
10 terminal::{self, Clear, ClearType},
11 ExecutableCommand,
12};
13use sysinfo::{System, SystemExt};
14use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
15use std::thread;
16use std::time::Duration;
17
18use crate::config::MonitorConfig;
19use crate::notification::GntpNotifier;
20use crate::cleaner::MemoryCleaner;
21
22pub struct MemoryMonitor {
23 pub config: MonitorConfig,
24 pub notifier: Option<GntpNotifier>,
25 cleaner: MemoryCleaner,
26 system: System,
27}
28
29impl MemoryMonitor {
30 pub fn new() -> Self {
31 let config = MonitorConfig::load("config.ini");
32 let notifier = GntpNotifier::new(
33 &config.growl_host,
34 config.growl_port,
35 &config.growl_password,
36 &config.growl_app_name,
37 &config.icon_path,
38 );
39 let cleaner = MemoryCleaner::new(&config.cleanmem_path);
40
41 MemoryMonitor {
42 config,
43 notifier,
44 cleaner,
45 system: System::new_all(),
46 }
47 }
48
49 #[allow(dead_code)]
50 pub fn with_config(config: MonitorConfig) -> Self {
51 let notifier = GntpNotifier::new(
52 &config.growl_host,
53 config.growl_port,
54 &config.growl_password,
55 &config.growl_app_name,
56 &config.icon_path,
57 );
58 let cleaner = MemoryCleaner::new(&config.cleanmem_path);
59
60 MemoryMonitor {
61 config,
62 notifier,
63 cleaner,
64 system: System::new_all(),
65 }
66 }
67
68 pub fn get_memory_usage(&mut self) -> f64 {
69 self.system.refresh_memory();
70 let total = self.system.total_memory() as f64;
71 let used = self.system.used_memory() as f64;
72 (used / total) * 100.0
73 }
74
75 pub fn threshold(&self) -> f64 {
76 self.config.threshold
77 }
78
79 pub fn check_interval(&self) -> u64 {
80 self.config.check_interval
81 }
82
83 pub fn cleanmem_path(&self) -> &str {
84 &self.config.cleanmem_path
85 }
86
87 pub fn growl_host(&self) -> &str {
88 &self.config.growl_host
89 }
90
91 pub fn growl_port(&self) -> u16 {
92 self.config.growl_port
93 }
94
95 pub fn growl_app_name(&self) -> &str {
96 &self.config.growl_app_name
97 }
98
99 pub fn has_notifier(&self) -> bool {
100 self.notifier.is_some()
101 }
102
103 fn display_status(&self, memory_percent: f64) {
104 let mut stdout = StandardStream::stdout(ColorChoice::Always);
105 let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S");
106
107 let (color, emoji, status) = if memory_percent >= self.config.threshold {
108 (Color::Red, "๐ด", "CRITICAL")
109 } else if memory_percent >= self.config.threshold - 5.0 {
110 (Color::Yellow, "๐ก", "WARNING")
111 } else {
112 (Color::Green, "๐ข", "OK")
113 };
114
115 stdout.execute(Clear(ClearType::All)).ok();
116 stdout.execute(cursor::MoveTo(0, 0)).ok();
117
118 let width = terminal::size().map(|(w, _)| w as usize).unwrap_or(80);
119
120 stdout.set_color(ColorSpec::new().set_fg(Some(Color::Magenta)).set_bold(true)).ok();
121 println!("{}", "=".repeat(width));
122 println!(" ๐ Memory Monitor & Auto-Cleaner");
123 println!("{}", "=".repeat(width));
124 stdout.reset().ok();
125
126 stdout.set_color(ColorSpec::new().set_fg(Some(color)).set_bold(true)).ok();
127 println!("\n{} Memory Status: {}", emoji, status);
128 stdout.reset().ok();
129
130 println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
131
132 stdout.set_color(ColorSpec::new().set_fg(Some(color))).ok();
133 println!("๐ Usage: {:.2}%", memory_percent);
134 stdout.reset().ok();
135
136 println!("๐ฏ Threshold: {}%", self.config.threshold);
137 println!("โฐ Interval : {} {}", self.config.check_interval,
138 if self.config.check_interval < 10 { "second" } else { "seconds" });
139 println!("โฐ Time: {}", timestamp);
140 }
141
142 pub fn monitor(&mut self) {
143 let mut stdout = StandardStream::stdout(ColorChoice::Always);
144 let width = terminal::size().map(|(w, _)| w as usize).unwrap_or(80);
145
146 stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true)).ok();
147 println!("{}", "โ".repeat(width));
148 println!("๐ Memory Monitor Started");
149 println!("Threshold: {}% | Interval: {}s", self.config.threshold, self.config.check_interval);
150 println!("{}", "โ".repeat(width));
151 stdout.reset().ok();
152
153 loop {
154 let memory_percent = self.get_memory_usage();
155 self.display_status(memory_percent);
156
157 if memory_percent >= self.config.threshold {
158 stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true)).ok();
159 println!("\nโ ๏ธ ALERT: Memory usage at {:.2}%!\n", memory_percent);
160 stdout.reset().ok();
161
162 let success = self.cleaner.clean();
163
164 if let Some(ref notifier) = self.notifier {
165 if success {
166 notifier.notify(
167 "๐งน Memory Cleaned",
168 &format!("Memory was at {:.2}%. CleanMem executed successfully.", memory_percent),
169 0,
170 );
171 } else {
172 notifier.notify(
173 "๐ด Memory Critical",
174 &format!("Memory at {:.2}%. CleanMem execution failed!", memory_percent),
175 2,
176 );
177 }
178 }
179
180 thread::sleep(Duration::from_secs(30));
181
182 let new_memory = self.get_memory_usage();
183 stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))).ok();
184 println!("๐ Memory after cleanup: {:.2}%\n", new_memory);
185 stdout.reset().ok();
186 }
187
188 thread::sleep(Duration::from_secs(self.config.check_interval));
189 }
190 }
191}