mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-28 07:14:40 +08:00
refactor(notification): replace ArcSwap with Mutex for notification system and simplify event handling
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
use crate::{APP_HANDLE, singleton};
|
||||
use arc_swap::ArcSwap;
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::Mutex;
|
||||
use smartstring::alias::String;
|
||||
use std::sync::{
|
||||
Arc,
|
||||
@@ -10,14 +9,13 @@ use tauri::{AppHandle, Manager as _, WebviewWindow};
|
||||
use tauri_plugin_mihomo::{Mihomo, MihomoExt as _};
|
||||
use tokio::sync::RwLockReadGuard;
|
||||
|
||||
use super::notification::{ErrorMessage, FrontendEvent, NotificationSystem};
|
||||
use super::notification::{FrontendEvent, NotificationSystem};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Handle {
|
||||
pub(super) notification_system: Arc<Mutex<NotificationSystem>>,
|
||||
is_exiting: AtomicBool,
|
||||
startup_completed: AtomicBool,
|
||||
startup_errors: Arc<RwLock<Vec<ErrorMessage>>>,
|
||||
pub(super) notification_system: ArcSwap<NotificationSystem>,
|
||||
}
|
||||
|
||||
singleton!(Handle, HANDLE);
|
||||
@@ -31,7 +29,7 @@ impl Handle {
|
||||
if self.is_exiting() {
|
||||
return;
|
||||
}
|
||||
self.notification_system.load().start();
|
||||
self.notification_system.lock().start();
|
||||
}
|
||||
|
||||
pub fn app_handle() -> &'static AppHandle {
|
||||
@@ -76,21 +74,13 @@ impl Handle {
|
||||
// TODO 利用 &str 等缩短 Clone
|
||||
pub fn notice_message<S: Into<String>, M: Into<String>>(status: S, msg: M) {
|
||||
let handle = Self::global();
|
||||
let status_str = status.into();
|
||||
let msg_str = msg.into();
|
||||
|
||||
if !handle.startup_completed.load(Ordering::Acquire) {
|
||||
handle.startup_errors.write().push(ErrorMessage {
|
||||
status: status_str,
|
||||
message: msg_str,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if handle.is_exiting() {
|
||||
return;
|
||||
}
|
||||
|
||||
let status_str = status.into();
|
||||
let msg_str = msg.into();
|
||||
|
||||
Self::send_event(FrontendEvent::NoticeMessage {
|
||||
status: status_str,
|
||||
message: msg_str,
|
||||
@@ -102,27 +92,16 @@ impl Handle {
|
||||
if handle.is_exiting() {
|
||||
return;
|
||||
}
|
||||
handle.notification_system.load().send_event(event);
|
||||
handle.notification_system.lock().send_event(event);
|
||||
}
|
||||
|
||||
pub fn mark_startup_completed(&self) {
|
||||
self.startup_completed.store(true, Ordering::Release);
|
||||
self.send_startup_errors();
|
||||
}
|
||||
|
||||
fn send_startup_errors(&self) {
|
||||
let errors = std::mem::take(&mut *self.startup_errors.write());
|
||||
for error in errors {
|
||||
Self::send_event(FrontendEvent::NoticeMessage {
|
||||
status: error.status,
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_is_exiting(&self) {
|
||||
self.is_exiting.store(true, Ordering::Release);
|
||||
self.notification_system.load().shutdown();
|
||||
self.notification_system.lock().shutdown();
|
||||
}
|
||||
|
||||
pub fn is_exiting(&self) -> bool {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use super::handle::Handle;
|
||||
use clash_verge_logging::{Type, logging};
|
||||
use parking_lot::Mutex;
|
||||
use serde_json::json;
|
||||
use smartstring::alias::String;
|
||||
use tauri::{
|
||||
Emitter as _, WebviewWindow,
|
||||
async_runtime::{Receiver, Sender, channel},
|
||||
async_runtime::{JoinHandle, Receiver, Sender, channel},
|
||||
};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
// TODO 重构或优化,避免 Clone 过多
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FrontendEvent {
|
||||
pub(super) enum FrontendEvent {
|
||||
RefreshClash,
|
||||
RefreshVerge,
|
||||
NoticeMessage { status: String, message: String },
|
||||
@@ -23,21 +24,15 @@ pub enum FrontendEvent {
|
||||
ProfileUpdateCompleted { uid: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ErrorMessage {
|
||||
pub status: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct NotificationSystem {
|
||||
sender: Mutex<Option<Sender<FrontendEvent>>>,
|
||||
worker_task: Mutex<Option<JoinHandle<()>>>,
|
||||
sender: Arc<Option<Sender<FrontendEvent>>>,
|
||||
worker_task: Arc<Option<JoinHandle<()>>>,
|
||||
pub(super) is_running: AtomicBool,
|
||||
}
|
||||
|
||||
impl NotificationSystem {
|
||||
pub fn start(&self) {
|
||||
pub fn start(&mut self) {
|
||||
if self
|
||||
.is_running
|
||||
.compare_exchange(false, true, Ordering::Release, Ordering::Relaxed)
|
||||
@@ -47,22 +42,18 @@ impl NotificationSystem {
|
||||
}
|
||||
|
||||
let (tx, rx) = channel(32);
|
||||
*self.sender.lock() = Some(tx);
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
let rt = tokio::runtime::Builder::new_current_thread()
|
||||
.worker_threads(1)
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to build runtime for notification system");
|
||||
|
||||
let task = rt.spawn(async move {
|
||||
if let Some(s) = Arc::get_mut(&mut self.sender) {
|
||||
*s = Some(tx);
|
||||
}
|
||||
let task = tauri::async_runtime::spawn(async move {
|
||||
Self::worker_loop(rx).await;
|
||||
});
|
||||
*self.worker_task.lock() = Some(task);
|
||||
if let Some(t) = Arc::get_mut(&mut self.worker_task) {
|
||||
*t = Some(task);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shutdown(&self) {
|
||||
pub fn shutdown(&mut self) {
|
||||
if self
|
||||
.is_running
|
||||
.compare_exchange(true, false, Ordering::Release, Ordering::Relaxed)
|
||||
@@ -71,16 +62,16 @@ impl NotificationSystem {
|
||||
return;
|
||||
}
|
||||
|
||||
self.sender.lock().take();
|
||||
self.sender = Arc::new(None);
|
||||
|
||||
let value = self.worker_task.lock().take();
|
||||
let value = Arc::get_mut(&mut self.worker_task).and_then(|t| t.take());
|
||||
if let Some(task) = value {
|
||||
task.abort();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_event(&self, event: FrontendEvent) -> bool {
|
||||
if let Some(sender) = &*self.sender.lock() {
|
||||
if let Some(sender) = &*self.sender {
|
||||
sender.try_send(event).is_ok()
|
||||
} else {
|
||||
false
|
||||
@@ -100,9 +91,8 @@ impl NotificationSystem {
|
||||
}
|
||||
|
||||
fn process_event_sync(handle: &super::handle::Handle, event: FrontendEvent) {
|
||||
let system = handle.notification_system.load();
|
||||
if let Some(window) = super::handle::Handle::get_window() {
|
||||
system.emit_to_window(&window, event);
|
||||
handle.notification_system.lock().emit_to_window(&window, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,6 @@ impl WindowManager {
|
||||
logging!(info, Type::Window, "窗口不存在,创建新窗口");
|
||||
if Self::create_window(true).await {
|
||||
logging!(info, Type::Window, "窗口创建成功");
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
WindowOperationResult::Created
|
||||
} else {
|
||||
logging!(warn, Type::Window, "窗口创建失败");
|
||||
|
||||
Reference in New Issue
Block a user