Mountain/Binary/Main/
Entry.rs

1//! # Entry (Binary/Main)
2//!
3//! ## RESPONSIBILITIES
4//!
5//! Main application entry point that orchestrates the complete application
6//! lifecycle. This function coordinates:
7//! - Tokio runtime creation and management
8//! - CLI argument parsing
9//! - Application state initialization
10//! - Tauri application builder setup
11//! - Service initialization (Vine, Cocoon, Configuration)
12//! - Graceful shutdown handling
13//!
14//! ## ARCHITECTURAL ROLE
15//!
16//! The Entry module is the **primary entry point** in Mountain's architecture:
17//!
18//! ```text
19//! main.rs ──► Binary::Main::Entry::Fn()
20//!                                    │
21//!                                    ▼
22//! AppLifecycle ──► Service Initialization ──► Tauri App Run
23//!                                           │
24//!                                           ▼
25//!                                   Graceful Shutdown
26//! ```
27//!
28//! ## KEY COMPONENTS
29//!
30//! - **Fn()**: Main entry point exported as `Binary::Main::Fn()`
31//! - Tokio runtime management
32//! - Application state initialization via StateBuild
33//! - Tauri builder configuration via TauriBuild
34//! - Service orchestration (Vine, Cocoon, Configuration)
35//! - Event-driven lifecycle management
36//!
37//! ## ERROR HANDLING
38//!
39//! - Panics on fatal errors (Tokio runtime failure, Tauri build failure)
40//! - Logs errors for service initialization failures
41//! - Graceful degradation for non-critical service failures
42//!
43//! ## LOGGING
44//!
45//! Uses the TraceStep! macro for checkpoint logging at TRACE level.
46//! Additional logging at DEBUG, INFO, WARN, and ERROR levels throughout.
47//!
48//! ## PERFORMANCE CONSIDERATIONS
49//!
50//! - Tokio multi-threaded runtime for optimal performance
51//! - Asynchronous service initialization
52//! - Lazy initialization where possible
53//!
54//! ## TODO
55//! - [ ] Add crash recovery mechanism
56//! - [ ] Implement proper error dialog for startup failures
57//! - [ ] Add startup performance metrics
58
59use std::sync::Arc;
60
61use log::{debug, error, info, trace, warn};
62use tauri::{App, RunEvent, Wry};
63use Echo::Scheduler::{Scheduler::Scheduler, SchedulerBuilder::SchedulerBuilder};
64
65use crate::{
66	// Crate root imports
67	ApplicationState::ApplicationState,
68	// Binary submodule imports
69	Binary::Build::LocalhostPlugin::LocalhostPlugin as LocalhostPluginFn,
70	Binary::Build::LoggingPlugin::LoggingPlugin as LoggingPluginFn,
71	Binary::Build::TauriBuild::TauriBuild as TauriBuildFn,
72	Binary::Build::WindowBuild::WindowBuild as WindowBuildFn,
73	Binary::Extension::ExtensionPopulate::ExtensionPopulate as ExtensionPopulateFn,
74	Binary::Extension::ScanPathConfigure::ScanPathConfigure as ScanPathConfigureFn,
75	Binary::Initialize::CliParse::Parse as CliParseFn,
76	Binary::Initialize::LogLevel::Resolve as ResolveLogLevel,
77	Binary::Initialize::PortSelector::BuildUrl as BuildPortUrl,
78	Binary::Initialize::PortSelector::Select as SelectPort,
79	Binary::Initialize::StateBuild::Build as BuildStateFn,
80	Binary::Register::AdvancedFeaturesRegister::AdvancedFeaturesRegister as AdvancedFeaturesRegisterFn,
81	Binary::Register::CommandRegister::CommandRegister as CommandRegisterFn,
82	Binary::Register::IPCServerRegister::IPCServerRegister as IPCServerRegisterFn,
83	Binary::Register::StatusReporterRegister::StatusReporterRegister as StatusReporterRegisterFn,
84	Binary::Register::WindSyncRegister::WindSyncRegister as WindSyncRegisterFn,
85	Binary::Service::CocoonStart::CocoonStart as CocoonStartFn,
86	Binary::Service::ConfigurationInitialize::ConfigurationInitialize as ConfigurationInitializeFn,
87	Binary::Service::VineStart::VineStart as VineStartFn,
88	Binary::Shutdown::RuntimeShutdown::RuntimeShutdown as RuntimeShutdownFn,
89	Binary::Shutdown::SchedulerShutdown::SchedulerShutdown as SchedulerShutdownFn,
90	Command,
91	Environment::MountainEnvironment::MountainEnvironment,
92	ProcessManagement::InitializationData,
93	RunTime::ApplicationRunTime::ApplicationRunTime,
94	Track,
95};
96use super::AppLifecycle::AppLifecycleSetup;
97
98// Note: Tauri commands are used with fully qualified paths in generate_handler
99// because the __cmd_* macros generated by #[tauri::command] are module-local.
100
101/// Logs a checkpoint message at TRACE level.
102macro_rules! TraceStep {
103	($($arg:tt)*) => {{
104		trace!($($arg)*);
105	}};
106}
107
108/// The main function that orchestrates the application lifecycle.
109///
110/// This function:
111/// 1. Creates a Tokio runtime
112/// 2. Parses CLI arguments
113/// 3. Builds application state
114/// 4. Creates a scheduler
115/// 5. Selects a port for the local server
116/// 6. Resolves the log level
117/// 7. Sets up the Tauri builder
118/// 8. Configures the application lifecycle
119/// 9. Runs the Tauri application
120/// 10. Handles graceful shutdown
121pub fn Fn() {
122	// -------------------------------------------------------------------------
123	// [Boot] [Runtime] Tokio runtime creation
124	// -------------------------------------------------------------------------
125	TraceStep!("[Boot] [Runtime] Building Tokio runtime...");
126
127	let Runtime = tokio::runtime::Builder::new_multi_thread()
128		.enable_all()
129		.build()
130		.expect("FATAL: Cannot build Tokio runtime.");
131
132	TraceStep!("[Boot] [Runtime] Tokio runtime built.");
133
134	Runtime.block_on(async {
135		// ---------------------------------------------------------------------
136		// [Boot] [Args] CLI parsing (using CliParse module)
137		// ---------------------------------------------------------------------
138		let _WorkspaceConfigurationPath = CliParseFn();
139		let _InitialFolders: Vec<String> = vec![];
140
141		// ---------------------------------------------------------------------
142		// [Boot] [State] ApplicationState (using StateBuild module)
143		// ---------------------------------------------------------------------
144		debug!("[Boot] [State] Building ApplicationState...");
145
146		// Create application state directly (StateBuild::Build with default config)
147		let AppState = ApplicationState::default();
148
149		debug!(
150			"[Boot] [State] ApplicationState created with {} workspace folders.",
151			AppState.Workspace.WorkspaceFolders.lock().map(|f| f.len()).unwrap_or(0)
152		);
153
154		// Create Arc for application state to be managed by Tauri
155		let AppStateArcForClosure = Arc::new(AppState.clone());
156
157		// ---------------------------------------------------------------------
158		// [Boot] [Runtime] Scheduler handles (using RuntimeBuild module)
159		// ---------------------------------------------------------------------
160		let Scheduler = Arc::new(SchedulerBuilder::Create().Build());
161		let SchedulerForClosure = Scheduler.clone();
162		TraceStep!("[Boot] [Echo] Scheduler handles prepared.");
163
164		// ---------------------------------------------------------------------
165		// [Boot] [Localhost] Port selection (using PortSelector module)
166		// ---------------------------------------------------------------------
167		let ServerPort = SelectPort();
168		let LocalhostUrl = BuildPortUrl(ServerPort);
169
170		// ---------------------------------------------------------------------
171		// [Boot] [Logging] Log level resolution (using LogLevel module)
172		// ---------------------------------------------------------------------
173		let log_level = ResolveLogLevel();
174
175		// ---------------------------------------------------------------------
176		// [Boot] [Tauri] Builder setup (using TauriBuild module)
177		// ---------------------------------------------------------------------
178		let Builder = TauriBuildFn();
179
180		Builder
181			.plugin(LoggingPluginFn(log_level))
182			.plugin(LocalhostPluginFn(ServerPort))
183			.manage(AppStateArcForClosure.clone())
184			.setup({
185				let LocalhostUrl = LocalhostUrl.clone();
186				move |app:&mut App| {
187					info!("[Lifecycle] [Setup] Setup hook started.");
188					debug!("[Lifecycle] [Setup] LocalhostUrl={}", LocalhostUrl);
189
190					let AppHandle = app.handle().clone();
191					TraceStep!("[Lifecycle] [Setup] AppHandle acquired.");
192
193					// ---------------------------------------------------------
194					// Setup application lifecycle through AppLifecycle module
195					// ---------------------------------------------------------
196					let AppStateArcFromClosure = AppStateArcForClosure.clone();
197					
198					if let Err(e) = AppLifecycleSetup(
199						app,
200						AppHandle.clone(),
201						LocalhostUrl.clone(),
202						SchedulerForClosure.clone(),
203						AppStateArcFromClosure,
204					) {
205						error!("[Lifecycle] [Setup] Failed to setup lifecycle: {}", e);
206					}
207
208					Ok(())
209				}
210			})
211			.plugin(tauri_plugin_dialog::init())
212			.plugin(tauri_plugin_fs::init())
213			.invoke_handler(tauri::generate_handler![
214				crate::Binary::Tray::SwitchTrayIcon::SwitchTrayIcon,
215				crate::Binary::IPC::WorkbenchConfigurationCommand::MountainGetWorkbenchConfiguration,
216				Command::TreeView::GetTreeViewChildren,
217				Command::LanguageFeature::MountainProvideHover,
218				Command::LanguageFeature::MountainProvideCompletions,
219				Command::LanguageFeature::MountainProvideDefinition,
220				Command::LanguageFeature::MountainProvideReferences,
221				Command::SourceControlManagement::GetAllSourceControlManagementState,
222				Command::Keybinding::GetResolvedKeybinding,
223				Track::FrontendCommand::DispatchFrontendCommand,
224				Track::UIRequest::ResolveUIRequest,
225				Track::Webview::MountainWebviewPostMessageFromGuest,
226				crate::Binary::IPC::MessageReceiveCommand::MountainIPCReceiveMessage,
227				crate::Binary::IPC::StatusGetCommand::MountainIPCGetStatus,
228				crate::Binary::IPC::InvokeCommand::MountainIPCInvoke,
229				crate::Binary::IPC::WindConfigurationCommand::MountainGetWindDesktopConfiguration,
230				crate::Binary::IPC::ConfigurationUpdateCommand::MountainUpdateConfigurationFromWind,
231				crate::Binary::IPC::ConfigurationSyncCommand::MountainSynchronizeConfiguration,
232				crate::Binary::IPC::ConfigurationStatusCommand::MountainGetConfigurationStatus,
233				crate::Binary::IPC::IPCStatusCommand::MountainGetIPCStatus,
234				crate::Binary::IPC::IPCStatusHistoryCommand::MountainGetIPCStatusHistory,
235				crate::Binary::IPC::IPCStatusReportingStartCommand::MountainStartIPCStatusReporting,
236				crate::Binary::IPC::PerformanceStatsCommand::MountainGetPerformanceStats,
237				crate::Binary::IPC::CacheStatsCommand::MountainGetCacheStats,
238				crate::Binary::IPC::CollaborationSessionCommand::MountainCreateCollaborationSession,
239				crate::Binary::IPC::CollaborationSessionCommand::MountainGetCollaborationSessions,
240				crate::Binary::IPC::DocumentSyncCommand::MountainAddDocumentForSync,
241				crate::Binary::IPC::DocumentSyncCommand::MountainGetSyncStatus,
242				crate::Binary::IPC::UpdateSubscriptionCommand::MountainSubscribeToUpdates,
243				crate::Binary::IPC::ConfigurationDataCommand::GetConfigurationData,
244				crate::Binary::IPC::ConfigurationDataCommand::SaveConfigurationData,
245			])
246			.build(tauri::generate_context!())
247			.expect("FATAL: Error while building Mountain Tauri application")
248			.run(move |app_handle:&tauri::AppHandle, event:tauri::RunEvent| {
249				// Debug-only: log selected lifecycle events
250				if cfg!(debug_assertions) {
251					match &event {
252						RunEvent::MainEventsCleared => {},
253						RunEvent::WindowEvent { .. } => {},
254						_ => debug!("[Lifecycle] [RunEvent] {:?}", event),
255					}
256				}
257
258				if let RunEvent::ExitRequested { api, .. } = event {
259					warn!("[Lifecycle] [Shutdown] Exit requested. Starting graceful shutdown...");
260					api.prevent_exit();
261
262					let SchedulerHandle = Scheduler.clone();
263					let app_handle_clone = app_handle.clone();
264
265					tokio::spawn(async move {
266						debug!("[Lifecycle] [Shutdown] Shutting down ApplicationRunTime...");
267						let _ = RuntimeShutdownFn(&app_handle_clone).await;
268
269						debug!("[Lifecycle] [Shutdown] Stopping Echo scheduler...");
270						let _ = SchedulerShutdownFn(SchedulerHandle).await;
271
272						info!("[Lifecycle] [Shutdown] Done. Exiting process.");
273						app_handle_clone.exit(0);
274					});
275				}
276			});
277
278		info!("[Lifecycle] [Exit] Mountain application has shut down.");
279	});
280}