Skip to main content

Mountain/ApplicationState/State/
ApplicationState.rs

1//! # ApplicationState Module (ApplicationState)
2//!
3//! ## RESPONSIBILITIES
4//! Central state management for the Mountain application, aggregating all
5//! state modules into a single source of truth.
6//!
7//! ## ARCHITECTURAL ROLE
8//! The ApplicationState is the **state container** that aggregates all
9//! domain-specific state modules and provides thread-safe access.
10//!
11//! ```text
12//! UI ──► Commands ──► ApplicationState (State) ──► Providers/Services
13//!                      │
14//!                      ↓
15//!                   Disk (Persistence)
16//! ```
17//!
18//! ### Design Principles:
19//! 1. **Single Source of Truth**: All state lives in one place
20//! 2. **Thread Safety**: All state is protected by Arc<Mutex<...>>
21//! 3. **Recovery-Oriented**: Comprehensive error handling and recovery
22//! 4. **Type Safety**: Strong typing at all levels
23//! 5. **Observability**: Comprehensive logging for state changes
24//!
25//! ## KEY COMPONENTS
26//! - Workspace: Workspace folders, trust, active document
27//! - Configuration: Configuration, memento storage
28//! - Extension: Extension registry, providers, scanned extensions
29//! - Feature: Diagnostics, documents, terminals, webviews, etc.
30//! - UI: Pending UI requests
31//!
32//! ## ERROR HANDLING
33//! All state operations use `Arc<Mutex<...>>` for thread-safety with proper
34//! error handling via `MapLockError` helpers.
35//!
36//! ## LOGGING
37//! State changes are logged at appropriate levels (debug, info, warn, error).
38//!
39//! ## PERFORMANCE CONSIDERATIONS
40//! - Lock mutexes briefly and release immediately
41//! - Avoid nested locks to prevent deadlocks
42//! - Use Arc for shared ownership across threads
43//!
44//! ## TODO
45//! - [ ] Add state validation invariants
46//! - [ ] Implement state metrics collection
47//! - [ ] Add state diffing for debugging
48
49use std::sync::{Arc, Mutex as StandardMutex, PoisonError};
50
51use CommonLibrary::Error::CommonError::CommonError;
52
53use super::{
54	ConfigurationState::ConfigurationState::State as ConfigurationState,
55	ExtensionState::State::State as ExtensionState,
56	FeatureState::State::State as FeatureState,
57	UIState::UIState::State as UIState,
58	WorkspaceState::WorkspaceState::State as WorkspaceState,
59};
60use crate::{Environment::TestProvider::TestProviderState::Struct as TestProviderState, dev_log};
61
62/// The central, shared, thread-safe state for the entire Mountain application.
63#[derive(Clone)]
64pub struct ApplicationState {
65	/// Workspace state containing workspace folders, trust, and active
66	/// document.
67	pub Workspace:WorkspaceState,
68
69	/// Configuration and storage state.
70	pub Configuration:ConfigurationState,
71
72	/// Extension management state.
73	pub Extension:ExtensionState,
74
75	/// Feature-specific state.
76	pub Feature:FeatureState,
77
78	/// User interface request state.
79	pub UI:UIState,
80
81	/// Test provider state.
82	pub TestProviderState:Arc<tokio::sync::RwLock<TestProviderState>>,
83
84	/// Memento storage paths.
85	pub GlobalMementoPath:Arc<StandardMutex<std::path::PathBuf>>,
86
87	pub WorkspaceMementoPath:Arc<StandardMutex<Option<std::path::PathBuf>>>,
88}
89
90impl Default for ApplicationState {
91	fn default() -> Self {
92		dev_log!("lifecycle", "[ApplicationState] Initializing default application state...");
93
94		Self {
95			Workspace:Default::default(),
96
97			Configuration:Default::default(),
98
99			Extension:Default::default(),
100
101			Feature:Default::default(),
102
103			UI:Default::default(),
104
105			TestProviderState:Arc::new(tokio::sync::RwLock::new(TestProviderState::new())),
106
107			GlobalMementoPath:Arc::new(StandardMutex::new(Default::default())),
108
109			WorkspaceMementoPath:Arc::new(StandardMutex::new(None)),
110		}
111	}
112}
113
114impl ApplicationState {
115	/// Gets the next available unique identifier for a provider registration.
116	pub fn GetNextProviderHandle(&self) -> u32 { self.Extension.GetNextProviderHandle() }
117
118	/// Gets the next available unique identifier for a terminal instance.
119	pub fn GetNextTerminalIdentifier(&self) -> u64 { self.Feature.GetNextTerminalIdentifier() }
120
121	/// Gets the next available unique identifier for an SCM provider.
122	pub fn GetNextSourceControlManagementProviderHandle(&self) -> u32 {
123		self.Feature.GetNextSourceControlManagementProviderHandle()
124	}
125
126	/// Gets the workspace identifier for the current application instance.
127	/// This is used to differentiate between different workspace instances
128	/// when running multiple instances of the application.
129	pub fn GetWorkspaceIdentifier(&self) -> Result<String, CommonError> {
130		// For now, generate a simple identifier based on the current timestamp
131		// In a proper implementation, this would be stored and persisted
132		use std::time::{SystemTime, UNIX_EPOCH};
133
134		let timestamp = SystemTime::now()
135			.duration_since(UNIX_EPOCH)
136			.map_err(|e| CommonError::Unknown { Description:format!("Failed to get system time: {}", e) })?;
137
138		Ok(format!("workspace-{:x}", timestamp.as_millis()))
139	}
140}
141
142/// A helper to map a mutex poison error into a CommonError.
143pub fn MapLockError<T>(Error:PoisonError<T>) -> CommonError {
144	CommonError::StateLockPoisoned { Context:Error.to_string() }
145}
146
147/// A helper to map a mutex poison error with recovery attempt.
148pub fn MapLockErrorWithRecovery<T>(Error:PoisonError<T>, RecoveryContext:&str) -> CommonError {
149	dev_log!(
150		"lifecycle",
151		"warn: [ApplicationState] Attempting recovery from poisoned lock in context: {}",
152		RecoveryContext
153	);
154
155	CommonError::StateLockPoisoned {
156		Context:format!("{} - Recovery attempted: {}", Error.to_string(), RecoveryContext),
157	}
158}
159
160/// Error handling result with recovery information.
161#[derive(Debug)]
162pub struct StateOperationResult<T> {
163	pub result:Result<T, CommonError>,
164
165	pub recovery_attempted:bool,
166
167	pub recovery_successful:bool,
168}