feat: agent Rust complet — systray, chat, enregistrement, floutage (2.4 MB)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
175
agent_rust/src/state.rs
Normal file
175
agent_rust/src/state.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
//! 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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user