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::State as ConfigurationState,
55 ExtensionState::State::State as ExtensionState,
56 FeatureState::State::State as FeatureState,
57 UIState::State as UIState,
58 WorkspaceState::State as WorkspaceState,
59};
60use crate::{Environment::TestProvider::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 pub WorkspaceMementoPath:Arc<StandardMutex<Option<std::path::PathBuf>>>,
87}
88
89impl Default for ApplicationState {
90 fn default() -> Self {
91 dev_log!("lifecycle", "[ApplicationState] Initializing default application state...");
92
93 Self {
94 Workspace:Default::default(),
95 Configuration:Default::default(),
96 Extension:Default::default(),
97 Feature:Default::default(),
98 UI:Default::default(),
99 TestProviderState:Arc::new(tokio::sync::RwLock::new(TestProviderState::new())),
100 GlobalMementoPath:Arc::new(StandardMutex::new(Default::default())),
101 WorkspaceMementoPath:Arc::new(StandardMutex::new(None)),
102 }
103 }
104}
105
106impl ApplicationState {
107 /// Gets the next available unique identifier for a provider registration.
108 pub fn GetNextProviderHandle(&self) -> u32 { self.Extension.GetNextProviderHandle() }
109
110 /// Gets the next available unique identifier for a terminal instance.
111 pub fn GetNextTerminalIdentifier(&self) -> u64 { self.Feature.GetNextTerminalIdentifier() }
112
113 /// Gets the next available unique identifier for an SCM provider.
114 pub fn GetNextSourceControlManagementProviderHandle(&self) -> u32 {
115 self.Feature.GetNextSourceControlManagementProviderHandle()
116 }
117
118 /// Gets the workspace identifier for the current application instance.
119 /// This is used to differentiate between different workspace instances
120 /// when running multiple instances of the application.
121 pub fn GetWorkspaceIdentifier(&self) -> Result<String, CommonError> {
122 // For now, generate a simple identifier based on the current timestamp
123 // In a proper implementation, this would be stored and persisted
124 use std::time::{SystemTime, UNIX_EPOCH};
125
126 let timestamp = SystemTime::now()
127 .duration_since(UNIX_EPOCH)
128 .map_err(|e| CommonError::Unknown { Description:format!("Failed to get system time: {}", e) })?;
129
130 Ok(format!("workspace-{:x}", timestamp.as_millis()))
131 }
132}
133
134/// A helper to map a mutex poison error into a CommonError.
135pub fn MapLockError<T>(Error:PoisonError<T>) -> CommonError {
136 CommonError::StateLockPoisoned { Context:Error.to_string() }
137}
138
139/// A helper to map a mutex poison error with recovery attempt.
140pub fn MapLockErrorWithRecovery<T>(Error:PoisonError<T>, RecoveryContext:&str) -> CommonError {
141 dev_log!(
142 "lifecycle",
143 "warn: [ApplicationState] Attempting recovery from poisoned lock in context: {}",
144 RecoveryContext
145 );
146 CommonError::StateLockPoisoned {
147 Context:format!("{} - Recovery attempted: {}", Error.to_string(), RecoveryContext),
148 }
149}
150
151/// Error handling result with recovery information.
152#[derive(Debug)]
153pub struct StateOperationResult<T> {
154 pub result:Result<T, CommonError>,
155 pub recovery_attempted:bool,
156 pub recovery_successful:bool,
157}