Skip to main content

Mountain/ApplicationState/State/FeatureState/LifecyclePhase/
LifecyclePhaseState.rs

1use std::sync::{Arc, Mutex as StandardMutex};
2
3use tokio::sync::Notify;
4use CommonLibrary::IPC::SkyEvent::SkyEvent;
5
6use crate::{IPC::SkyEmit::LogSkyEmit, dev_log};
7
8/// Application lifecycle phases (mirrors VS Code LifecyclePhase).
9/// 1 = Starting, 2 = Ready, 3 = Restored, 4 = Eventually
10pub type Phase = u8;
11
12/// Tracks the current application lifecycle phase.
13/// `PhaseNotify` fires every time the phase advances so `LifecycleWhenPhase`
14/// can await it instead of polling at 100 ms intervals.
15#[derive(Clone)]
16pub struct LifecyclePhaseState {
17	CurrentPhase:Arc<StandardMutex<Phase>>,
18
19	/// Fired (notify_waiters) on every forward phase transition.
20	pub PhaseNotify:Arc<Notify>,
21}
22
23impl Default for LifecyclePhaseState {
24	fn default() -> Self {
25		dev_log!(
26			"lifecycle",
27			"[LifecyclePhaseState] Initializing default lifecycle state (phase 1: Starting)..."
28		);
29
30		Self {
31			CurrentPhase:Arc::new(StandardMutex::new(1)),
32
33			PhaseNotify:Arc::new(Notify::new()),
34		}
35	}
36}
37
38impl LifecyclePhaseState {
39	/// Return the current lifecycle phase.
40	pub fn GetPhase(&self) -> Phase { self.CurrentPhase.lock().ok().map(|Guard| *Guard).unwrap_or(1) }
41
42	/// Advance the lifecycle phase. Only advances forward - never backwards.
43	pub fn SetPhase(&self, NewPhase:Phase) {
44		if let Ok(mut Guard) = self.CurrentPhase.lock() {
45			if NewPhase > *Guard {
46				dev_log!("lifecycle", "[LifecyclePhaseState] Phase advanced: {} → {}", *Guard, NewPhase);
47
48				*Guard = NewPhase;
49
50				// Wake all `LifecycleWhenPhase` waiters immediately.
51				self.PhaseNotify.notify_waiters();
52			}
53		}
54	}
55
56	/// Advance the phase and emit a `sky://lifecycle/phaseChanged` Tauri
57	/// event so the workbench (subscribed via
58	/// `TauriChannel("lifecycle").listen("onDidChangePhase")`) can gate
59	/// long-running services (extension discovery, telemetry, heavy
60	/// providers) until the editor is fully restored. Mirrors VS Code's
61	/// `ILifecycleService.onDidChangePhase` signal.
62	pub fn AdvanceAndBroadcast<R:tauri::Runtime>(&self, NewPhase:Phase, ApplicationHandle:&tauri::AppHandle<R>) {
63		// Local `use tauri::Emitter` removed - now routed through
64		// `LogSkyEmit` which carries the trait import internally.
65		let Previous = self.GetPhase();
66
67		if NewPhase <= Previous {
68			return;
69		}
70
71		self.SetPhase(NewPhase);
72
73		let Label = match NewPhase {
74			1 => "Starting",
75
76			2 => "Ready",
77
78			3 => "Restored",
79
80			4 => "Eventually",
81
82			_ => "Unknown",
83		};
84
85		if let Err(Error) = LogSkyEmit(
86			ApplicationHandle,
87			SkyEvent::LifecyclePhaseChanged.AsStr(),
88			serde_json::json!({
89				"phase": NewPhase,
90				"previous": Previous,
91				"label": Label,
92			}),
93		) {
94			dev_log!(
95				"lifecycle",
96				"warn: [LifecyclePhaseState] sky://lifecycle/phaseChanged emit failed: {}",
97				Error
98			);
99		}
100	}
101}