Mountain/ApplicationState/State/FeatureState/Terminals/
TerminalState.rs

1//! # TerminalState Module (ApplicationState)
2//!
3//! ## RESPONSIBILITIES
4//! Manages terminal instances state including terminal metadata, content, and
5//! unique identifier tracking.
6//!
7//! ## ARCHITECTURAL ROLE
8//! TerminalState is part of the **FeatureState** module, representing
9//! terminal instances state organized by terminal ID.
10//!
11//! ## KEY COMPONENTS
12//! - TerminalState: Main struct containing active terminals map and counter
13//! - Default: Initialization implementation
14//! - Helper methods: Terminal manipulation utilities
15//!
16//! ## ERROR HANDLING
17//! - Thread-safe access via `Arc<Mutex<...>>`
18//! - Proper lock error handling with `MapLockError` helpers
19//!
20//! ## LOGGING
21//! State changes are logged at appropriate levels (debug, info, warn, error).
22//!
23//! ## PERFORMANCE CONSIDERATIONS
24//! - Lock mutexes briefly and release immediately
25//! - Avoid nested locks to prevent deadlocks
26//! - Use Arc for shared ownership across threads
27//! - Use double mutex for terminals (outer for map, inner for each terminal)
28//!
29//! ## TODO
30//! - [ ] Add terminal validation invariants
31//! - [ ] Implement terminal lifecycle events
32//! - [ ] Add terminal metrics collection
33
34use std::{
35	collections::HashMap,
36	sync::{
37		Arc,
38		Mutex as StandardMutex,
39		atomic::{AtomicU64, Ordering as AtomicOrdering},
40	},
41};
42
43use log::debug;
44
45use crate::ApplicationState::DTO::TerminalStateDTO::TerminalStateDTO;
46
47/// Active terminals state containing terminals by ID with next identifier
48/// counter.
49#[derive(Clone)]
50pub struct TerminalState {
51	/// Active terminals organized by ID.
52	pub ActiveTerminals:Arc<StandardMutex<HashMap<u64, Arc<StandardMutex<TerminalStateDTO>>>>>,
53
54	/// Counter for generating unique terminal identifiers.
55	pub NextTerminalIdentifier:Arc<AtomicU64>,
56}
57
58impl Default for TerminalState {
59	fn default() -> Self {
60		debug!("[TerminalState] Initializing default terminal state...");
61
62		Self {
63			ActiveTerminals:Arc::new(StandardMutex::new(HashMap::new())),
64			NextTerminalIdentifier:Arc::new(AtomicU64::new(1)),
65		}
66	}
67}
68
69impl TerminalState {
70	/// Gets the next available unique identifier for a terminal instance.
71	pub fn GetNextTerminalIdentifier(&self) -> u64 { self.NextTerminalIdentifier.fetch_add(1, AtomicOrdering::Relaxed) }
72
73	/// Gets all active terminals.
74	pub fn GetAll(&self) -> HashMap<u64, TerminalStateDTO> {
75		self.ActiveTerminals
76			.lock()
77			.ok()
78			.map(|guard| {
79				guard
80					.iter()
81					.filter_map(|(id, arc)| arc.lock().ok().map(|dto| (*id, dto.clone())))
82					.collect()
83			})
84			.unwrap_or_default()
85	}
86
87	/// Gets a terminal by its ID.
88	pub fn Get(&self, id:u64) -> Option<TerminalStateDTO> {
89		self.ActiveTerminals
90			.lock()
91			.ok()
92			.and_then(|guard| guard.get(&id).and_then(|arc| arc.lock().ok().map(|dto| dto.clone())))
93	}
94
95	/// Gets a terminal's Arc<Mutex<>> by its ID for direct manipulation.
96	pub fn GetArc(&self, id:u64) -> Option<Arc<StandardMutex<TerminalStateDTO>>> {
97		self.ActiveTerminals.lock().ok().and_then(|guard| guard.get(&id).cloned())
98	}
99
100	/// Adds or updates a terminal.
101	pub fn AddOrUpdate(&self, id:u64, terminal:TerminalStateDTO) {
102		if let Ok(mut guard) = self.ActiveTerminals.lock() {
103			guard.insert(id, Arc::new(StandardMutex::new(terminal)));
104			debug!("[TerminalState] Terminal added/updated with ID: {}", id);
105		}
106	}
107
108	/// Removes a terminal by its ID.
109	pub fn Remove(&self, id:u64) {
110		if let Ok(mut guard) = self.ActiveTerminals.lock() {
111			guard.remove(&id);
112			debug!("[TerminalState] Terminal removed with ID: {}", id);
113		}
114	}
115
116	/// Clears all active terminals.
117	pub fn Clear(&self) {
118		if let Ok(mut guard) = self.ActiveTerminals.lock() {
119			guard.clear();
120			debug!("[TerminalState] All terminals cleared");
121		}
122	}
123
124	/// Gets the count of active terminals.
125	pub fn Count(&self) -> usize { self.ActiveTerminals.lock().ok().map(|guard| guard.len()).unwrap_or(0) }
126
127	/// Checks if a terminal exists.
128	pub fn Contains(&self, id:u64) -> bool {
129		self.ActiveTerminals
130			.lock()
131			.ok()
132			.map(|guard| guard.contains_key(&id))
133			.unwrap_or(false)
134	}
135}