Skip to content

Commit f955918

Browse files
Merge branch 'Current' of ssh://github.com/CodeEditorLand/Mountain into Current
2 parents 27cd317 + 31f8d3e commit f955918

17 files changed

Lines changed: 4230 additions & 18 deletions

.github/Update.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Update: Mon Jan 26 01:27:48 UTC 2026
1+
Update: Wed Jan 28 01:23:01 UTC 2026

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ prost = { workspace = true }
5454
rand = { workspace = true }
5555
serde = { workspace = true }
5656
serde_json = { workspace = true }
57+
sha2 = { workspace = true }
58+
hostname = { workspace = true }
5759
thiserror = { workspace = true }
5860
tokio = { workspace = true, features = ["full"] }
5961
tokio-tungstenite = { workspace = true, features = ["rustls-tls-native-roots"] }

Source/Binary.rs

Lines changed: 227 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use crate::{
5757
},
5858
Command,
5959
Environment::{ConfigurationProvider::InitializeAndMergeConfigurations, MountainEnvironment::MountainEnvironment},
60+
IPC::{TauriIPCServer, register_wind_ipc_handlers, initialize_status_reporter, initialize_advanced_features, initialize_wind_advanced_sync},
6061
ProcessManagement::{CocoonManagement::InitializeCocoon, InitializationData},
6162
RunTime::ApplicationRunTime::ApplicationRunTime,
6263
Vine,
@@ -127,6 +128,168 @@ fn SwitchTrayIcon(App:AppHandle, IsDarkMode:bool) {
127128
}
128129
}
129130

