1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex};
8use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
9
10const DEVELOPMENT_THRESHOLD: f64 = 0.60;
12const PRODUCTION_THRESHOLD: f64 = 0.90;
13const RELEASE_THRESHOLD: f64 = 0.99;
14
15#[derive(Debug, Clone, Copy, PartialEq)]
17pub enum SystemStage {
18 Development,
19 Production,
20 Release,
21 Unavailable,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ComponentStatus {
27 pub name: String,
29 pub status: f64,
31 pub last_check: u64,
33 pub metrics: HashMap<String, f64>,
35 pub issues: Vec<String>,
37}
38
39impl ComponentStatus {
40 pub fn new(
42 name: String,
43 status: f64,
44 metrics: HashMap<String, f64>,
45 issues: Vec<String>,
46 ) -> Self {
47 Self {
48 name,
49 status,
50 last_check: chrono::Utc::now().timestamp() as u64,
51 metrics,
52 issues,
53 }
54 }
55}
56
57#[derive(Debug, Clone)]
59pub struct SystemHealth {
60 overall_status: f64,
61 stage: SystemStage,
62 components: HashMap<String, ComponentStatus>,
63 last_update: Instant,
64}
65
66pub struct AgentChecker {
68 health: Arc<Mutex<SystemHealth>>,
69 input_buffer: Arc<Mutex<Vec<String>>>,
70 input_counter: Arc<Mutex<usize>>,
71 auto_save_frequency: usize,
72 last_save: Arc<Mutex<Instant>>,
73}
74
75impl AgentChecker {
76 pub fn new(auto_save_frequency: usize) -> Self {
78 let health = SystemHealth {
79 overall_status: 0.0,
80 stage: SystemStage::Unavailable,
81 components: HashMap::new(),
82 last_update: Instant::now(),
83 };
84
85 Self {
86 health: Arc::new(Mutex::new(health)),
87 input_buffer: Arc::new(Mutex::new(Vec::new())),
88 input_counter: Arc::new(Mutex::new(0)),
89 auto_save_frequency,
90 last_save: Arc::new(Mutex::new(Instant::now())),
91 }
92 }
93
94 pub fn process_input(&self, input: &str) -> Result<(), String> {
96 {
98 let mut buffer = match self.input_buffer.lock() {
99 Ok(guard) => guard,
100 Err(e) => return Err(format!("Failed to lock input buffer: {e}")),
101 };
102 buffer.push(input.to_string());
103 }
104
105 let should_save = {
107 let mut counter = match self.input_counter.lock() {
108 Ok(guard) => guard,
109 Err(e) => return Err(format!("Failed to lock input counter: {e}")),
110 };
111 *counter += 1;
112 *counter % self.auto_save_frequency == 0
113 };
114
115 if should_save {
117 self.save_state_to_memory();
118 println!("Auto-saved state after processing input");
119 }
120
121 self.analyze_input(input)
123 }
124
125 fn save_state_to_memory(&self) {
127 match self.last_save.lock() {
129 Ok(mut last_save) => {
130 *last_save = Instant::now();
131 }
132 Err(e) => {
133 log::error!("Failed to update last save time: {e}");
134 }
135 }
136 }
137
138 fn analyze_input(&self, input: &str) -> Result<(), String> {
140 let mut health = match self.health.lock() {
142 Ok(guard) => guard,
143 Err(e) => return Err(format!("Failed to acquire health lock: {e}")),
144 };
145
146 if input.contains("error") {
149 health.overall_status = (health.overall_status - 0.05).max(0.0);
150 } else if input.contains("success") {
151 health.overall_status = (health.overall_status + 0.03).min(1.0);
152 }
153
154 health.stage = if health.overall_status >= RELEASE_THRESHOLD {
156 SystemStage::Release
157 } else if health.overall_status >= PRODUCTION_THRESHOLD {
158 SystemStage::Production
159 } else if health.overall_status >= DEVELOPMENT_THRESHOLD {
160 SystemStage::Development
161 } else {
162 SystemStage::Unavailable
163 };
164
165 health.last_update = Instant::now();
166 Ok(())
167 }
168
169 pub fn get_system_stage(&self) -> SystemStage {
171 match self.health.lock() {
172 Ok(health) => health.stage,
173 Err(_) => SystemStage::Unavailable,
174 }
175 }
176
177 pub fn get_system_health(&self) -> SystemHealth {
179 match self.health.lock() {
180 Ok(health) => health.clone(),
181 Err(_) => SystemHealth {
182 stage: SystemStage::Unavailable,
183 components: HashMap::new(),
184 overall_status: 0.0,
185 last_update: Instant::now(),
186 },
187 }
188 }
189
190 pub fn check_component_status(&self, component_name: &str) -> Option<ComponentStatus> {
192 match self.health.lock() {
193 Ok(health) => health.components.get(component_name).cloned(),
194 Err(_) => None,
195 }
196 }
197
198 pub fn update_component_status(
200 &self,
201 component_name: &str,
202 status: f64,
203 metrics: HashMap<String, f64>,
204 issues: Vec<String>,
205 ) {
206 let mut health = match self.health.lock() {
207 Ok(health) => health,
208 Err(e) => {
209 log::error!("Failed to acquire health lock: {e}");
210 return;
211 }
212 };
213
214 let component = ComponentStatus {
215 name: component_name.to_string(),
216 status,
217 last_check: SystemTime::now()
218 .duration_since(UNIX_EPOCH)
219 .unwrap_or(Duration::ZERO)
220 .as_secs(),
221 metrics,
222 issues,
223 };
224
225 health
226 .components
227 .insert(component_name.to_string(), component);
228
229 let component_count = health.components.len() as f64;
231 let total_status: f64 = health.components.values().map(|c| c.status).sum();
232
233 if component_count > 0.0 {
234 health.overall_status = total_status / component_count;
235
236 health.stage = if health.overall_status >= RELEASE_THRESHOLD {
238 SystemStage::Release
239 } else if health.overall_status >= PRODUCTION_THRESHOLD {
240 SystemStage::Production
241 } else if health.overall_status >= DEVELOPMENT_THRESHOLD {
242 SystemStage::Development
243 } else {
244 SystemStage::Unavailable
245 };
246 }
247 }
248
249 pub fn validate_system_readiness(&self) -> (bool, SystemStage, Vec<String>) {
251 let health = match self.health.lock() {
252 Ok(health) => health,
253 Err(e) => {
254 log::error!("Failed to acquire health lock: {e}");
255 return (
256 false,
257 SystemStage::Unavailable,
258 vec![format!("Failed to acquire health lock: {}", e)],
259 );
260 }
261 };
262
263 let stage = health.stage;
264 let mut issues = Vec::new();
265
266 for (name, component) in &health.components {
267 if component.status < DEVELOPMENT_THRESHOLD {
268 issues.push(format!(
269 "Component {} is below minimum threshold: {:.2}",
270 name, component.status
271 ));
272 }
273 }
274
275 let is_ready = match stage {
276 SystemStage::Development => health.overall_status >= DEVELOPMENT_THRESHOLD,
277 SystemStage::Production => health.overall_status >= PRODUCTION_THRESHOLD,
278 SystemStage::Release => health.overall_status >= RELEASE_THRESHOLD,
279 SystemStage::Unavailable => false,
280 };
281
282 (is_ready, stage, issues)
283 }
284
285 pub fn get_input_stats(&self) -> (usize, usize, Duration) {
287 let buffer = match self.input_buffer.lock() {
288 Ok(guard) => guard,
289 Err(_) => return (0, 0, Duration::from_secs(0)),
290 };
291
292 let counter = match self.input_counter.lock() {
293 Ok(guard) => *guard,
294 Err(_) => return (buffer.len(), 0, Duration::from_secs(0)),
295 };
296
297 let last_save = match self.last_save.lock() {
298 Ok(guard) => guard.elapsed(),
299 Err(_) => Duration::from_secs(0),
300 };
301
302 (buffer.len(), counter, last_save)
303 }
304}
305
306#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn test_input_processing_with_auto_save() -> Result<(), Box<dyn std::error::Error>> {
313 let checker = AgentChecker::new(20); for i in 0..25 {
317 let input = if i % 5 == 0 {
318 format!("success message {i}")
319 } else {
320 format!("normal message {i}")
321 };
322
323 checker
324 .process_input(&input)
325 .map_err(|e| format!("Failed to process input: {e}"))?;
326 }
327
328 let (buffer_size, counter, _) = checker.get_input_stats();
330 assert_eq!(buffer_size, 25);
331 assert_eq!(counter, 25);
332
333 let health = checker.get_system_health();
335 assert!(health.overall_status > 0.0);
336
337 Ok(())
338 }
339
340 #[test]
341 fn test_system_stage_transitions() -> Result<(), Box<dyn std::error::Error>> {
342 let checker = AgentChecker::new(10);
343
344 assert_eq!(checker.get_system_stage(), SystemStage::Unavailable);
346
347 let mut metrics = HashMap::new();
349 metrics.insert("memory".to_string(), 0.70);
350 metrics.insert("cpu".to_string(), 0.65);
351
352 checker.update_component_status("core", 0.62, metrics, vec![]);
353
354 assert_eq!(checker.get_system_stage(), SystemStage::Development);
356
357 Ok(())
358 }
359}