Files
clash-verge-rev-lite/src-tauri/src/feat/window.rs
2025-11-12 23:28:49 +03:00

275 lines
8.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#[cfg(target_os = "macos")]
use crate::AppHandleManager;
use crate::{
config::Config,
core::{event_driven_proxy::EventDrivenProxyManager, handle, sysopt, CoreManager},
logging,
module::mihomo::MihomoManager,
utils::logging::Type,
};
/// Open or close the dashboard window
#[allow(dead_code)]
pub fn open_or_close_dashboard() {
open_or_close_dashboard_internal(false)
}
/// Open or close the dashboard window (hotkey call, dispatched to main thread)
#[allow(dead_code)]
pub fn open_or_close_dashboard_hotkey() {
open_or_close_dashboard_internal(true)
}
/// Internal implementation for opening/closing dashboard
fn open_or_close_dashboard_internal(bypass_debounce: bool) {
use crate::process::AsyncHandler;
use crate::utils::window_manager::WindowManager;
log::info!(target: "app", "Attempting to open/close dashboard (bypass debounce: {bypass_debounce})");
// 热键调用调度到主线程执行,避免 WebView 创建死锁
if bypass_debounce {
log::info!(target: "app", "Hotkey invoked, dispatching window operation to main thread");
AsyncHandler::spawn(move || async move {
log::info!(target: "app", "Executing hotkey window operation on main thread");
if crate::module::lightweight::is_in_lightweight_mode() {
log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode");
crate::module::lightweight::exit_lightweight_mode();
log::info!(target: "app", "Creating new window after exiting lightweight mode");
let result = WindowManager::show_main_window();
log::info!(target: "app", "Window operation result: {result:?}");
return;
}
let result = WindowManager::toggle_main_window();
log::info!(target: "app", "Window toggle result: {result:?}");
});
return;
}
if crate::module::lightweight::is_in_lightweight_mode() {
log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode");
crate::module::lightweight::exit_lightweight_mode();
log::info!(target: "app", "Creating new window after exiting lightweight mode");
let result = WindowManager::show_main_window();
log::info!(target: "app", "Window operation result: {result:?}");
return;
}
let result = WindowManager::toggle_main_window();
log::info!(target: "app", "Window toggle result: {result:?}");
}
/// 异步优化的应用退出函数
pub fn quit() {
use crate::process::AsyncHandler;
logging!(debug, Type::System, true, "Start exit process");
// 获取应用句柄并设置退出标志
let app_handle = handle::Handle::global().app_handle().unwrap();
handle::Handle::global().set_is_exiting();
EventDrivenProxyManager::global().notify_app_stopping();
// 优先关闭窗口,提供立即反馈
if let Some(window) = handle::Handle::global().get_window() {
let _ = window.hide();
log::info!(target: "app", "Window hidden");
}
// 使用异步任务处理资源清理,避免阻塞
AsyncHandler::spawn(move || async move {
logging!(
info,
Type::System,
true,
"Start asynchronous resource cleanup"
);
let cleanup_result = clean_async().await;
logging!(
info,
Type::System,
true,
"Resource cleanup completed, exit code: {}",
if cleanup_result { 0 } else { 1 }
);
app_handle.exit(if cleanup_result { 0 } else { 1 });
});
}
async fn clean_async() -> bool {
use tokio::time::{timeout, Duration};
logging!(
info,
Type::System,
true,
"Start executing asynchronous cleanup..."
);
// 1. 处理TUN模式
let tun_task = async {
if Config::verge().data().enable_tun_mode.unwrap_or(false) {
let disable_tun = serde_json::json!({
"tun": {
"enable": false
}
});
match timeout(
Duration::from_secs(2),
MihomoManager::global().patch_configs(disable_tun),
)
.await
{
Ok(_) => {
log::info!(target: "app", "TUN mode disabled");
true
}
Err(_) => {
log::warn!(target: "app", "Timeout disabling TUN mode");
false
}
}
} else {
true
}
};
// 2. 系统代理重置
let proxy_task = async {
match timeout(
Duration::from_secs(3),
sysopt::Sysopt::global().reset_sysproxy(),
)
.await
{
Ok(_) => {
log::info!(target: "app", "System proxy reset");
true
}
Err(_) => {
log::warn!(target: "app", "Timeout resetting system proxy");
false
}
}
};
// 3. 核心服务停止
let core_task = async {
match timeout(Duration::from_secs(3), CoreManager::global().stop_core()).await {
Ok(_) => {
log::info!(target: "app", "Core service stopped");
true
}
Err(_) => {
log::warn!(target: "app", "Timeout stopping core service");
false
}
}
};
// 4. DNS恢复仅macOS
#[cfg(target_os = "macos")]
let dns_task = async {
match timeout(
Duration::from_millis(1000),
crate::utils::resolve::restore_public_dns(),
)
.await
{
Ok(_) => {
log::info!(target: "app", "DNS settings restored");
true
}
Err(_) => {
log::warn!(target: "app", "Timeout restoring DNS settings");
false
}
}
};
// 并行执行所有清理任务
let (tun_success, proxy_success, core_success) = tokio::join!(tun_task, proxy_task, core_task);
#[cfg(target_os = "macos")]
let dns_success = dns_task.await;
#[cfg(not(target_os = "macos"))]
let dns_success = true;
let all_success = tun_success && proxy_success && core_success && dns_success;
logging!(
info,
Type::System,
true,
"Asynchronous cleanup completed - TUN: {}, Proxy: {}, Core: {}, DNS: {}, Overall: {}",
tun_success,
proxy_success,
core_success,
dns_success,
all_success
);
all_success
}
pub fn clean() -> bool {
use crate::process::AsyncHandler;
let (tx, rx) = std::sync::mpsc::channel();
AsyncHandler::spawn(move || async move {
logging!(info, Type::System, true, "Start executing cleanup...");
// 使用已有的异步清理函数
let cleanup_result = clean_async().await;
// 发送结果
let _ = tx.send(cleanup_result);
});
match rx.recv_timeout(std::time::Duration::from_secs(8)) {
Ok(result) => {
logging!(
info,
Type::System,
true,
"Cleanup completed, result: {}",
result
);
result
}
Err(_) => {
logging!(
warn,
Type::System,
true,
"Cleanup timed out, returning success to avoid blocking"
);
true
}
}
}
#[cfg(target_os = "macos")]
pub fn hide() {
use crate::module::lightweight::add_light_weight_timer;
let enable_auto_light_weight_mode = Config::verge()
.data()
.enable_auto_light_weight_mode
.unwrap_or(false);
if enable_auto_light_weight_mode {
add_light_weight_timer();
}
if let Some(window) = handle::Handle::global().get_window() {
if window.is_visible().unwrap_or(false) {
let _ = window.hide();
}
}
AppHandleManager::global().set_activation_policy_accessory();
}