150 lines
6.7 KiB
Rust
150 lines
6.7 KiB
Rust
//! 应用启动初始化 —— 从 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::music::MusicManager;
|
||
use crate::network_monitor::NetworkMonitor;
|
||
use crate::process_manager::{ProcessManager, start_monitoring_thread};
|
||
|
||
/// 应用启动初始化入口(setup 闭包调用)。
|
||
/// 初始化顺序即依赖顺序:日志 → 数据目录 → 各管理器 → 托盘 → 进程监控 → 自动启动。
|
||
pub fn init(app: &mut App<Wry>) -> Result<(), Box<dyn std::error::Error>> {
|
||
// ===== 日志系统:{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);
|
||
|
||
// ===== 音乐模块:MusicManager(Python 运行时 + 桥接进程) =====
|
||
// 仅注册状态,不主动启动桥接(由前端模块激活/首次请求时按需拉起)
|
||
let music = MusicManager::new(app_data_dir.clone());
|
||
// 注入 AppHandle:桥接 reader 线程把下载事件行转发给前端
|
||
music.set_app(app.handle().clone());
|
||
app.manage(music);
|
||
|
||
// 网速采样不依赖提权,应用启动即开始
|
||
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::<MihomoManager>() {
|
||
if let Some(pm) = app.try_state::<ProcessManager>() {
|
||
mihomo.auto_start_on_launch(app.handle(), &pm);
|
||
}
|
||
}
|
||
|
||
// monitor Kernel:用户在设置中开启"自动启动"时随应用启动
|
||
if let Some(monitor) = app.try_state::<MonitorKernel>() {
|
||
monitor.auto_start_on_launch(app.handle());
|
||
}
|
||
|
||
// 截图快捷键由前端 screenshotStore 启动时调用 screenshot_register_shortcut 注册
|
||
// (支持自定义,默认 Ctrl+Alt+A),此处不再硬编码注册
|
||
|
||
Ok(())
|
||
}
|