131+
// =============================================================================
132+
// IPC Command Wrappers
133+
// =============================================================================
134+
135+
/// Receive messages from Wind through IPC
136+
#[tauri::command]
137+
async fn mountain_ipc_receive_message(
138+
app_handle: AppHandle,
139+
message: serde_json::Value
140+
) -> Result<serde_json::Value, String> {
141+
crate::IPC::TauriIPCServer::mountain_ipc_receive_message(app_handle, serde_json::from_value(message).map_err(|e| e.to_string())?).await
142+
}
143+
144+
/// Get Mountain IPC status
145+
#[tauri::command]
146+
async fn mountain_ipc_get_status(
147+
app_handle: AppHandle
148+
) -> Result<serde_json::Value, String> {
149+
crate::IPC::TauriIPCServer::mountain_ipc_get_status(app_handle).await
150+
}
151+
152+
/// Invoke IPC methods
153+
#[tauri::command]
154+
async fn mountain_ipc_invoke(
155+
app_handle: AppHandle,
156+
method: String,
157+
params: serde_json::Value
158+
) -> Result<serde_json::Value, String> {
159+
crate::IPC::WindServiceHandlers::mountain_ipc_invoke(app_handle, method, params).await
160+
}
161+
162+
/// Get Wind desktop configuration
163+
#[tauri::command]
164+
async fn mountain_get_wind_desktop_configuration(
165+
app_handle: AppHandle
166+
) -> Result<serde_json::Value, String> {
167+
crate::IPC::ConfigurationBridge::mountain_get_wind_desktop_configuration(app_handle).await
168+
}
169+
170+
/// Update configuration from Wind
171+
#[tauri::command]
172+
async fn mountain_update_configuration_from_wind(
173+
app_handle: AppHandle,
174+
config: serde_json::Value
175+
) -> Result<serde_json::Value, String> {
176+
crate::IPC::ConfigurationBridge::mountain_update_configuration_from_wind(app_handle, config).await
177+
}
178+
179+
/// Synchronize configuration
180+
#[tauri::command]
181+
async fn mountain_synchronize_configuration(
182+
app_handle: AppHandle
183+
) -> Result<serde_json::Value, String> {
184+
crate::IPC::ConfigurationBridge::mountain_synchronize_configuration(app_handle).await
185+
}
186+
187+
/// Get configuration status
188+
#[tauri::command]
189+
async fn mountain_get_configuration_status(
190+
app_handle: AppHandle
191+
) -> Result<serde_json::Value, String> {
192+
crate::IPC::ConfigurationBridge::mountain_get_configuration_status(app_handle).await
193+
}
194+
195+
/// Get IPC status
196+
#[tauri::command]
197+
async fn mountain_get_ipc_status(
198+
app_handle: AppHandle
199+
) -> Result<serde_json::Value, String> {
200+
crate::IPC::StatusReporter::mountain_get_ipc_status(app_handle).await
201+
}
202+
203+
/// Get IPC status history
204+
#[tauri::command]
205+
async fn mountain_get_ipc_status_history(
206+
app_handle: AppHandle
207+
) -> Result<serde_json::Value, String> {
208+
crate::IPC::StatusReporter::mountain_get_ipc_status_history(app_handle).await
209+
}
210+
211+
/// Start IPC status reporting
212+
#[tauri::command]
213+
async fn mountain_start_ipc_status_reporting(
214+
app_handle: AppHandle
215+
) -> Result<serde_json::Value, String> {
216+
crate::IPC::StatusReporter::mountain_start_ipc_status_reporting(app_handle).await
217+
}
218+
219+
/// Get performance stats
220+
#[tauri::command]
221+
async fn mountain_get_performance_stats(
222+
app_handle: AppHandle
223+
) -> Result<serde_json::Value, String> {
224+
crate::IPC::AdvancedFeatures::mountain_get_performance_stats(app_handle).await
225+
}
226+
227+
/// Get cache stats
228+
#[tauri::command]
229+
async fn mountain_get_cache_stats(
230+
app_handle: AppHandle
231+
) -> Result<serde_json::Value, String> {
232+
crate::IPC::AdvancedFeatures::mountain_get_cache_stats(app_handle).await
233+
}
234+
235+
/// Create collaboration session
236+
#[tauri::command]
237+
async fn mountain_create_collaboration_session(
238+
app_handle: AppHandle,
239+
session_data: serde_json::Value
240+
) -> Result<serde_json::Value, String> {
241+
crate::IPC::AdvancedFeatures::mountain_create_collaboration_session(app_handle, session_data).await
242+
}
243+
244+
/// Get collaboration sessions
245+
#[tauri::command]
246+
async fn mountain_get_collaboration_sessions(
247+
app_handle: AppHandle
248+
) -> Result<serde_json::Value, String> {
249+
crate::IPC::AdvancedFeatures::mountain_get_collaboration_sessions(app_handle).await
250+
}
251+
252+
/// Add document for sync
253+
#[tauri::command]
254+
async fn mountain_add_document_for_sync(
255+
app_handle: AppHandle,
256+
document_data: serde_json::Value
257+
) -> Result<serde_json::Value, String> {
258+
// Extract document_id and file_path from JSON data
259+
let document_id = document_data["document_id"].as_str()
260+
.ok_or("Missing document_id")?.to_string();
261+
let file_path = document_data["file_path"].as_str()
262+
.ok_or("Missing file_path")?.to_string();
263+
264+
crate::IPC::WindAdvancedSync::mountain_add_document_for_sync(app_handle, document_id, file_path).await
265+
.map(|_| serde_json::Value::Null)
266+
}
267+
268+
/// Get sync status
269+
#[tauri::command]
270+
async fn mountain_get_sync_status(
271+
app_handle: AppHandle
272+
) -> Result<serde_json::Value, String> {
273+
crate::IPC::WindAdvancedSync::mountain_get_sync_status(app_handle).await
274+
.map(|status| serde_json::to_value(status).unwrap_or(serde_json::Value::Null))
275+
}
276+
277+
/// Subscribe to updates
278+
#[tauri::command]
279+
async fn mountain_subscribe_to_updates(
280+
app_handle: AppHandle,
281+
subscription_data: serde_json::Value
282+
) -> Result<serde_json::Value, String> {
283+
// Extract target and subscriber from JSON data
284+
let target = subscription_data["target"].as_str()
285+
.ok_or("Missing target")?.to_string();
286+
let subscriber = subscription_data["subscriber"].as_str()
287+
.ok_or("Missing subscriber")?.to_string();
288+
289+
crate::IPC::WindAdvancedSync::mountain_subscribe_to_updates(app_handle, target, subscriber).await
290+
.map(|_| serde_json::Value::Null)
291+
}
292+
130293
// =============================================================================
131294
// Tray Initialization Logic
132295
// =============================================================================
@@ -409,7 +572,7 @@ pub fn Fn() {
409572
.setup({
410573
let LocalhostUrl = LocalhostUrl.clone();
411574

412-
move |Application| {
575+
move |Application| async move {
413576
info!("[Lifecycle] [Setup] Setup hook started.");
414577

415578
debug!("[Lifecycle] [Setup] LocalhostUrl={}", LocalhostUrl);
@@ -439,14 +602,53 @@ pub fn Fn() {
439602

440603
debug!("[Lifecycle] [Commands] Native commands registered.");
441604

442-
// ---------------------------------------------------------
443-
// [UI] [Window] Main window creation
444-
// ---------------------------------------------------------
445-
debug!("[UI] [Window] Building init script...");
605+
// ---------------------------------------------------------
606+
// [Lifecycle] [IPC] Initialize Mountain IPC Server
607+
// ---------------------------------------------------------
608+
debug!("[Lifecycle] [IPC] Initializing Mountain IPC Server...");
609+
610+
let ipc_server = crate::IPC::TauriIPCServer::new(ApplicationHandle.clone());
611+
ApplicationHandle.manage(ipc_server.clone());
612+
613+
debug!("[Lifecycle] [IPC] Mountain IPC Server initialized.");
614+
615+
// ---------------------------------------------------------
616+
// [Lifecycle] [IPC] Initialize Status Reporter
617+
// ---------------------------------------------------------
618+
debug!("[Lifecycle] [IPC] Initializing Status Reporter...");
446619

447-
let InitScript = format!("window.__MOUNTAIN_BASE_URL__ = '{}';", LocalhostUrl);
620+
let status_reporter = initialize_status_reporter(&ApplicationHandle, Runtime.clone())?;
621+
status_reporter.set_ipc_server(ipc_server);
622+
623+
// Start periodic status reporting
624+
if let Err(e) = status_reporter.start_periodic_reporting(30).await {
625+
error!("[Lifecycle] [IPC] Failed to start status reporting: {}", e);
626+
}
627+
628+
debug!("[Lifecycle] [IPC] Status Reporter initialized.");
629+
630+
// ---------------------------------------------------------
631+
// [Lifecycle] [IPC] Initialize Advanced Features
632+
// ---------------------------------------------------------
633+
debug!("[Lifecycle] [IPC] Initializing Advanced Features...");
634+
635+
if let Err(e) = initialize_advanced_features(&ApplicationHandle, Runtime.clone()) {
636+
error!("[Lifecycle] [IPC] Failed to initialize advanced features: {}", e);
637+
}
638+
639+
debug!("[Lifecycle] [IPC] Advanced Features initialized.");
640+
641+
// ---------------------------------------------------------
642+
// [Lifecycle] [IPC] Initialize Wind Advanced Sync
643+
// ---------------------------------------------------------
644+
debug!("[Lifecycle] [IPC] Initializing Wind Advanced Sync...");
645+
646+
if let Err(e) = initialize_wind_advanced_sync(&ApplicationHandle, Runtime.clone()) {
647+
error!("[Lifecycle] [IPC] Failed to initialize Wind advanced sync: {}", e);
648+
}
448649

449-
TraceStep!("[UI] [Window] InitScript bytes={}", InitScript.len());
650+
debug!("[Lifecycle] [IPC] Wind Advanced Sync initialized.");
651+
TraceStep!("[UI] [Window] InitScript bytes=0");
450652

451653
debug!("[UI] [Window] Creating window builder...");
452654

@@ -458,7 +660,7 @@ pub fn Fn() {
458660
),
459661
)
460662
.use_https_scheme(false)
461-
.initialization_script(&InitScript)
663+
.initialization_script("")
462664
.zoom_hotkeys_enabled(true)
463665
.browser_extensions_enabled(false);
464666

@@ -630,6 +832,23 @@ pub fn Fn() {
630832
Command::Keybinding::GetResolvedKeybinding,
631833
crate::Track::DispatchLogic::DispatchFrontendCommand,
632834
crate::Track::DispatchLogic::ResolveUIRequest,
835+
mountain_ipc_receive_message,
836+
mountain_ipc_get_status,
837+
mountain_ipc_invoke,
838+
mountain_get_wind_desktop_configuration,
839+
mountain_update_configuration_from_wind,
840+
mountain_synchronize_configuration,
841+
mountain_get_configuration_status,
842+
mountain_get_ipc_status,
843+
mountain_get_ipc_status_history,
844+
mountain_start_ipc_status_reporting,
845+
mountain_get_performance_stats,
846+
mountain_get_cache_stats,
847+
mountain_create_collaboration_session,
848+
mountain_get_collaboration_sessions,
849+
mountain_add_document_for_sync,
850+
mountain_get_sync_status,
851+
mountain_subscribe_to_updates,
633852
])
634853
// ---------------------------------------------------------------------
635854
// [Tauri] Build & run loop

Source/ExtensionManagement/Scanner.rs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,62 @@ pub fn CollectDefaultConfigurations(State:&ApplicationState) -> Result<Value, Co
111111
if let Some(contributes) = Extension.Contributes.as_ref().and_then(|v| v.as_object()) {
112112
if let Some(configuration) = contributes.get("configuration").and_then(|v| v.as_object()) {
113113
if let Some(properties) = configuration.get("properties").and_then(|v| v.as_object()) {
114-
for (key, value) in properties {
115-
if let Some(prop_details) = value.as_object() {
116-
if let Some(default_value) = prop_details.get("default") {
117-
// TODO: A full implementation would handle nested objects.
118-
MergedDefaults.insert(key.clone(), default_value.clone());
119-
}
120-
}
121-
}
114+
// ADVANCED NESTED OBJECT HANDLING: Recursively process configuration properties
115+
self::process_configuration_properties(
116+
&mut MergedDefaults,
117+
"",
118+
properties,
119+
&mut Vec::new()
120+
)?;
122121
}
123122
}
124123
}
125124
}
126125

127126
Ok(Value::Object(MergedDefaults))
128127
}
128+
129+
/// ADVANCED RECURSIVE CONFIGURATION PROCESSING: Handle nested object structures
130+
fn process_configuration_properties(
131+
merged_defaults: &mut serde_json::Map<String, Value>,
132+
current_path: &str,
133+
properties: &serde_json::Map<String, Value>,
134+
visited_keys: &mut Vec<String>
135+
) -> Result<(), String> {
136+
for (key, value) in properties {
137+
// Build the full path for this property
138+
let full_path = if current_path.is_empty() {
139+
key.clone()
140+
} else {
141+
format!("{}.{}", current_path, key)
142+
};
143+
144+
// Check for circular references
145+
if visited_keys.contains(&full_path) {
146+
return Err(format!("Circular reference detected in configuration properties: {}", full_path));
147+
}
148+
149+
visited_keys.push(full_path.clone());
150+
151+
if let Some(prop_details) = value.as_object() {
152+
// Check if this is a nested object structure
153+
if let Some(nested_properties) = prop_details.get("properties").and_then(|v| v.as_object()) {
154+
// Recursively process nested properties
155+
self::process_configuration_properties(
156+
merged_defaults,
157+
&full_path,
158+
nested_properties,
159+
visited_keys
160+
)?;
161+
} else if let Some(default_value) = prop_details.get("default") {
162+
// Handle regular property with default value
163+
merged_defaults.insert(full_path.clone(), default_value.clone());
164+
}
165+
}
166+
167+
// Remove current key from visited keys
168+
visited_keys.retain(|k| k != &full_path);
169+
}
170+
171+
Ok(())
172+
}

0 commit comments

Comments
 (0)