176 lines
5.7 KiB
Rust
176 lines
5.7 KiB
Rust
//! Etat partage thread-safe de l'agent.
|
|
//!
|
|
//! Centralise l'etat courant (enregistrement, replay, connexion, etc.)
|
|
//! accessible depuis tous les threads (systray, heartbeat, replay, recorder).
|
|
//! Equivalent de agent_v1/ui/shared_state.py.
|
|
|
|
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
/// Etats possibles de l'icone systray
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum TrayState {
|
|
/// Gris — en attente, pas de session active
|
|
Idle,
|
|
/// Rouge — enregistrement en cours
|
|
Recording,
|
|
/// Vert — connecte au serveur, pret
|
|
Connected,
|
|
/// Bleu — replay en cours
|
|
Replay,
|
|
}
|
|
|
|
/// Etat partage de l'agent, thread-safe via Arc + atomics.
|
|
///
|
|
/// Les booleens utilisent AtomicBool pour un acces lock-free.
|
|
/// Le nom de session utilise un Mutex car c'est une String.
|
|
#[derive(Debug)]
|
|
pub struct AgentState {
|
|
/// Enregistrement en cours (session de capture)
|
|
pub recording: AtomicBool,
|
|
|
|
/// Nom de la session d'enregistrement courante
|
|
pub recording_name: Mutex<String>,
|
|
|
|
/// Replay en cours (execution d'actions)
|
|
pub replay_active: AtomicBool,
|
|
|
|
/// Connecte au serveur streaming
|
|
pub connected: AtomicBool,
|
|
|
|
/// Nombre d'actions capturees dans la session courante
|
|
pub actions_count: AtomicU32,
|
|
|
|
/// L'agent est en cours d'execution (false = arret demande)
|
|
pub running: AtomicBool,
|
|
|
|
/// Fenetre de chat visible
|
|
pub chat_visible: AtomicBool,
|
|
|
|
/// Arret d'urgence active
|
|
pub emergency_stop: AtomicBool,
|
|
|
|
/// Dernier message de notification (pour eviter les doublons)
|
|
#[allow(dead_code)]
|
|
pub last_notification: Mutex<String>,
|
|
}
|
|
|
|
impl AgentState {
|
|
/// Cree un nouvel etat avec les valeurs par defaut.
|
|
pub fn new() -> Arc<Self> {
|
|
Arc::new(Self {
|
|
recording: AtomicBool::new(false),
|
|
recording_name: Mutex::new(String::new()),
|
|
replay_active: AtomicBool::new(false),
|
|
connected: AtomicBool::new(false),
|
|
actions_count: AtomicU32::new(0),
|
|
running: AtomicBool::new(true),
|
|
chat_visible: AtomicBool::new(false),
|
|
emergency_stop: AtomicBool::new(false),
|
|
last_notification: Mutex::new(String::new()),
|
|
})
|
|
}
|
|
|
|
/// Demarre un enregistrement avec le nom donne.
|
|
pub fn start_recording(&self, name: &str) {
|
|
self.recording.store(true, Ordering::SeqCst);
|
|
self.actions_count.store(0, Ordering::SeqCst);
|
|
if let Ok(mut n) = self.recording_name.lock() {
|
|
*n = name.to_string();
|
|
}
|
|
println!("[STATE] Enregistrement demarre : '{}'", name);
|
|
}
|
|
|
|
/// Arrete l'enregistrement en cours.
|
|
pub fn stop_recording(&self) -> (String, u32) {
|
|
self.recording.store(false, Ordering::SeqCst);
|
|
let count = self.actions_count.load(Ordering::SeqCst);
|
|
let name = self
|
|
.recording_name
|
|
.lock()
|
|
.map(|n| n.clone())
|
|
.unwrap_or_default();
|
|
println!("[STATE] Enregistrement arrete : '{}' ({} actions)", name, count);
|
|
(name, count)
|
|
}
|
|
|
|
/// Incremente le compteur d'actions capturees.
|
|
pub fn increment_actions(&self) -> u32 {
|
|
self.actions_count.fetch_add(1, Ordering::SeqCst) + 1
|
|
}
|
|
|
|
/// Verifie si l'agent est en cours d'execution.
|
|
pub fn is_running(&self) -> bool {
|
|
self.running.load(Ordering::SeqCst)
|
|
}
|
|
|
|
/// Demande l'arret de l'agent.
|
|
pub fn request_shutdown(&self) {
|
|
self.running.store(false, Ordering::SeqCst);
|
|
println!("[STATE] Arret demande");
|
|
}
|
|
|
|
/// Active/desactive le replay.
|
|
pub fn set_replay_active(&self, active: bool) {
|
|
self.replay_active.store(active, Ordering::SeqCst);
|
|
}
|
|
|
|
/// Met a jour le statut de connexion au serveur.
|
|
pub fn set_connected(&self, connected: bool) {
|
|
let was_connected = self.connected.swap(connected, Ordering::SeqCst);
|
|
if was_connected != connected {
|
|
println!(
|
|
"[STATE] Connexion serveur : {}",
|
|
if connected { "CONNECTE" } else { "DECONNECTE" }
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Active l'arret d'urgence — stoppe tout immediatement.
|
|
pub fn emergency_stop(&self) {
|
|
self.emergency_stop.store(true, Ordering::SeqCst);
|
|
self.recording.store(false, Ordering::SeqCst);
|
|
self.replay_active.store(false, Ordering::SeqCst);
|
|
println!("[STATE] === ARRET D'URGENCE ACTIVE ===");
|
|
}
|
|
|
|
/// Retourne l'etat courant du systray.
|
|
pub fn tray_state(&self) -> TrayState {
|
|
if self.recording.load(Ordering::SeqCst) {
|
|
TrayState::Recording
|
|
} else if self.replay_active.load(Ordering::SeqCst) {
|
|
TrayState::Replay
|
|
} else if self.connected.load(Ordering::SeqCst) {
|
|
TrayState::Connected
|
|
} else {
|
|
TrayState::Idle
|
|
}
|
|
}
|
|
|
|
/// Retourne le nom de la session d'enregistrement courante.
|
|
pub fn current_recording_name(&self) -> String {
|
|
self.recording_name
|
|
.lock()
|
|
.map(|n| n.clone())
|
|
.unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
impl Default for AgentState {
|
|
fn default() -> Self {
|
|
// Note: on ne peut pas retourner Arc<Self> depuis Default,
|
|
// donc on fournit les valeurs brutes. Utiliser new() de preference.
|
|
Self {
|
|
recording: AtomicBool::new(false),
|
|
recording_name: Mutex::new(String::new()),
|
|
replay_active: AtomicBool::new(false),
|
|
connected: AtomicBool::new(false),
|
|
actions_count: AtomicU32::new(0),
|
|
running: AtomicBool::new(true),
|
|
chat_visible: AtomicBool::new(false),
|
|
emergency_stop: AtomicBool::new(false),
|
|
last_notification: Mutex::new(String::new()),
|
|
}
|
|
}
|
|
}
|