refactor: simplfy backend notify message to frontend (#6323)

This commit is contained in:
Tunglies 2026-02-20 11:18:51 +08:00 committed by GitHub
parent e5dd127bcc
commit 5f573ca2d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 24 additions and 181 deletions

View File

@ -23,7 +23,6 @@ pub mod timing {
use super::Duration;
pub const CONFIG_UPDATE_DEBOUNCE: Duration = Duration::from_millis(300);
pub const EVENT_EMIT_DELAY: Duration = Duration::from_millis(20);
pub const STARTUP_ERROR_DELAY: Duration = Duration::from_secs(2);
#[cfg(target_os = "windows")]

View File

@ -1,10 +1,6 @@
use crate::{APP_HANDLE, singleton, utils::window_manager::WindowManager};
use parking_lot::RwLock;
use crate::{APP_HANDLE, singleton};
use smartstring::alias::String;
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use std::sync::atomic::{AtomicBool, Ordering};
use tauri::AppHandle;
use tauri_plugin_mihomo::{Mihomo, MihomoExt as _};
use tokio::sync::RwLockReadGuard;
@ -14,14 +10,12 @@ use super::notification::{FrontendEvent, NotificationSystem};
#[derive(Debug)]
pub struct Handle {
is_exiting: AtomicBool,
pub(crate) notification_system: Arc<RwLock<Option<NotificationSystem>>>,
}
impl Default for Handle {
fn default() -> Self {
Self {
is_exiting: AtomicBool::new(false),
notification_system: Arc::new(RwLock::new(Some(NotificationSystem::new()))),
}
}
}
@ -33,19 +27,6 @@ impl Handle {
Self::default()
}
pub fn init(&self) {
if self.is_exiting() {
return;
}
let mut system_opt = self.notification_system.write();
if let Some(system) = system_opt.as_mut()
&& !system.is_running()
{
system.start();
}
}
pub fn app_handle() -> &'static AppHandle {
#[allow(clippy::expect_used)]
APP_HANDLE.get().expect("App handle not initialized")
@ -56,27 +37,11 @@ impl Handle {
}
pub fn refresh_clash() {
let handle = Self::global();
if handle.is_exiting() {
return;
}
let system_opt = handle.notification_system.read();
if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::RefreshClash);
}
Self::send_event(FrontendEvent::RefreshClash);
}
pub fn refresh_verge() {
let handle = Self::global();
if handle.is_exiting() {
return;
}
let system_opt = handle.notification_system.read();
if let Some(system) = system_opt.as_ref() {
system.send_event(FrontendEvent::RefreshVerge);
}
Self::send_event(FrontendEvent::RefreshVerge);
}
pub fn notify_profile_changed(profile_id: String) {
@ -99,17 +64,6 @@ impl Handle {
// TODO 利用 &str 等缩短 Clone
pub fn notice_message<S: Into<String>, M: Into<String>>(status: S, msg: M) {
let handle = Self::global();
if handle.is_exiting() {
return;
}
// We only send notice when main window exists
if WindowManager::get_main_window().is_none() {
return;
}
let status_str = status.into();
let msg_str = msg.into();
@ -119,29 +73,21 @@ impl Handle {
});
}
pub fn set_is_exiting(&self) {
self.is_exiting.store(true, Ordering::Release);
}
pub fn is_exiting(&self) -> bool {
self.is_exiting.load(Ordering::Acquire)
}
fn send_event(event: FrontendEvent) {
let handle = Self::global();
if handle.is_exiting() {
return;
}
let system_opt = handle.notification_system.read();
if let Some(system) = system_opt.as_ref() {
system.send_event(event);
}
}
pub fn set_is_exiting(&self) {
self.is_exiting.store(true, Ordering::Release);
let mut system_opt = self.notification_system.write();
if let Some(system) = system_opt.as_mut() {
system.shutdown();
}
}
pub fn is_exiting(&self) -> bool {
self.is_exiting.load(Ordering::Acquire)
NotificationSystem::send_event(event);
}
}

View File

