性能优化
This commit is contained in:
+98
-156
@@ -1,8 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use tauri::Emitter;
|
||||
use tauri::Manager;
|
||||
|
||||
mod clipboard;
|
||||
mod constants;
|
||||
mod download_engine;
|
||||
mod logger;
|
||||
mod mihomo_manager;
|
||||
@@ -12,17 +11,20 @@ mod osd_window;
|
||||
mod process_manager;
|
||||
mod quickpanel;
|
||||
mod screenshot;
|
||||
mod setup;
|
||||
mod shortcut;
|
||||
mod snap_fix;
|
||||
mod tray_menu;
|
||||
mod win32_util;
|
||||
|
||||
use download_engine::{
|
||||
DownloadEngine, ExtensionServer,
|
||||
DownloadEngine,
|
||||
downloader_add_task, downloader_check_url, downloader_get_extension_info, downloader_get_settings, downloader_get_tasks,
|
||||
downloader_open_dir, downloader_open_url, downloader_pause_task, downloader_remove_task,
|
||||
downloader_resume_task, downloader_save_settings, downloader_status,
|
||||
};
|
||||
use logger::{
|
||||
clear_logs, get_log_info, get_logs, log_message, LogManager,
|
||||
log_clear, log_info_state, log_list, log_message,
|
||||
};
|
||||
use mihomo_manager::{
|
||||
proxy_activate_profile, proxy_check_kernel_update, proxy_clear_system_proxy, proxy_close_connection, proxy_delete_profile,
|
||||
@@ -37,21 +39,22 @@ use monitor_kernel::{
|
||||
monitor_set_hardware_config, monitor_start, monitor_start_elevated, monitor_status,
|
||||
monitor_stop, MonitorKernel,
|
||||
};
|
||||
use network_monitor::{network_monitor_status, NetworkMonitor};
|
||||
use network_monitor::network_status;
|
||||
use osd_window::{
|
||||
osd_apply_overlay_style, osd_begin_drag, osd_set_click_through, osd_set_topmost,
|
||||
osd_start_drag_watch, osd_start_topmost_watch, osd_stop_watch,
|
||||
};
|
||||
use process_manager::{
|
||||
get_all_process_status, get_process_status, start_monitoring_thread, start_process,
|
||||
stop_all_processes, stop_process, ProcessManager,
|
||||
process_all_status, process_start, process_status,
|
||||
process_stop, process_stop_all, ProcessManager,
|
||||
};
|
||||
use screenshot::commands::{
|
||||
screenshot_capture_fullscreen, screenshot_capture_window, screenshot_clear_fullscreen,
|
||||
screenshot_compose_copy, screenshot_copy_image, screenshot_crop_copy_stored,
|
||||
screenshot_crop_stored, screenshot_cursor_pos, screenshot_disable_transitions,
|
||||
screenshot_enum_windows, screenshot_fullscreen_png, screenshot_get_editor_image,
|
||||
screenshot_get_fullscreen_bmp, screenshot_register_shortcut, screenshot_save_png,
|
||||
screenshot_crop_stored, screenshot_cursor_pos, screenshot_delete_cache,
|
||||
screenshot_disable_transitions, screenshot_enum_windows, screenshot_fullscreen_png,
|
||||
screenshot_get_editor_image, screenshot_get_fullscreen_bmp, screenshot_load_cache,
|
||||
screenshot_register_shortcut, screenshot_save_cache, screenshot_save_png,
|
||||
screenshot_set_editor_image, screenshot_unregister_shortcut, screenshot_window_from_point,
|
||||
};
|
||||
use clipboard::{
|
||||
@@ -75,35 +78,73 @@ use quickpanel::{
|
||||
use tray_menu::{tray_menu_action, tray_menu_hide, tray_menu_ready};
|
||||
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
fn quit_app(app: tauri::AppHandle) {
|
||||
// 资源清理统一收敛到 RunEvent::ExitRequested(覆盖所有退出路径),此处仅请求退出
|
||||
app.exit(0);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn quit_app(
|
||||
state: tauri::State<'_, ProcessManager>,
|
||||
mihomo: tauri::State<'_, MihomoManager>,
|
||||
engine: tauri::State<'_, DownloadEngine>,
|
||||
monitor: tauri::State<'_, MonitorKernel>,
|
||||
clipboard: tauri::State<'_, ClipboardManager>,
|
||||
app: tauri::AppHandle,
|
||||
) {
|
||||
// 退出前清理系统代理,避免遗留导致网络问题
|
||||
mihomo.cleanup_on_exit();
|
||||
// 退出前保存下载引擎状态
|
||||
engine.cleanup_on_exit();
|
||||
// 停止提权 Kernel(普通权限由 stop_all 统一清理,提权 Kernel 需通过 /shutdown)
|
||||
tauri::async_runtime::block_on(monitor.cleanup_on_exit(&app));
|
||||
// 停止剪贴板监听线程
|
||||
clipboard.stop();
|
||||
// 停止所有子进程(同步 kill + 带超时的 wait,确保进程真正终止)
|
||||
state.stop_all();
|
||||
// 通过 app.exit 触发 RunEvent::ExitRequested,统一退出路径
|
||||
app.exit(0);
|
||||
/// 导出 tauri-specta 生成的 TypeScript 类型与命令绑定(仅 debug 构建,开发时自动刷新)。
|
||||
/// 覆盖 proxy / quickpanel / clipboard / download_engine / screenshot 五个模块;
|
||||
/// 豁免清单(返回 serde_json::Value 或 tauri::ipc::Response/Request,specta 无法生成):
|
||||
/// proxy_version / proxy_get_proxies / proxy_get_connections / proxy_patch_configs、
|
||||
/// downloader_status / downloader_get_extension_info、
|
||||
/// screenshot_get_fullscreen_bmp(返回 ipc::Response)/ screenshot_compose_copy(接收 ipc::Request)。
|
||||
#[cfg(debug_assertions)]
|
||||
fn export_bindings() {
|
||||
use specta_typescript::Typescript;
|
||||
use tauri_specta::{Builder, ErrorHandlingMode, collect_commands};
|
||||
|
||||
Builder::<tauri::Wry>::new()
|
||||
// 全局把 u64/i64 映射为 number(项目取值均在 JS 安全整数范围:大小/时间戳/limit)
|
||||
.dangerously_cast_bigints_to_number()
|
||||
// 生成命令失败时直接 throw,与原生 invoke 一致,前端无需解包 helper
|
||||
.error_handling(ErrorHandlingMode::Throw)
|
||||
.commands(collect_commands![
|
||||
// proxy(20)
|
||||
proxy_activate_profile, proxy_check_kernel_update, proxy_clear_system_proxy,
|
||||
proxy_close_connection, proxy_delete_profile, proxy_get_settings,
|
||||
proxy_get_system_proxy, proxy_import_profile, proxy_install_kernel,
|
||||
proxy_kernel_info, proxy_restart, proxy_save_settings,
|
||||
proxy_select_proxy, proxy_set_system_proxy, proxy_start, proxy_status, proxy_stop,
|
||||
proxy_test_delay, proxy_update_kernel, proxy_update_profile,
|
||||
// quickpanel(22)
|
||||
quickpanel_get_settings, quickpanel_save_settings, quickpanel_register_shortcut,
|
||||
quickpanel_unregister_shortcut, quickpanel_show_popup, quickpanel_hide_popup,
|
||||
quickpanel_show_window, quickpanel_lock_screen, quickpanel_init_file_index,
|
||||
quickpanel_build_file_index, quickpanel_search_files, quickpanel_file_index_stats,
|
||||
quickpanel_scan_apps, quickpanel_get_app_icon, quickpanel_clear_app_icon_cache,
|
||||
quickpanel_reveal_in_explorer, quickpanel_open_file, quickpanel_get_special_locations,
|
||||
quickpanel_open_special, quickpanel_delete_file, quickpanel_run_custom_command,
|
||||
quickpanel_run_system_command,
|
||||
// clipboard(20)
|
||||
clipboard_get_history, clipboard_get_pinned, clipboard_search, clipboard_get_item,
|
||||
clipboard_set_pinned, clipboard_delete, clipboard_clear, clipboard_copy_back,
|
||||
clipboard_count, clipboard_get_settings, clipboard_save_settings, clipboard_status,
|
||||
clipboard_start, clipboard_stop, clipboard_register_shortcut,
|
||||
clipboard_unregister_shortcut, clipboard_show_popup, clipboard_hide_popup,
|
||||
clipboard_show_window, clipboard_paste_to_target,
|
||||
// download_engine(10,豁免 2)
|
||||
downloader_get_tasks, downloader_check_url, downloader_add_task, downloader_pause_task,
|
||||
downloader_resume_task, downloader_remove_task, downloader_get_settings,
|
||||
downloader_save_settings, downloader_open_dir, downloader_open_url,
|
||||
// screenshot(19,豁免 2:get_fullscreen_bmp 返回 ipc::Response、compose_copy 接收 ipc::Request)
|
||||
screenshot_disable_transitions, screenshot_register_shortcut,
|
||||
screenshot_unregister_shortcut, screenshot_capture_fullscreen, screenshot_fullscreen_png,
|
||||
screenshot_clear_fullscreen, screenshot_crop_stored, screenshot_crop_copy_stored,
|
||||
screenshot_window_from_point, screenshot_cursor_pos, screenshot_enum_windows,
|
||||
screenshot_capture_window, screenshot_set_editor_image, screenshot_get_editor_image,
|
||||
screenshot_copy_image, screenshot_save_png,
|
||||
screenshot_save_cache, screenshot_load_cache, screenshot_delete_cache,
|
||||
])
|
||||
.export(Typescript::default(), "../src/lib/bindings.ts")
|
||||
.expect("failed to export bindings");
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
#[cfg(debug_assertions)]
|
||||
export_bindings();
|
||||
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_autostart::Builder::new().build())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
@@ -119,17 +160,16 @@ pub fn run() {
|
||||
)
|
||||
.manage(ProcessManager::new())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
greet,
|
||||
quit_app,
|
||||
start_process,
|
||||
stop_process,
|
||||
get_process_status,
|
||||
get_all_process_status,
|
||||
stop_all_processes,
|
||||
process_start,
|
||||
process_stop,
|
||||
process_status,
|
||||
process_all_status,
|
||||
process_stop_all,
|
||||
log_message,
|
||||
get_logs,
|
||||
clear_logs,
|
||||
get_log_info,
|
||||
log_list,
|
||||
log_clear,
|
||||
log_info_state,
|
||||
proxy_get_settings,
|
||||
proxy_save_settings,
|
||||
proxy_kernel_info,
|
||||
@@ -166,7 +206,7 @@ pub fn run() {
|
||||
monitor_set_elevate_on_launch,
|
||||
monitor_get_hardware_config,
|
||||
monitor_set_hardware_config,
|
||||
network_monitor_status,
|
||||
network_status,
|
||||
osd_apply_overlay_style,
|
||||
osd_begin_drag,
|
||||
osd_set_click_through,
|
||||
@@ -246,123 +286,15 @@ pub fn run() {
|
||||
screenshot_get_editor_image,
|
||||
screenshot_copy_image,
|
||||
screenshot_save_png,
|
||||
screenshot_save_cache,
|
||||
screenshot_load_cache,
|
||||
screenshot_delete_cache,
|
||||
screenshot_register_shortcut,
|
||||
screenshot_unregister_shortcut,
|
||||
screenshot_disable_transitions,
|
||||
screenshot_compose_copy
|
||||
])
|
||||
.setup(|app| {
|
||||
// 初始化日志系统,日志目录: {app_data_dir}/logs/
|
||||
let log_dir = app
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.unwrap_or_else(|_| std::path::PathBuf::from("."))
|
||||
.join("logs");
|
||||
app.manage(LogManager::new(log_dir));
|
||||
|
||||
// 初始化 MihomoManager,数据目录: {app_data_dir}/proxy/
|
||||
let app_data_dir = app
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.unwrap_or_else(|_| std::path::PathBuf::from("."));
|
||||
|
||||
// 永久提权检查:如果标志已设置且当前非管理员,以管理员权限重启自身并退出
|
||||
// 必须在所有模块初始化之前执行(此时无资源需要清理)
|
||||
if monitor_kernel::check_and_relaunch_if_needed(&app_data_dir) {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let mihomo = MihomoManager::new(app_data_dir.clone());
|
||||
app.manage(mihomo);
|
||||
|
||||
// 初始化 MonitorKernel,数据目录: {app_data_dir}/monitor/
|
||||
let monitor = MonitorKernel::new(app_data_dir.clone());
|
||||
app.manage(monitor);
|
||||
|
||||
// 初始化 NetworkMonitor(网速监控,独立于 ThingHK Kernel)
|
||||
// 网速采样不依赖提权,应用启动即开始
|
||||
let network_monitor = Arc::new(NetworkMonitor::new());
|
||||
app.manage(network_monitor.clone());
|
||||
network_monitor.start(app.handle().clone());
|
||||
|
||||
// 初始化 DownloadEngine,数据目录: {app_data_dir}/downloader/
|
||||
let engine = DownloadEngine::new(
|
||||
app_data_dir.join("downloader"),
|
||||
app.handle().clone(),
|
||||
);
|
||||
let settings = engine.get_settings();
|
||||
app.manage(engine.clone());
|
||||
|
||||
// 启动扩展 HTTP API 服务器
|
||||
let server_engine = engine.clone();
|
||||
let server_port = settings.extension_port;
|
||||
let server_secret = settings.extension_secret.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
ExtensionServer::start(server_engine, server_port, server_secret).await;
|
||||
});
|
||||
|
||||
// 初始化 ClipboardManager,数据目录: {app_data_dir}/clipboard/
|
||||
let 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) = clipboard::popup::register_shortcut(&app_handle, &shortcut) {
|
||||
eprintln!("[clipboard] 快捷键注册失败: {}", e);
|
||||
}
|
||||
// 预创建弹窗窗口(隐藏),首次按快捷键时直接 show,避免首次创建时序问题
|
||||
clipboard::popup::ensure_popup_window(&app_handle);
|
||||
}
|
||||
app.manage(clipboard);
|
||||
|
||||
// 快速面板:应用启动时注册全局快捷键 + 预创建隐藏窗口。
|
||||
// defaultEnabled:true 假设启用;用户在设置页禁用模块时由前端 onDisable 钩子注销快捷键。
|
||||
let qp_settings = quickpanel::load_settings(&app.handle());
|
||||
if !qp_settings.shortcut.trim().is_empty() {
|
||||
let app_handle = app.handle().clone();
|
||||
if let Err(e) = quickpanel::register_shortcut(&app_handle, &qp_settings.shortcut) {
|
||||
eprintln!("[quickpanel] 快捷键注册失败: {}", e);
|
||||
}
|
||||
// 预创建弹窗窗口(隐藏),首次按快捷键时直接 show,避免首次创建时序问题
|
||||
quickpanel::ensure_window(&app_handle);
|
||||
}
|
||||
// 初始化文件索引数据库(不立即构建,由前端设置页或首次唤起时触发)
|
||||
quickpanel::file_index::init(&app.handle());
|
||||
|
||||
// 自定义托盘菜单(代理/OSD/Kernel/下载/设置/退出)
|
||||
tray_menu::create_tray_menu(app.handle())?;
|
||||
|
||||
// 启动进程监控线程
|
||||
start_monitoring_thread(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>() {
|
||||
let monitor = monitor.inner().clone();
|
||||
let app_handle = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
match monitor.start_with_subscription(&app_handle).await {
|
||||
Ok(info) => eprintln!("[monitor] 自动启动成功, pid={:?}", info.pid),
|
||||
Err(e) => eprintln!("[monitor] 自动启动跳过: {}", e),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 截图快捷键由前端 screenshotStore 启动时调用 screenshot_register_shortcut 注册
|
||||
// (支持自定义,默认 Ctrl+Alt+A),此处不再硬编码注册
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.setup(setup::init)
|
||||
.on_window_event(|window, event| {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
window.hide().ok();
|
||||
@@ -380,7 +312,17 @@ pub fn run() {
|
||||
engine.cleanup_on_exit();
|
||||
}
|
||||
if let Some(monitor) = app.try_state::<MonitorKernel>() {
|
||||
tauri::async_runtime::block_on(monitor.cleanup_on_exit(app));
|
||||
// cleanup_on_exit 是 async;在事件循环回调中直接 block_on 有 panic 风险且阻塞退出,
|
||||
// 放到独立 OS 线程执行并限时等待(与托盘旧实现同模式)。
|
||||
let app_clone = app.clone();
|
||||
let monitor_clone = monitor.inner().clone();
|
||||
std::thread::spawn(move || {
|
||||
tauri::async_runtime::block_on(async move {
|
||||
monitor_clone.cleanup_on_exit(&app_clone).await;
|
||||
});
|
||||
})
|
||||
.join()
|
||||
.ok();
|
||||
}
|
||||
if let Some(clip) = app.try_state::<ClipboardManager>() {
|
||||
clip.stop();
|
||||
|
||||
Reference in New Issue
Block a user