mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
refactor: optimize timer and network management with atomic operations
This commit is contained in:
@@ -1,9 +1,14 @@
|
|||||||
use crate::{config::Config, feat, logging, logging_error, utils::logging::Type};
|
use crate::{config::Config, feat, logging, logging_error, singleton, utils::logging::Type};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
|
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
|
||||||
use once_cell::sync::OnceCell;
|
use parking_lot::RwLock;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use std::{
|
||||||
use std::{collections::HashMap, sync::Arc};
|
collections::HashMap,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
type TaskID = u64;
|
type TaskID = u64;
|
||||||
|
|
||||||
@@ -22,23 +27,24 @@ pub struct Timer {
|
|||||||
/// save the current state - using RwLock for better read concurrency
|
/// save the current state - using RwLock for better read concurrency
|
||||||
pub timer_map: Arc<RwLock<HashMap<String, TimerTask>>>,
|
pub timer_map: Arc<RwLock<HashMap<String, TimerTask>>>,
|
||||||
|
|
||||||
/// increment id - kept as mutex since it's just a counter
|
/// increment id - atomic counter for better performance
|
||||||
pub timer_count: Arc<Mutex<TaskID>>,
|
pub timer_count: AtomicU64,
|
||||||
|
|
||||||
/// Flag to mark if timer is initialized - atomic for better performance
|
/// Flag to mark if timer is initialized - atomic for better performance
|
||||||
pub initialized: Arc<std::sync::atomic::AtomicBool>,
|
pub initialized: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
// Use singleton macro
|
||||||
pub fn global() -> &'static Timer {
|
singleton!(Timer, TIMER_INSTANCE);
|
||||||
static TIMER: OnceCell<Timer> = OnceCell::new();
|
|
||||||
|
|
||||||
TIMER.get_or_init(|| Timer {
|
impl Timer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Timer {
|
||||||
delay_timer: Arc::new(RwLock::new(DelayTimerBuilder::default().build())),
|
delay_timer: Arc::new(RwLock::new(DelayTimerBuilder::default().build())),
|
||||||
timer_map: Arc::new(RwLock::new(HashMap::new())),
|
timer_map: Arc::new(RwLock::new(HashMap::new())),
|
||||||
timer_count: Arc::new(Mutex::new(1)),
|
timer_count: AtomicU64::new(1),
|
||||||
initialized: Arc::new(std::sync::atomic::AtomicBool::new(false)),
|
initialized: AtomicBool::new(false),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize timer with better error handling and atomic operations
|
/// Initialize timer with better error handling and atomic operations
|
||||||
@@ -46,12 +52,7 @@ impl Timer {
|
|||||||
// Use compare_exchange for thread-safe initialization check
|
// Use compare_exchange for thread-safe initialization check
|
||||||
if self
|
if self
|
||||||
.initialized
|
.initialized
|
||||||
.compare_exchange(
|
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
||||||
false,
|
|
||||||
true,
|
|
||||||
std::sync::atomic::Ordering::SeqCst,
|
|
||||||
std::sync::atomic::Ordering::SeqCst,
|
|
||||||
)
|
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
logging!(debug, Type::Timer, "Timer already initialized, skipping...");
|
logging!(debug, Type::Timer, "Timer already initialized, skipping...");
|
||||||
@@ -63,8 +64,7 @@ impl Timer {
|
|||||||
// Initialize timer tasks
|
// Initialize timer tasks
|
||||||
if let Err(e) = self.refresh() {
|
if let Err(e) = self.refresh() {
|
||||||
// Reset initialization flag on error
|
// Reset initialization flag on error
|
||||||
self.initialized
|
self.initialized.store(false, Ordering::SeqCst);
|
||||||
.store(false, std::sync::atomic::Ordering::SeqCst);
|
|
||||||
logging_error!(Type::Timer, false, "Failed to initialize timer: {}", e);
|
logging_error!(Type::Timer, false, "Failed to initialize timer: {}", e);
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
@@ -299,7 +299,8 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find new tasks to add
|
// Find new tasks to add
|
||||||
let mut next_id = *self.timer_count.lock();
|
let mut next_id = self.timer_count.load(Ordering::Relaxed);
|
||||||
|
let original_id = next_id;
|
||||||
|
|
||||||
for (uid, &interval) in new_map.iter() {
|
for (uid, &interval) in new_map.iter() {
|
||||||
if !timer_map.contains_key(uid) {
|
if !timer_map.contains_key(uid) {
|
||||||
@@ -316,8 +317,8 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update counter only if we added new tasks
|
// Update counter only if we added new tasks
|
||||||
if next_id > *self.timer_count.lock() {
|
if next_id > original_id {
|
||||||
*self.timer_count.lock() = next_id;
|
self.timer_count.store(next_id, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
logging!(debug, Type::Timer, "定时任务变更数量: {}", diff_map.len());
|
logging!(debug, Type::Timer, "定时任务变更数量: {}", diff_map.len());
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ pub fn use_script(
|
|||||||
name: String,
|
name: String,
|
||||||
) -> Result<(Mapping, Vec<(String, String)>)> {
|
) -> Result<(Mapping, Vec<(String, String)>)> {
|
||||||
use boa_engine::{native_function::NativeFunction, Context, JsValue, Source};
|
use boa_engine::{native_function::NativeFunction, Context, JsValue, Source};
|
||||||
use parking_lot::Mutex;
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use std::sync::Arc;
|
|
||||||
let mut context = Context::default();
|
let mut context = Context::default();
|
||||||
|
|
||||||
let outputs = Arc::new(Mutex::new(vec![]));
|
let outputs = Rc::new(RefCell::new(vec![]));
|
||||||
|
|
||||||
let copy_outputs = outputs.clone();
|
let copy_outputs = outputs.clone();
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -25,7 +24,7 @@ pub fn use_script(
|
|||||||
let level = level.to_std_string().unwrap();
|
let level = level.to_std_string().unwrap();
|
||||||
let data = args.get(1).unwrap().to_string(context)?;
|
let data = args.get(1).unwrap().to_string(context)?;
|
||||||
let data = data.to_std_string().unwrap();
|
let data = data.to_std_string().unwrap();
|
||||||
let mut out = copy_outputs.lock();
|
let mut out = copy_outputs.borrow_mut();
|
||||||
out.push((level, data));
|
out.push((level, data));
|
||||||
Ok(JsValue::undefined())
|
Ok(JsValue::undefined())
|
||||||
},
|
},
|
||||||
@@ -68,7 +67,7 @@ pub fn use_script(
|
|||||||
// 直接解析JSON结果,不做其他解析
|
// 直接解析JSON结果,不做其他解析
|
||||||
let res: Result<Mapping, Error> = parse_json_safely(&result);
|
let res: Result<Mapping, Error> = parse_json_safely(&result);
|
||||||
|
|
||||||
let mut out = outputs.lock();
|
let mut out = outputs.borrow_mut();
|
||||||
match res {
|
match res {
|
||||||
Ok(config) => Ok((use_lowercase(config), out.to_vec())),
|
Ok(config) => Ok((use_lowercase(config), out.to_vec())),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ mod app_init {
|
|||||||
|
|
||||||
/// Setup plugins for the Tauri builder
|
/// Setup plugins for the Tauri builder
|
||||||
pub fn setup_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
pub fn setup_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut builder = builder
|
let mut builder = builder
|
||||||
.plugin(tauri_plugin_notification::init())
|
.plugin(tauri_plugin_notification::init())
|
||||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
|
|||||||
@@ -254,10 +254,9 @@ fn setup_light_weight_timer() -> Result<()> {
|
|||||||
|
|
||||||
// 获取task_id
|
// 获取task_id
|
||||||
let task_id = {
|
let task_id = {
|
||||||
let mut timer_count = Timer::global().timer_count.lock();
|
Timer::global()
|
||||||
let id = *timer_count;
|
.timer_count
|
||||||
*timer_count += 1;
|
.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
||||||
id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建任务
|
// 创建任务
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ use anyhow::Result;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use reqwest::{Client, ClientBuilder, Proxy, RequestBuilder, Response};
|
use reqwest::{Client, ClientBuilder, Proxy, RequestBuilder, Response};
|
||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, Once},
|
sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering},
|
||||||
|
Arc, Once,
|
||||||
|
},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use tokio::runtime::{Builder, Runtime};
|
use tokio::runtime::{Builder, Runtime};
|
||||||
@@ -23,12 +26,12 @@ const POOL_IDLE_TIMEOUT: Duration = Duration::from_secs(15);
|
|||||||
/// 网络管理器
|
/// 网络管理器
|
||||||
pub struct NetworkManager {
|
pub struct NetworkManager {
|
||||||
runtime: Arc<Runtime>,
|
runtime: Arc<Runtime>,
|
||||||
self_proxy_client: Arc<Mutex<Option<Client>>>,
|
self_proxy_client: Mutex<Option<Client>>,
|
||||||
system_proxy_client: Arc<Mutex<Option<Client>>>,
|
system_proxy_client: Mutex<Option<Client>>,
|
||||||
no_proxy_client: Arc<Mutex<Option<Client>>>,
|
no_proxy_client: Mutex<Option<Client>>,
|
||||||
init: Once,
|
init: Once,
|
||||||
last_connection_error: Arc<Mutex<Option<(Instant, String)>>>,
|
last_connection_error: Mutex<Option<(Instant, String)>>,
|
||||||
connection_error_count: Arc<Mutex<usize>>,
|
connection_error_count: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use singleton_lazy macro to replace lazy_static!
|
// Use singleton_lazy macro to replace lazy_static!
|
||||||
@@ -47,12 +50,12 @@ impl NetworkManager {
|
|||||||
|
|
||||||
NetworkManager {
|
NetworkManager {
|
||||||
runtime: Arc::new(runtime),
|
runtime: Arc::new(runtime),
|
||||||
self_proxy_client: Arc::new(Mutex::new(None)),
|
self_proxy_client: Mutex::new(None),
|
||||||
system_proxy_client: Arc::new(Mutex::new(None)),
|
system_proxy_client: Mutex::new(None),
|
||||||
no_proxy_client: Arc::new(Mutex::new(None)),
|
no_proxy_client: Mutex::new(None),
|
||||||
init: Once::new(),
|
init: Once::new(),
|
||||||
last_connection_error: Arc::new(Mutex::new(None)),
|
last_connection_error: Mutex::new(None),
|
||||||
connection_error_count: Arc::new(Mutex::new(0)),
|
connection_error_count: AtomicUsize::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,12 +88,11 @@ impl NetworkManager {
|
|||||||
let mut last_error = self.last_connection_error.lock();
|
let mut last_error = self.last_connection_error.lock();
|
||||||
*last_error = Some((Instant::now(), error.to_string()));
|
*last_error = Some((Instant::now(), error.to_string()));
|
||||||
|
|
||||||
let mut error_count = self.connection_error_count.lock();
|
self.connection_error_count.fetch_add(1, Ordering::Relaxed);
|
||||||
*error_count += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_reset_clients(&self) -> bool {
|
fn should_reset_clients(&self) -> bool {
|
||||||
let error_count = *self.connection_error_count.lock();
|
let error_count = self.connection_error_count.load(Ordering::Relaxed);
|
||||||
let last_error = self.last_connection_error.lock();
|
let last_error = self.last_connection_error.lock();
|
||||||
|
|
||||||
if error_count > 5 {
|
if error_count > 5 {
|
||||||
@@ -120,10 +122,7 @@ impl NetworkManager {
|
|||||||
let mut client = self.no_proxy_client.lock();
|
let mut client = self.no_proxy_client.lock();
|
||||||
*client = None;
|
*client = None;
|
||||||
}
|
}
|
||||||
{
|
self.connection_error_count.store(0, Ordering::Relaxed);
|
||||||
let mut error_count = self.connection_error_count.lock();
|
|
||||||
*error_count = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 创建带有自定义选项的HTTP请求
|
/// 创建带有自定义选项的HTTP请求
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ use parking_lot::{Mutex, RwLock};
|
|||||||
use percent_encoding::percent_decode_str;
|
use percent_encoding::percent_decode_str;
|
||||||
use scopeguard;
|
use scopeguard;
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::{
|
use std::time::{Duration, Instant};
|
||||||
sync::Arc,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
@@ -33,7 +30,7 @@ const DEFAULT_WIDTH: u32 = 940;
|
|||||||
const DEFAULT_HEIGHT: u32 = 700;
|
const DEFAULT_HEIGHT: u32 = 700;
|
||||||
|
|
||||||
// 添加全局UI准备就绪标志
|
// 添加全局UI准备就绪标志
|
||||||
static UI_READY: OnceCell<Arc<RwLock<bool>>> = OnceCell::new();
|
static UI_READY: OnceCell<RwLock<bool>> = OnceCell::new();
|
||||||
|
|
||||||
// 窗口创建锁,防止并发创建窗口
|
// 窗口创建锁,防止并发创建窗口
|
||||||
static WINDOW_CREATING: OnceCell<Mutex<(bool, Instant)>> = OnceCell::new();
|
static WINDOW_CREATING: OnceCell<Mutex<(bool, Instant)>> = OnceCell::new();
|
||||||
@@ -63,18 +60,18 @@ impl Default for UiReadyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取UI就绪状态细节
|
// 获取UI就绪状态细节
|
||||||
static UI_READY_STATE: OnceCell<Arc<UiReadyState>> = OnceCell::new();
|
static UI_READY_STATE: OnceCell<UiReadyState> = OnceCell::new();
|
||||||
|
|
||||||
fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> {
|
fn get_window_creating_lock() -> &'static Mutex<(bool, Instant)> {
|
||||||
WINDOW_CREATING.get_or_init(|| Mutex::new((false, Instant::now())))
|
WINDOW_CREATING.get_or_init(|| Mutex::new((false, Instant::now())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ui_ready() -> &'static Arc<RwLock<bool>> {
|
fn get_ui_ready() -> &'static RwLock<bool> {
|
||||||
UI_READY.get_or_init(|| Arc::new(RwLock::new(false)))
|
UI_READY.get_or_init(|| RwLock::new(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ui_ready_state() -> &'static Arc<UiReadyState> {
|
fn get_ui_ready_state() -> &'static UiReadyState {
|
||||||
UI_READY_STATE.get_or_init(|| Arc::new(UiReadyState::default()))
|
UI_READY_STATE.get_or_init(UiReadyState::default)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新UI准备阶段
|
// 更新UI准备阶段
|
||||||
|
|||||||
Reference in New Issue
Block a user