Skip to content

Commit da0d834

Browse files
refactor(Build): restructure Mountain entry point into module
- Moved main application entry from `main.rs` to `Entry.rs` module - Added `pub mod Entry` declaration in `Library.rs` for proper module exposure - Maintained all Mountain backend initialization logic including Tauri setup, AppState management, and Cocoon process launching - Updated module imports to reflect new structure while preserving functionality This restructuring aligns with Rust project conventions, improves code organization as the Land project scales, and enables better testability by separating the entry point from library components. The change supports future expansion of Mountain's core modules while maintaining the critical startup sequence for the Tauri-based backend.
1 parent 4a02fa4 commit da0d834

2 files changed

Lines changed: 96 additions & 136 deletions

File tree

Source/main.rs renamed to Source/Entry.rs

Lines changed: 94 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// - In `.setup()`:
1616
// - Perform AppState initializations requiring AppHandle (paths, extension
1717
// scan, config load).
18-
// - Register frontend command handlers (`Track`).
18+
// - Register frontend command handlers (`Track` and UI response handlers).
1919
// - Launch sidecar processes (Cocoon) via `process_mgmt`.
2020
// - Initialize IPC/RPC layers (`Vine`/`rpc`).
2121
// - Register custom URI protocol handlers (`handlers::protocol`).
@@ -27,8 +27,9 @@
2727
// path resolution.
2828
// - Manages `AppState` and `AppRuntime` via Tauri's `State<T>`.
2929
// - Calls `handlers::process_mgmt::launch_and_manage_cocoon`.
30-
// - Calls `rpc::setup_mountain_rpc_server` (conceptual).
31-
// - Registers `track::dispatch_command` and
30+
// - Calls `rpc::setup_mountain_rpc_server`.
31+
// - Registers `track::dispatch_command`,
32+
// `handlers::sky_ui_responses::sky_resolves_ui_request`, and
3233
// `handlers::protocol::handle_vscode_protocol`.
3334
// --------------------------------------------------------------------------------------------
3435

@@ -41,31 +42,29 @@ use log::{debug, error, info, trace, warn};
4142
use tauri::{AppHandle, Manager, Runtime as TauriRuntime, State, Window, Wry};
4243

4344
// --- Application Modules ---
44-
mod app_state;
45+
// mod app_state;
4546

46-
mod environment;
47-
48-
mod handlers;
47+
// mod environment;
4948

49+
// Parent module for sub-handlers
50+
// mod handlers;
5051
// Centralized logger initialization
51-
mod logging_setup;
52-
mod mist;
53-
54-
mod rpc;
52+
// mod logging_setup;
53+
// mod mist;
5554

56-
mod runtime;
55+
// mod rpc;
5756

58-
mod track;
57+
// mod runtime;
5958

60-
mod vine;
59+
// mod track;
6160

62-
use app_state::AppState;
63-
use environment::MountainEnvironment;
64-
use runtime::AppRuntime;
61+
// mod vine;
62+
use crate::app_state::AppState;
63+
use crate::{environment::MountainEnvironment, runtime::AppRuntime};
6564

66-
// Example struct for event payloads (may or may not be actively used in main)
6765
#[derive(Clone, serde::Serialize)]
6866
struct GenericPayload {
67+
// Example, may not be used directly in main
6968
message:String,
7069
}
7170