@ -1,8 +1,8 @@
use super::handle::Handle;
use crate::{constants::timing, utils::window_manager::WindowManager};
use crate::utils::window_manager::WindowManager;
use clash_verge_logging::{Type, logging};
use serde_json::json;
use smartstring::alias::String;
use std::{sync::mpsc, thread};
use tauri::{Emitter as _, WebviewWindow};
// TODO 重构或优化,避免 Clone 过多
@ -18,83 +18,11 @@ pub enum FrontendEvent {
}
#[derive(Debug)]
pub struct NotificationSystem {
sender: Option<mpsc::Sender<FrontendEvent>>,
#[allow(clippy::type_complexity)]
worker_handle: Option<thread::JoinHandle<()>>,
}
impl Default for NotificationSystem {
fn default() -> Self {
Self::new()
}
}
pub struct NotificationSystem {}
impl NotificationSystem {
pub const fn new() -> Self {
Self {
sender: None,
worker_handle: None,
}
}
pub const fn is_running(&self) -> bool {
self.sender.is_some() && self.worker_handle.is_some()
}
pub fn start(&mut self) {
if self.is_running() {
return;
}
let (tx, rx) = mpsc::channel();
self.sender = Some(tx);
//? Do we have to create a new thread for this?
let result = thread::Builder::new()
.name("frontend-notifier".into())
.spawn(move || Self::worker_loop(rx));
match result {
Ok(handle) => self.worker_handle = Some(handle),
Err(e) => logging!(error, Type::System, "Failed to start notification worker: {}", e),
}
}
fn worker_loop(rx: mpsc::Receiver<FrontendEvent>) {
let handle = Handle::global();
loop {
if handle.is_exiting() {
break;
}
match rx.recv() {
Ok(event) => Self::process_event(handle, event),
Err(e) => {
logging!(error, Type::System, "Notification System will exit, recv error: {}", e);
break;
}
}
}
}
fn process_event(handle: &super::handle::Handle, event: FrontendEvent) {
let binding = handle.notification_system.read();
let system = match binding.as_ref() {
Some(s) => s,
None => return,
};
if let Some(window) = WindowManager::get_main_window() {
system.emit_to_window(&window, event);
drop(binding);
thread::sleep(timing::EVENT_EMIT_DELAY);
}
}
fn emit_to_window(&self, window: &WebviewWindow, event: FrontendEvent) {
let (event_name, payload) = self.serialize_event(event);
let Ok(payload) = payload else {
fn emit_to_window(window: &WebviewWindow, event: FrontendEvent) {
let (event_name, Ok(payload)) = Self::serialize_event(event) else {
return;
};
@ -103,9 +31,7 @@ impl NotificationSystem {
}
}
fn serialize_event(&self, event: FrontendEvent) -> (&'static str, Result<serde_json::Value, serde_json::Error>) {
use serde_json::json;
fn serialize_event(event: FrontendEvent) -> (&'static str, Result<serde_json::Value, serde_json::Error>) {
match event {
FrontendEvent::RefreshClash => ("verge://refresh-clash-config", Ok(json!("yes"))),
FrontendEvent::RefreshVerge => ("verge://refresh-verge-config", Ok(json!("yes"))),
@ -119,25 +45,9 @@ impl NotificationSystem {
}
}
pub fn send_event(&self, event: FrontendEvent) -> bool {
if !self.is_running() {
return false;
}
if let Some(sender) = &self.sender {
sender.send(event).is_ok()
} else {
false
}
}
pub fn shutdown(&mut self) {
if let Some(sender) = self.sender.take() {
drop(sender);
}
if let Some(handle) = self.worker_handle.take() {
let _ = handle.join();
pub(crate) fn send_event(event: FrontendEvent) {
if let Some(window) = WindowManager::get_main_window() {
Self::emit_to_window(&window, event);
}
}
}

View File

@ -250,7 +250,6 @@ pub fn run() {
logging!(error, Type::Setup, "Failed to setup window state: {}", e);
}
resolve::resolve_setup_handle();
resolve::resolve_setup_async();
resolve::resolve_setup_sync();
resolve::init_signal();
@ -282,7 +281,6 @@ pub fn run() {
}
logging!(info, Type::System, "应用就绪");
handle::Handle::global().init();
#[cfg(target_os = "macos")]
if let Some(window) = _app_handle.get_webview_window("main") {
@ -292,8 +290,6 @@ pub fn run() {
#[cfg(target_os = "macos")]
pub async fn handle_reopen(has_visible_windows: bool) {
handle::Handle::global().init();
if lightweight::is_in_lightweight_mode() {
lightweight::exit_lightweight_mode().await;
return;

View File

@ -5,7 +5,7 @@ use anyhow::Result;
use crate::{
config::Config,
core::{
CoreManager, Timer, handle,
CoreManager, Timer,
hotkey::Hotkey,
logger::Logger,
service::{SERVICE_MANAGER, ServiceManager, is_service_ipc_path_exists},
@ -39,10 +39,6 @@ pub fn init_work_dir_and_logger() -> anyhow::Result<()> {
})
}
pub fn resolve_setup_handle() {
init_handle();
}
pub fn resolve_setup_sync() {
AsyncHandler::spawn(|| async {
AsyncHandler::spawn_blocking(init_scheme);
@ -95,10 +91,6 @@ pub async fn resolve_reset_async() -> Result<(), anyhow::Error> {
Ok(())
}
pub fn init_handle() {
handle::Handle::global().init();
}
pub(super) fn init_scheme() {
logging_error!(Type::Setup, init::init_scheme());
}