//! 应用启动初始化 —— 从 lib.rs 的 setup 闭包拆出,按子系统分组。 //! //! 各子系统职责边界: //! - 日志:LogManager(全局日志) //! - 代理:MihomoManager + 自动启动 //! - 监控:MonitorKernel + NetworkMonitor + 自动启动 //! - 下载:DownloadEngine + 扩展 HTTP API 服务 //! - 剪贴板:ClipboardManager + 快捷键 + 预创建弹窗 //! - 快速面板:快捷键 + 预创建弹窗 + 文件索引 //! - 托盘:自定义菜单窗口 //! - 进程:监控线程 use std::sync::Arc; use tauri::{App, Manager, Wry}; use crate::download_engine::{DownloadEngine, ExtensionServer}; use crate::logger::LogManager; use crate::mihomo_manager::MihomoManager; use crate::monitor_kernel::{MonitorKernel, check_and_relaunch_if_needed}; use crate::network_monitor::NetworkMonitor; use crate::process_manager::{ProcessManager, start_monitoring_thread}; /// 应用启动初始化入口(setup 闭包调用)。 /// 初始化顺序即依赖顺序:日志 → 数据目录 → 各管理器 → 托盘 → 进程监控 → 自动启动。 pub fn init(app: &mut App) -> Result<(), Box> { // ===== 日志系统:{app_data_dir}/logs/ ===== let log_dir = app .path() .app_data_dir() .unwrap_or_else(|_| std::path::PathBuf::from(".")) .join("logs"); let log_manager = LogManager::new(log_dir); // 注册为 Tauri State(供 log_* 命令),同时安装进程级全局日志器(供后端模块 log_line 使用) crate::logger::install_global(log_manager.clone()); app.manage(log_manager); // ===== 数据目录:{app_data_dir}/ ===== let app_data_dir = app .path() .app_data_dir() .unwrap_or_else(|_| std::path::PathBuf::from(".")); // 永久提权检查:如果标志已设置且当前非管理员,以管理员权限重启自身并退出 // 必须在所有模块初始化之前执行(此时无资源需要清理) if check_and_relaunch_if_needed(&app_data_dir) { std::process::exit(0); } // ===== 代理模块:MihomoManager ===== let mihomo = MihomoManager::new(app_data_dir.clone()); app.manage(mihomo); // ===== 监控模块:MonitorKernel(硬件)+ NetworkMonitor(网速) ===== let monitor = MonitorKernel::new(app_data_dir.clone()); app.manage(monitor); // 网速采样不依赖提权,应用启动即开始 let network_monitor = Arc::new(NetworkMonitor::new()); app.manage(network_monitor.clone()); network_monitor.start(app.handle().clone()); // ===== 下载模块:DownloadEngine + 扩展 HTTP API 服务 ===== let engine = DownloadEngine::new(app_data_dir.join("downloader"), app.handle().clone()); let settings = engine.get_settings(); app.manage(engine.clone()); let server_engine = engine.clone(); let server_port = settings.extension_port; let server_secret = settings.extension_secret.clone(); let server_app = app.handle().clone(); tauri::async_runtime::spawn(async move { ExtensionServer::start(server_engine, server_port, server_secret, server_app).await; }); // ===== 剪贴板模块:监听 + 快捷键 + 预创建弹窗 ===== let clipboard = crate::clipboard::ClipboardManager::new(app_data_dir.clone()); // 应用启动时若已启用则自动开始监听 if clipboard.get_settings().enabled { clipboard.start(&app.handle()); } // 应用启动时注册快捷弹窗全局快捷键(共享工具模块) let shortcut = clipboard.get_settings().shortcut.clone(); if !shortcut.trim().is_empty() { let app_handle = app.handle().clone(); if let Err(e) = crate::shortcut::register_shortcut(&app_handle, "剪贴板", &shortcut, |a| { crate::clipboard::popup::show_popup(a) }) { crate::logger::log_error("clipboard", &format!("快捷键注册失败: {}", e)); } // 预创建弹窗窗口(隐藏),首次按快捷键时直接 show,避免首次创建时序问题 crate::clipboard::popup::ensure_popup_window(&app_handle); // 同时预创建独立预览窗口(隐藏),弹窗悬停条目时直接显示 crate::clipboard::popup::ensure_preview_window(&app_handle); } app.manage(clipboard); // ===== 快速面板:快捷键 + 预创建弹窗 ===== // defaultEnabled:true 假设启用;用户在设置页禁用模块时由前端 onDisable 钩子注销快捷键。 // 文件索引 DB 连接改为懒加载(首次搜索/构建时由 commands 中的 ensure_initialized 触发), // 避免应用启动时即打开 SQLite 连接,降低启动 IO 开销。 let qp_settings = crate::quickpanel::load_settings(&app.handle()); if !qp_settings.shortcut.trim().is_empty() { let app_handle = app.handle().clone(); if let Err(e) = crate::shortcut::register_shortcut( &app_handle, "快速面板", &qp_settings.shortcut, |a| crate::quickpanel::popup::show_popup(a), ) { crate::logger::log_error("quickpanel", &format!("快捷键注册失败: {}", e)); } // 预创建弹窗窗口(隐藏),首次按快捷键时直接 show,避免首次创建时序问题 crate::quickpanel::ensure_window(&app_handle); } // ===== 托盘菜单 ===== crate::tray_menu::create_tray_menu(app.handle())?; // ===== 进程监控线程 ===== start_monitoring_thread(app.handle().clone()); // ===== 代理:自动切换节点后台调度(独立于模块激活状态) ===== crate::mihomo_manager::start_auto_switch_loop(app.handle().clone()); // ===== 自动启动(随应用启动,不依赖模块启用) ===== // mihomo:用户在设置中开启"自动启动"时随应用启动 if let Some(mihomo) = app.try_state::() { if let Some(pm) = app.try_state::() { mihomo.auto_start_on_launch(app.handle(), &pm); } } // monitor Kernel:用户在设置中开启"自动启动"时随应用启动 if let Some(monitor) = app.try_state::() { monitor.auto_start_on_launch(app.handle()); } // 截图快捷键由前端 screenshotStore 启动时调用 screenshot_register_shortcut 注册 // (支持自定义,默认 Ctrl+Alt+A),此处不再硬编码注册 Ok(()) }