@@ -85,144 +84,99 @@ async fn main() {
8584
.manage(initial_app_state)
8685
// AppRuntime and MountainEnvironment will be created and managed inside .setup once AppHandle is available
8786
.setup(|app| {
88-
8987
info!("[Mountain Setup] Tauri setup hook running.");
9088

9189
let app_handle = app.handle();
90+
9291
// --- Create and Manage Environment & Runtime with AppHandle ---
9392
let mountain_env_arc = Arc::new(MountainEnvironment::new(app_handle.clone()));
9493

9594
let app_runtime_arc = Arc::new(AppRuntime::new(mountain_env_arc.clone()));
9695

9796
// Manage the fully initialized AppRuntime
9897
app_handle.manage(app_runtime_arc.clone());
98+
9999
info!("[Mountain Setup] MountainEnvironment and AppRuntime created and managed.");
100+
100101
// --- AppState Post-Handle Initialization Task ---
101102
// This task performs initializations that require AppHandle and should run asynchronously.
102103
let post_setup_app_handle = app_handle.clone();
103104

104105
tauri::async_runtime::spawn(async move {
105106
info!("[Mountain Setup Task] Starting AppState post-handle initialization...");
106107

108+
// Get managed AppState
107109
let app_state = post_setup_app_handle.state::<AppState>();
108110

109111
// 1. Resolve and set extension scan paths
110-
let mut resolved_scan_paths: Vec<PathBuf> = Vec::new();
112+
// Assumes AppState.extension_scan_paths is Arc<Mutex<Vec<PathBuf>>>
113+
{
114+
let mut resolved_scan_paths: Vec<PathBuf> = Vec::new();
115+
116+
if let Some(builtin_ext_dir) = post_setup_app_handle.path_resolver().resolve_resource("extensions/builtin") {
117+
if builtin_ext_dir.is_dir() {
118+
info!("[Mountain Setup Task] Adding builtin extension scan path: {}", builtin_ext_dir.display());
119+
120+
resolved_scan_paths.push(builtin_ext_dir);
121+
} else {
122+
warn!("[Mountain Setup Task] Resolved builtin extension path is not a directory or does not exist: {}", builtin_ext_dir.display());
123+
}
124+
} else {
125+
warn!("[Mountain Setup Task] Could not resolve 'extensions/builtin' resource path.");
126+
}
111127

112-
if let Some(builtin_ext_dir) = post_setup_app_handle.path_resolver().resolve_resource("extensions/builtin") {
113-
info!("[Mountain Setup Task] Adding builtin extension scan path: {}", builtin_ext_dir.display());
114-
resolved_scan_paths.push(builtin_ext_dir);
115-
} else {
116-
warn!("[Mountain Setup Task] Could not resolve 'extensions/builtin' resource path.");
117-
}
128+
if let Some(user_ext_base_dir) = post_setup_app_handle.path_resolver().app_data_dir() {
129+
let user_ext_dir = user_ext_base_dir.join("extensions");
118130

119-
// TODO: Add other potential scan paths (e.g., user extensions based on config or standard locations)
120-
// Example:
121-
// if let Some(user_ext_dir) = post_setup_app_handle.path_resolver().app_data_dir().map(|d| d.join("extensions")) {
122-
// if user_ext_dir.exists() {
123-
// info!("[Mountain Setup Task] Adding user extension scan path: {}", user_ext_dir.display());
124-
// resolved_scan_paths.push(user_ext_dir);
125-
// }
126-
// }
127-
// Scope for mutable access to app_state.extension_scan_paths if it were a Mutex/RwLock
128-
{
129-
// For now, assuming direct vec mutation is fine if it's not Arc<Mutex<Vec<PathBuf>>>
130-
// If it's plain Vec, this direct modification is problematic if AppState is shared.
131-
// app_state.extension_scan_paths needs to be Arc<Mutex<Vec<PathBuf>>> or similar for this to be safe.
132-
// For simplicity of this example, assuming AppState::extension_scan_paths itself might be behind a lock or is init-once.
133-
// Given AppState structure, this direct modification is incorrect.
134-
// Instead, it should be like:
135-
// let mut scan_paths_guard = app_state.extension_scan_paths.lock().unwrap();
136-
137-
// scan_paths_guard.clear();
138-
139-
// scan_paths_guard.extend(resolved_scan_paths);
140-
141-
// OR if extension_scan_paths is not wrapped in Arc<Mutex>:
142-
// If it's a plain field, this task needs &mut AppState or similar
143-
// app_state.extension_scan_paths = resolved_scan_paths;
144-
145-
// Correct approach: Assuming AppState.extension_scan_paths is NOT behind a Mutex
146-
// and this task owns a mutable reference or is initializing a part of it.
147-
// The current `app_state.extension_scan_paths` is `Vec<PathBuf>`, not `Arc<Mutex<...>>`
148-
// This indicates that `extension_scan_paths` is intended to be populated once, possibly here.
149-
// If it needs to be dynamic later, AppState field type should change.
150-
// For now, we'll assume this is effectively an initialization step for that field.
151-
// To make this safe with `State<AppState>`, the field itself needs to be behind a Mutex
152-
// or this part of initialization logic needs rethinking.
153-
// Let's assume AppState holds an Arc<Mutex<Vec<PathBuf>>> for extension_scan_paths.
154-
// If AppState is: pub extension_scan_paths: Vec<PathBuf>, then this is not thread safe.
155-
// Reverting to original intent if it was non-Mutexed for simplicity:
156-
// Clear placeholder
157-
// app_state.extension_scan_paths.clear();
158-
// app_state.extension_scan_paths.extend(resolved_scan_paths);
159-
160-
// *This part highlights a potential design issue in the provided AppState if modification
161-
// is expected from multiple places or async tasks after initial AppState::default().
162-
// For the purpose of synthesis, assuming app_state.scan_extensions() internally handles
163-
// how it gets/uses these paths if they are set this way.
164-
// If AppState.extension_scan_paths must be mutable, it needs Arc<Mutex>.
165-
// Given `state.scan_extensions().await` is called next, that method should use the paths.
166-
// Let's assume AppState::default() initialized it empty and this task populates it before scan.
167-
// If `scan_extensions` reads from `self.extension_scan_paths`, it will see this.
168-
// THIS IS STILL NOT SAFE IF AppState IS CLONED AND SHARED WITHOUT INTERNAL MUTABILITY FOR THE VEC.
169-
// Safest: AppState::extension_scan_paths: Arc<Mutex<Vec<PathBuf>>>
170-
// For now, will keep the direct modification as implied by `state.extension_scan_paths.clear()`
171-
// but acknowledge it's problematic without internal mutability for that field in AppState.
172-
// The AppState provided DOES NOT use Arc<Mutex<Vec<PathBuf>>>, it's just Vec<PathBuf>.
173-
// So, the `.manage(initial_app_state)` shares an immutable AppState.
174-
// The only way to modify it is if `app_state` itself is `Arc<Mutex<AppState>>`, or
175-
// its fields are `Arc<Mutex<...>>`.
176-
// The current `AppState` uses `Arc<Mutex<...>>` for *most* fields, but not `extension_scan_paths`.
177-
// This is a design flaw in the provided `AppState`.
178-
// **Correction based on AppState structure:** `extension_scan_paths` is NOT mutable this way.
179-
// It must be set during `AppState::default()` or `AppState` must be wrapped further.
180-
// Alternative: clone app_state, modify, and then re-manage. But this is not ideal.
181-
// **Simplifying assumption for synthesis:**
182-
// `extension_scan_paths` is initialized in `AppState::default()` with these paths,
183-
// or `scan_extensions` takes paths as an argument.
184-
// For now, commenting out direct modification and relying on `scan_extensions` to use paths
185-
// set in `AppState::default()` or another mechanism.
186-
debug!("[Mountain Setup Task] Extension scan paths used by scan_extensions will be from AppState::default or config.");
131+
if user_ext_dir.is_dir() {
132+
info!("[Mountain Setup Task] Adding user extension scan path: {}", user_ext_dir.display());
133+
134+
resolved_scan_paths.push(user_ext_dir);
135+
} else {
136+
trace!("[Mountain Setup Task] User extension path does not exist, skipping: {}", user_ext_dir.display());
137+
}
138+
} else {
139+
warn!("[Mountain Setup Task] Could not resolve app data directory for user extensions path.");
140+
}
141+
142+
let mut scan_paths_guard = app_state.extension_scan_paths.lock().expect("Failed to lock extension_scan_paths for writing");
143+
144+
scan_paths_guard.clear();
187145

146+
scan_paths_guard.extend(resolved_scan_paths);
147+
148+
debug!("[Mountain Setup Task] Final extension scan paths set in AppState: {:?}", scan_paths_guard);
188149
}
189-
// 2. Scan for extensions
150+
151+
// 2. Scan for extensions (now uses the paths set above)
190152
app_state.scan_extensions().await;
191-
// 3. Load/configure enabled proposed APIs
192-
{
193-
let mut proposed_apis_guard = app_state.enabled_proposed_apis.lock().expect("Failed to lock proposed APIs for init");
194153

195-
proposed_apis_guard.insert("*".to_string(), vec!["testProposedApi".to_string(), "workspaceTrust".to_string()]);
154+
// 3. Load/configure enabled proposed APIs (example)
155+
let mut proposed_apis_guard = app_state.enabled_proposed_apis.lock().expect("Failed to lock proposed APIs for init");
156+
157+
// For MVP, could be hardcoded or from a simple config file Mountain loads
158+
proposed_apis_guard.insert("*".to_string(), vec!["testProposedApi".to_string(), "workspaceTrust".to_string()]);
159+
160+
info!("[Mountain Setup Task] Enabled proposed APIs configured. Count: {}", proposed_apis_guard.len());
196161

197-
info!("[Mountain Setup Task] Enabled proposed APIs configured. Count: {}", proposed_apis_guard.len());
198-
}
199-
200162
// 4. Load initial merged configuration into AppState
201163
match handlers::config::load_and_merge_configurations_internal(&post_setup_app_handle, &app_state).await {
202-
203164
Ok(merged_config_state) => {
204-
205165
app_state.configuration.lock().expect("Failed to lock AppState.configuration for init load").update_from(merged_config_state);
206166

207167
info!("[Mountain Setup Task] Initial merged configuration loaded into AppState.");
208-
209168
}
210169
Err(e) => {
211-
212170
error!("[Mountain Setup Task] CRITICAL: Failed to load initial merged configurations: {}", e);
213-
214171
}
215172
}
216-
217-
// 5. Update workspace memento path
218-
if let Some(app_data_dir_for_memento) = post_setup_app_handle.path_resolver().app_data_dir() {
219173

174+
// 5. Update workspace memento path based on initial workspace (if any)
175+
if let Some(app_data_dir_for_memento) = post_setup_app_handle.path_resolver().app_data_dir() {
220176
debug!("[Mountain Setup Task] Attempting to initialize workspace memento path based on data dir: {}", app_data_dir_for_memento.display());
221177

222178
if let Err(e) = app_state.update_workspace_memento_path(&app_data_dir_for_memento) {
223-
224179
error!("[Mountain Setup Task] Failed to initialize workspace memento path: {}", e);
225-
226180
}
227181
} else {
228182
warn!("[Mountain Setup Task] App data directory not available for workspace memento path init at this stage.");
@@ -236,7 +190,6 @@ async fn main() {
236190

237191
app.protocol()
238192
.register("vscode", move |request| {
239-
240193
debug!("[Mountain Setup Protocol] Received vscode:// request: {}", request.uri());
241194

242195
handlers::protocol::handle_vscode_protocol(request, protocol_handle_setup.clone())
@@ -245,10 +198,8 @@ async fn main() {
245198

246199
info!("[Mountain Setup] vscode:// protocol registered.");
247200

201+
248202
// --- Setup RPC Server (for Vine/Sidecar Communication) ---
249-
// This setup ensures Mountain can handle incoming RPC calls.
250-
// Actual dispatching of these calls to specific handlers typically happens
251-
// within the Vine/RPC layer, using the AppRuntime to execute logic.
252203
let rpc_runtime_clone_setup = app_handle.state::<Arc<AppRuntime>>().inner().clone();
253204

254205
let rpc_app_handle_clone_setup = app_handle.clone();
@@ -264,7 +215,6 @@ async fn main() {
264215

265216
let cocoon_app_handle = app_handle.clone();
266217

267-
// Use Tauri's async runtime for background tasks
268218
tauri::async_runtime::spawn(async move {
269219
handlers::process_mgmt::launch_and_manage_cocoon(cocoon_app_handle).await;
270220
});
@@ -278,7 +228,6 @@ async fn main() {
278228
// --- Start Native Mist WebSocket Server (Conditional) ---
279229
#[cfg(feature = "mist_native")]
280230
{
281-
282231
info!("[Mountain Setup] Native Mist feature enabled. Spawning start_websocket_server task...");
283232

284233
let mist_app_handle = app_handle.clone();
@@ -295,9 +244,9 @@ async fn main() {
295244
info!("[Mountain Setup] Native Mist feature disabled.");
296245
}
297246

247+
298248
// --- TODO: Start File Watchers for Configuration Files ---
299-
// This would involve using a crate like `notify` to watch settings.json files
300-
// and trigger a configuration reload (e.g., calling parts of the post-setup task again).
249+
// Example:
301250
// let watcher_app_handle = app_handle.clone();
302251
// tauri::async_runtime::spawn(async move {
303252
// if let Err(e) = handlers::config_watcher::start_watching_config_files(watcher_app_handle).await {
@@ -313,22 +262,21 @@ async fn main() {
313262
})
314263
.invoke_handler(tauri::generate_handler![
315264
// Main entry point for frontend commands
316-
track::dispatch_command
265+
track::dispatch_command,
266+
// Handler for UI responses from Sky
267+
handlers::sky_ui_responses::sky_resolves_ui_request
317268
])
318269
.on_window_event(|event| match event.event() {
319270
tauri::WindowEvent::CloseRequested { api, .. } => {
320-
321271
info!("[Mountain WindowEvent] Close requested for window: {}", event.window().label());
322272

323273
// TODO: Implement graceful shutdown:
324274
// 1. Notify Cocoon to deactivate extensions.
325275
// 2. Wait for Cocoon to signal completion or timeout.
326276
// 3. Save AppState (mementos, dirty files via DocumentProvider effects).
327277
// 4. Allow close.
328-
// For now, allow default close. To prevent for debugging:
329-
// api.prevent_close();
330-
331-
// warn!("[Mountain WindowEvent] Close prevention is active for debugging if uncommented.");
278+
// To prevent immediate close
279+
// Example: api.prevent_close();
332280
}
333281

334282
tauri::WindowEvent::Destroyed => {
@@ -338,36 +286,46 @@ async fn main() {
338286
_ => {
339287
trace!("[Mountain WindowEvent] Other event on window '{}': {:?}", event.window().label(), event.event());
340288
}
289+
341290
})
342291
.build(tauri::generate_context!())
343-
.expect("Error while building Mountain Tauri application").run(|app_handle_run, event| match event {
344-
// Renamed app_handle to avoid conflict
292+
.expect("Error while building Mountain Tauri application")
293+
.run(|app_handle_run, event| match event {
345294
tauri::RunEvent::ExitRequested { api, .. } => {
346295
info!("[Mountain RunEvent] Application exit requested. Performing cleanup...");
347296

348297
// TODO: Global cleanup before app exit:
298+
// Call this if async cleanup is needed
349299
// api.prevent_exit();
350-
351300
// let handle_clone_exit = app_handle_run.clone();
352301

353302
// tauri::async_runtime::spawn(async move {
354-
355303
// info!("[Mountain Exit] Signaling sidecars to terminate...");
356304

357-
// Example: vine::broadcast_terminate_signal(&handle_clone_exit).await;
358-
//
359-
// Give time
305+
// // Example: vine::broadcast_terminate_signal(&handle_clone_exit).await;
306+
307+
// Give time for sidecars
360308
// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
361309
// info!("[Mountain Exit] Exiting application now.");
310+
311+
// Exit after cleanup
362312
// handle_clone_exit.exit(0);
363313
// });
364314

315+
info!("[Mountain RunEvent] Application process is beginning to exit or handling exit request.");
365316
}
366-
317+
367318
tauri::RunEvent::Exit => {
368-
info!("[Mountain RunEvent] Application process is exiting.");
319+
info!("[Mountain RunEvent] Application has fully exited.");
320+
}
321+
322+
tauri::RunEvent::Ready => {
323+
info!("[Mountain RunEvent] Application is ready.");
324+
}
325+
326+
_ => {
327+
trace!("[Mountain RunEvent] Other/unhandled run event: {:?}", event);
369328
}
370-
_ => {}
371329
});
372330

373331
info!("[Mountain Main] Application event loop finished or error occurred.");

Source/Library.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,5 @@ pub mod handlers {
4747

4848
pub mod workspace_fs_api;
4949
}
50+
51+
pub mod Entry;

0 commit comments

Comments
 (0)