diff --git a/src-tauri/src/core_runtime.rs b/src-tauri/src/core_runtime.rs index 77c80a5..fa79a91 100644 --- a/src-tauri/src/core_runtime.rs +++ b/src-tauri/src/core_runtime.rs @@ -802,6 +802,7 @@ pub(crate) fn current_core_status( let install_dir = core_install_dir()?; let binary_path = find_core_binary(&install_dir); let installed = binary_path.is_some(); + let starting = process_state.is_some_and(CoreProcessState::is_starting); let managed_pid = process_state.and_then(|state| state.managed_pid()); let management_port_open = management_port.map(is_management_port_open); let process_id = match managed_pid { @@ -814,7 +815,9 @@ pub(crate) fn current_core_status( let running = process_id.is_some() && management_port_open.unwrap_or(true); let current_version = read_core_metadata(&install_dir).map(|metadata| metadata.version); - let message = if !installed { + let message = if starting { + "CPA 内核正在启动".to_string() + } else if !installed { "未安装 CPA 内核,请先安装最新版".to_string() } else if running { "CPA 内核正在运行".to_string() @@ -825,6 +828,7 @@ pub(crate) fn current_core_status( Ok(CoreStatus { installed, running, + starting, managed: managed_pid.is_some(), process_id, current_version, diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d1a6962..d618cab 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -39,7 +39,6 @@ use objc2::MainThreadMarker; use objc2_app_kit::NSEvent; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -#[cfg(target_os = "windows")] use std::sync::atomic::{AtomicBool, Ordering}; #[cfg(target_os = "macos")] use std::sync::Arc; @@ -276,6 +275,7 @@ struct AppUpdateInner { #[derive(Default)] struct CoreProcessState { child: Mutex>, + starting: AtomicBool, #[cfg(windows)] job: Mutex>, } @@ -370,6 +370,7 @@ struct CorePlatform { struct CoreStatus { installed: bool, running: bool, + starting: bool, managed: bool, process_id: Option, current_version: Option, @@ -1341,6 +1342,23 @@ impl AppUpdateState { } impl CoreProcessState { + fn new(starting: bool) -> Self { + Self { + child: Mutex::new(None), + starting: AtomicBool::new(starting), + #[cfg(windows)] + job: Mutex::new(None), + } + } + + fn is_starting(&self) -> bool { + self.starting.load(Ordering::Acquire) + } + + fn set_starting(&self, starting: bool) { + self.starting.store(starting, Ordering::Release); + } + fn managed_pid(&self) -> Option { let Ok(mut child) = self.child.lock() else { return None; @@ -1727,7 +1745,7 @@ fn main() { ) .manage(CoreDownloadState::default()) .manage(AppUpdateState::default()) - .manage(CoreProcessState::default()) + .manage(CoreProcessState::new(gui_config.start_core_on_launch)) .manage(usage::UsageCollectorState::default()) .manage(GuiConfigState::new(gui_config)) .manage(MainWindowSizeState::new(initial_window_size)) @@ -1845,9 +1863,18 @@ fn main() { let gui_config_state = core_app.state::(); let process_state = core_app.state::(); let Ok(config) = gui_config_state.snapshot() else { + process_state.set_starting(false); return; }; + if config.start_core_on_launch { + if let Ok(status) = + current_core_status(Some(process_state.inner()), Some(config.port)) + { + emit_core_status(&core_app, &status); + } + } + match auto_install_bundled_core_if_missing(&core_app) { Ok(true) => eprintln!("未检测到 CPA 内核,已自动安装内置离线版本"), Ok(false) => {} @@ -1860,6 +1887,8 @@ fn main() { } } + process_state.set_starting(false); + if let Ok(status) = current_core_status(Some(process_state.inner()), Some(config.port)) { diff --git a/src-tauri/src/tests/core_runtime.rs b/src-tauri/src/tests/core_runtime.rs index a5b74cb..b172615 100644 --- a/src-tauri/src/tests/core_runtime.rs +++ b/src-tauri/src/tests/core_runtime.rs @@ -1,6 +1,14 @@ use super::support::*; use super::*; +#[test] +fn core_process_starting_state_tracks_automatic_launch() { + let state = CoreProcessState::new(true); + assert!(state.is_starting()); + state.set_starting(false); + assert!(!state.is_starting()); +} + #[test] fn replacing_a_core_preserves_only_regular_bundled_assets() { let root = agent_test_home("bundled-assets"); diff --git a/src-tauri/src/tests/platform.rs b/src-tauri/src/tests/platform.rs index 1ac496d..36ac13b 100644 --- a/src-tauri/src/tests/platform.rs +++ b/src-tauri/src/tests/platform.rs @@ -6,6 +6,7 @@ fn windows_tray_presentation_tracks_core_state_and_busy_actions() { let mut status = CoreStatus { installed: false, running: false, + starting: false, managed: false, process_id: None, current_version: None, diff --git a/src/coreRuntime.tsx b/src/coreRuntime.tsx index 78f1057..7d9b3f0 100644 --- a/src/coreRuntime.tsx +++ b/src/coreRuntime.tsx @@ -5,6 +5,7 @@ import { listen } from '@tauri-apps/api/event'; export type CoreStatus = { installed: boolean; running: boolean; + starting: boolean; managed: boolean; processId: number | null; currentVersion: string | null; diff --git a/src/pages/Kernel.tsx b/src/pages/Kernel.tsx index c082a6b..0037b63 100644 --- a/src/pages/Kernel.tsx +++ b/src/pages/Kernel.tsx @@ -584,9 +584,10 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) { const currentVersion = coreStatus?.currentVersion ?? ''; const coreInstalled = Boolean(coreStatus?.installed); const coreRunning = Boolean(coreStatus?.running); - const busy = checkingLatest || installing || processBusy; + const coreProcessBusy = processBusy || Boolean(coreStatus?.starting); + const busy = checkingLatest || installing || coreProcessBusy; const installDisabled = busy || Boolean(coreStatus?.running); - const offlineInstallDisabled = installing || processBusy || coreRunning; + const offlineInstallDisabled = installing || coreProcessBusy || coreRunning; const computedPercent = progress?.percent ?? (progress?.total && progress.total > 0 ? (progress.downloaded / progress.total) * 100 : null); @@ -702,7 +703,7 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) {

{t('kernel.control.title')}

- {processBusy ? t('common.processing') : statusLabel} + {coreProcessBusy ? t('common.processing') : statusLabel} @@ -736,7 +737,7 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) {