diff --git a/src-tauri/src/module/lightweight.rs b/src-tauri/src/module/lightweight.rs index 40d3ff74..127c246b 100644 --- a/src-tauri/src/module/lightweight.rs +++ b/src-tauri/src/module/lightweight.rs @@ -1,6 +1,6 @@ use crate::{ config::Config, - core::{handle, timer::Timer, tray::Tray}, + core::{handle, timer::Timer}, log_err, logging, logging_error, utils::logging::Type, AppHandleManager, @@ -9,8 +9,9 @@ use crate::{ use anyhow::{Context, Result}; use delay_timer::prelude::TaskBuilder; use once_cell::sync::OnceCell; -use parking_lot::RwLock; +use parking_lot::{Mutex, RwLock}; use std::sync::Arc; +use std::time::{Duration, Instant}; use tauri::{Listener, Manager}; pub static AUTO_LIGHT_WEIGHT_MODE_INIT: OnceCell<()> = OnceCell::new(); @@ -20,10 +21,17 @@ const LIGHT_WEIGHT_TASK_UID: &str = "light_weight_task"; // 轻量模式状态标志 static IS_LIGHTWEIGHT_MODE: OnceCell>> = OnceCell::new(); +// 添加一个锁来防止并发退出轻量模式 +static EXIT_LOCK: OnceCell> = OnceCell::new(); + fn get_lightweight_mode() -> &'static Arc> { IS_LIGHTWEIGHT_MODE.get_or_init(|| Arc::new(RwLock::new(false))) } +fn get_exit_lock() -> &'static Mutex<(bool, Instant)> { + EXIT_LOCK.get_or_init(|| Mutex::new((false, Instant::now()))) +} + // 检查是否处于轻量模式 pub fn is_in_lightweight_mode() -> bool { *get_lightweight_mode().read() @@ -64,12 +72,35 @@ pub fn entry_lightweight_mode() { // 标记已进入轻量模式 set_lightweight_mode(true); let _ = cancel_light_weight_timer(); - - logging_error!(Type::Tray, true, Tray::global().update_menu()); } -// 从轻量模式恢复 +// 添加从轻量模式恢复的函数 pub fn exit_lightweight_mode() { + // 获取锁,检查是否已经有退出操作在进行中 + let mut exit_lock = get_exit_lock().lock(); + let (is_exiting, last_exit_time) = *exit_lock; + let now = Instant::now(); + + // 如果已经有一个退出操作在进行,并且距离上次退出时间不超过2秒,跳过本次退出 + if is_exiting && now.duration_since(last_exit_time) < Duration::from_secs(2) { + logging!( + warn, + Type::Lightweight, + true, + "已有退出轻量模式操作正在进行中,跳过本次请求" + ); + return; + } + + *exit_lock = (true, now); + + // 确保当前确实处于轻量模式才执行退出操作 + if !is_in_lightweight_mode() { + logging!(info, Type::Lightweight, true, "当前不在轻量模式,无需退出"); + exit_lock.0 = false; + return; + } + // 标记退出轻量模式 set_lightweight_mode(false); logging!(info, Type::Lightweight, true, "正在退出轻量模式"); @@ -77,7 +108,8 @@ pub fn exit_lightweight_mode() { // 重置UI就绪状态 crate::utils::resolve::reset_ui_ready(); - logging_error!(Type::Tray, true, Tray::global().update_menu()); + // 释放锁 + exit_lock.0 = false; } pub fn add_light_weight_timer() { diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index fa166e05..3910e9a2 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -11,11 +11,15 @@ use crate::{ }; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; -use parking_lot::RwLock; +use parking_lot::{Mutex, RwLock}; use percent_encoding::percent_decode_str; use serde_json; use serde_yaml::Mapping; -use std::{net::TcpListener, sync::Arc}; +use std::{ + net::TcpListener, + sync::Arc, + time::{Duration, Instant}, +}; use tauri::{App, Emitter, Manager}; use tauri::Url; @@ -31,6 +35,13 @@ static STATE_HEIGHT: OnceCell = OnceCell::new(); // 添加全局UI准备就绪标志 static UI_READY: OnceCell>> = OnceCell::new(); +// 窗口创建锁,防止并发创建窗口 +static WINDOW_CREATING: OnceCell> = OnceCell::new(); + +fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> { + WINDOW_CREATING.get_or_init(|| Mutex::new((false, Instant::now()))) +} + fn get_ui_ready() -> &'static Arc> { UI_READY.get_or_init(|| Arc::new(RwLock::new(false))) } @@ -148,8 +159,41 @@ pub async fn resolve_reset_async() { } } +/// 窗口创建锁守卫 +struct WindowCreateGuard; + +impl Drop for WindowCreateGuard { + fn drop(&mut self) { + let mut lock = get_window_creating_lock().lock(); + lock.0 = false; + logging!(info, Type::Window, true, "窗口创建过程已完成,释放锁"); + } +} + /// create main window pub fn create_window(is_showup: bool) { + // 尝试获取窗口创建锁 + let mut creating_lock = get_window_creating_lock().lock(); + let (is_creating, last_create_time) = *creating_lock; + let now = Instant::now(); + + // 检查是否有其他线程正在创建窗口,防止短时间内多次创建窗口导致竞态条件 + if is_creating && now.duration_since(last_create_time) < Duration::from_secs(2) { + logging!( + warn, + Type::Window, + true, + "另一个窗口创建过程正在进行中,跳过本次创建请求" + ); + return; + } + + *creating_lock = (true, now); + drop(creating_lock); + + // 创建窗口锁守卫结束时自动释放锁 + let _guard = WindowCreateGuard; + // 打印 .window-state.json 文件路径 if let Ok(app_dir) = crate::utils::dirs::app_home_dir() { let window_state_path = app_dir.join(".window-state.json"); @@ -244,6 +288,9 @@ pub fn create_window(is_showup: bool) { // 从轻量模式恢复需要销毁旧窗口以重建 logging!(info, Type::Window, true, "销毁旧窗口以重建新窗口"); let _ = window.close(); + + // 添加短暂延迟确保窗口正确关闭 + std::thread::sleep(std::time::Duration::from_millis(100)); } else { // 普通情况直接显示窗口 let _ = window.show(); diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index 44acafd2..c6b5ea11 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -214,9 +214,6 @@ const Layout = () => { useEffect(() => { const notifyUiReady = async () => { try { - await invoke("reset_ui_ready_state"); - console.log("已重置UI就绪状态"); - await new Promise(resolve => setTimeout(resolve, 200)); await invoke("notify_ui_ready"); console.log("已通知后端UI准备就绪"); } catch (err) { @@ -238,6 +235,7 @@ const Layout = () => { } }; + // 初始加载时也通知一次 console.log("页面初始加载,通知UI就绪"); notifyUiReady(); const unlistenPromise = listenStartupCompleted();