mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-18 08:21:34 +08:00
refactor: clean up and improve code structure (#6010)
This commit is contained in:
parent
421bbd090e
commit
9e4e0c81a4
@ -25,7 +25,6 @@ pub mod timing {
|
|||||||
pub const CONFIG_UPDATE_DEBOUNCE: Duration = Duration::from_millis(300);
|
pub const CONFIG_UPDATE_DEBOUNCE: Duration = Duration::from_millis(300);
|
||||||
pub const EVENT_EMIT_DELAY: Duration = Duration::from_millis(20);
|
pub const EVENT_EMIT_DELAY: Duration = Duration::from_millis(20);
|
||||||
pub const STARTUP_ERROR_DELAY: Duration = Duration::from_secs(2);
|
pub const STARTUP_ERROR_DELAY: Duration = Duration::from_secs(2);
|
||||||
pub const ERROR_BATCH_DELAY: Duration = Duration::from_millis(300);
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub const SERVICE_WAIT_MAX: Duration = Duration::from_millis(3000);
|
pub const SERVICE_WAIT_MAX: Duration = Duration::from_millis(3000);
|
||||||
@ -33,10 +32,6 @@ pub mod timing {
|
|||||||
pub const SERVICE_WAIT_INTERVAL: Duration = Duration::from_millis(200);
|
pub const SERVICE_WAIT_INTERVAL: Duration = Duration::from_millis(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod retry {
|
|
||||||
pub const EVENT_EMIT_THRESHOLD: u64 = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod files {
|
pub mod files {
|
||||||
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
|
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
|
||||||
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
|
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
|
||||||
|
|||||||
@ -53,16 +53,16 @@ impl Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct WebDavClient {
|
pub struct WebDavClient {
|
||||||
config: Arc<ArcSwapOption<WebDavConfig>>,
|
config: ArcSwapOption<WebDavConfig>,
|
||||||
clients: Arc<ArcSwap<HashMap<Operation, reqwest_dav::Client>>>,
|
clients: ArcSwap<HashMap<Operation, reqwest_dav::Client>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebDavClient {
|
impl WebDavClient {
|
||||||
pub fn global() -> &'static Self {
|
pub fn global() -> &'static Self {
|
||||||
static WEBDAV_CLIENT: OnceCell<WebDavClient> = OnceCell::new();
|
static WEBDAV_CLIENT: OnceCell<WebDavClient> = OnceCell::new();
|
||||||
WEBDAV_CLIENT.get_or_init(|| Self {
|
WEBDAV_CLIENT.get_or_init(|| Self {
|
||||||
config: Arc::new(ArcSwapOption::new(None)),
|
config: ArcSwapOption::new(None),
|
||||||
clients: Arc::new(ArcSwap::new(Arc::new(HashMap::new()))),
|
clients: ArcSwap::new(Arc::new(HashMap::new())),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,11 +147,12 @@ impl WebDavClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缓存客户端(替换 Arc<Mutex<HashMap<...>>> 的写法)
|
|
||||||
{
|
{
|
||||||
let mut map = (**self.clients.load()).clone();
|
self.clients.rcu(|clients_map| {
|
||||||
map.insert(op, client.clone());
|
let mut new_map = (**clients_map).clone();
|
||||||
self.clients.store(map.into());
|
new_map.insert(op, client.clone());
|
||||||
|
Arc::new(new_map)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(client)
|
Ok(client)
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
use crate::{APP_HANDLE, constants::timing, singleton};
|
use crate::{APP_HANDLE, singleton, utils::window_manager::WindowManager};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
use std::{
|
use std::sync::{
|
||||||
sync::{
|
|
||||||
Arc,
|
Arc,
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
},
|
|
||||||
thread,
|
|
||||||
};
|
};
|
||||||
use tauri::{AppHandle, Manager as _, WebviewWindow};
|
use tauri::{AppHandle, Manager as _, WebviewWindow};
|
||||||
use tauri_plugin_mihomo::{Mihomo, MihomoExt as _};
|
use tauri_plugin_mihomo::{Mihomo, MihomoExt as _};
|
||||||
use tokio::sync::RwLockReadGuard;
|
use tokio::sync::RwLockReadGuard;
|
||||||
|
|
||||||
use super::notification::{ErrorMessage, FrontendEvent, NotificationSystem};
|
use super::notification::{FrontendEvent, NotificationSystem};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
is_exiting: AtomicBool,
|
is_exiting: AtomicBool,
|
||||||
startup_errors: Arc<RwLock<Vec<ErrorMessage>>>,
|
|
||||||
startup_completed: AtomicBool,
|
|
||||||
pub(crate) notification_system: Arc<RwLock<Option<NotificationSystem>>>,
|
pub(crate) notification_system: Arc<RwLock<Option<NotificationSystem>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,8 +21,6 @@ impl Default for Handle {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_exiting: AtomicBool::new(false),
|
is_exiting: AtomicBool::new(false),
|
||||||
startup_errors: Arc::new(RwLock::new(Vec::new())),
|
|
||||||
startup_completed: AtomicBool::new(false),
|
|
||||||
notification_system: Arc::new(RwLock::new(Some(NotificationSystem::new()))),
|
notification_system: Arc::new(RwLock::new(Some(NotificationSystem::new()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,7 +40,7 @@ impl Handle {
|
|||||||
|
|
||||||
let mut system_opt = self.notification_system.write();
|
let mut system_opt = self.notification_system.write();
|
||||||
if let Some(system) = system_opt.as_mut()
|
if let Some(system) = system_opt.as_mut()
|
||||||
&& !system.is_running
|
&& !system.is_running()
|
||||||
{
|
{
|
||||||
system.start();
|
system.start();
|
||||||
}
|
}
|
||||||
@ -111,21 +104,19 @@ impl Handle {
|
|||||||
// TODO 利用 &str 等缩短 Clone
|
// TODO 利用 &str 等缩短 Clone
|
||||||
pub fn notice_message<S: Into<String>, M: Into<String>>(status: S, msg: M) {
|
pub fn notice_message<S: Into<String>, M: Into<String>>(status: S, msg: M) {
|
||||||
let handle = Self::global();
|
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() {
|
if handle.is_exiting() {
|
||||||
return;
|
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();
|
||||||
|
|
||||||
Self::send_event(FrontendEvent::NoticeMessage {
|
Self::send_event(FrontendEvent::NoticeMessage {
|
||||||
status: status_str,
|
status: status_str,
|
||||||
message: msg_str,
|
message: msg_str,
|
||||||
@ -144,49 +135,6 @@ impl Handle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_startup_completed(&self) {
|
|
||||||
self.startup_completed.store(true, Ordering::Release);
|
|
||||||
self.send_startup_errors();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_startup_errors(&self) {
|
|
||||||
let errors = {
|
|
||||||
let mut errors = self.startup_errors.write();
|
|
||||||
std::mem::take(&mut *errors)
|
|
||||||
};
|
|
||||||
|
|
||||||
if errors.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = thread::Builder::new()
|
|
||||||
.name("startup-errors-sender".into())
|
|
||||||
.spawn(move || {
|
|
||||||
thread::sleep(timing::STARTUP_ERROR_DELAY);
|
|
||||||
|
|
||||||
let handle = Self::global();
|
|
||||||
if handle.is_exiting() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let system_opt = handle.notification_system.read();
|
|
||||||
if let Some(system) = system_opt.as_ref() {
|
|
||||||
for error in errors {
|
|
||||||
if handle.is_exiting() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
system.send_event(FrontendEvent::NoticeMessage {
|
|
||||||
status: error.status,
|
|
||||||
message: error.message,
|
|
||||||
});
|
|
||||||
|
|
||||||
thread::sleep(timing::ERROR_BATCH_DELAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_is_exiting(&self) {
|
pub fn set_is_exiting(&self) {
|
||||||
self.is_exiting.store(true, Ordering::Release);
|
self.is_exiting.store(true, Ordering::Release);
|
||||||
|
|
||||||
|
|||||||
@ -134,7 +134,6 @@ impl Logger {
|
|||||||
|
|
||||||
/// only update app log level
|
/// only update app log level
|
||||||
pub fn update_log_level(&self, level: LevelFilter) -> Result<()> {
|
pub fn update_log_level(&self, level: LevelFilter) -> Result<()> {
|
||||||
println!("refresh log level");
|
|
||||||
*self.log_level.write() = level;
|
*self.log_level.write() = level;
|
||||||
let log_level = self.log_level.read().to_owned();
|
let log_level = self.log_level.read().to_owned();
|
||||||
if let Some(handle) = self.handle.lock().as_mut() {
|
if let Some(handle) = self.handle.lock().as_mut() {
|
||||||
@ -149,7 +148,6 @@ impl Logger {
|
|||||||
|
|
||||||
/// update app and mihomo core log config
|
/// update app and mihomo core log config
|
||||||
pub async fn update_log_config(&self, log_max_size: u64, log_max_count: usize) -> Result<()> {
|
pub async fn update_log_config(&self, log_max_size: u64, log_max_count: usize) -> Result<()> {
|
||||||
println!("refresh log file");
|
|
||||||
self.log_max_size.store(log_max_size, Ordering::SeqCst);
|
self.log_max_size.store(log_max_size, Ordering::SeqCst);
|
||||||
self.log_max_count.store(log_max_count, Ordering::SeqCst);
|
self.log_max_count.store(log_max_count, Ordering::SeqCst);
|
||||||
if let Some(handle) = self.handle.lock().as_ref() {
|
if let Some(handle) = self.handle.lock().as_ref() {
|
||||||
|
|||||||
@ -1,16 +1,8 @@
|
|||||||
use super::handle::Handle;
|
use super::handle::Handle;
|
||||||
use crate::constants::{retry, timing};
|
use crate::constants::timing;
|
||||||
use clash_verge_logging::{Type, logging};
|
use clash_verge_logging::{Type, logging};
|
||||||
use parking_lot::RwLock;
|
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
use std::{
|
use std::{sync::mpsc, thread};
|
||||||
sync::{
|
|
||||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
|
||||||
mpsc,
|
|
||||||
},
|
|
||||||
thread,
|
|
||||||
time::Instant,
|
|
||||||
};
|
|
||||||
use tauri::{Emitter as _, WebviewWindow};
|
use tauri::{Emitter as _, WebviewWindow};
|
||||||
|
|
||||||
// TODO 重构或优化,避免 Clone 过多
|
// TODO 重构或优化,避免 Clone 过多
|
||||||
@ -25,27 +17,11 @@ pub enum FrontendEvent {
|
|||||||
ProfileUpdateCompleted { uid: String },
|
ProfileUpdateCompleted { uid: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct EventStats {
|
|
||||||
total_sent: AtomicU64,
|
|
||||||
total_errors: AtomicU64,
|
|
||||||
last_error_time: RwLock<Option<Instant>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ErrorMessage {
|
|
||||||
pub status: String,
|
|
||||||
pub message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NotificationSystem {
|
pub struct NotificationSystem {
|
||||||
sender: Option<mpsc::Sender<FrontendEvent>>,
|
sender: Option<mpsc::Sender<FrontendEvent>>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
worker_handle: Option<thread::JoinHandle<()>>,
|
worker_handle: Option<thread::JoinHandle<()>>,
|
||||||
pub(super) is_running: bool,
|
|
||||||
stats: EventStats,
|
|
||||||
emergency_mode: AtomicBool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NotificationSystem {
|
impl Default for NotificationSystem {
|
||||||
@ -55,25 +31,26 @@ impl Default for NotificationSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NotificationSystem {
|
impl NotificationSystem {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
sender: None,
|
sender: None,
|
||||||
worker_handle: None,
|
worker_handle: None,
|
||||||
is_running: false,
|
|
||||||
stats: EventStats::default(),
|
|
||||||
emergency_mode: AtomicBool::new(false),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn is_running(&self) -> bool {
|
||||||
|
self.sender.is_some() && self.worker_handle.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
if self.is_running {
|
if self.is_running() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
self.sender = Some(tx);
|
self.sender = Some(tx);
|
||||||
self.is_running = true;
|
|
||||||
|
|
||||||
|
//? Do we have to create a new thread for this?
|
||||||
let result = thread::Builder::new()
|
let result = thread::Builder::new()
|
||||||
.name("frontend-notifier".into())
|
.name("frontend-notifier".into())
|
||||||
.spawn(move || Self::worker_loop(rx));
|
.spawn(move || Self::worker_loop(rx));
|
||||||
@ -107,10 +84,6 @@ impl NotificationSystem {
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
if system.should_skip_event(&event) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(window) = super::handle::Handle::get_window() {
|
if let Some(window) = super::handle::Handle::get_window() {
|
||||||
system.emit_to_window(&window, event);
|
system.emit_to_window(&window, event);
|
||||||
drop(binding);
|
drop(binding);
|
||||||
@ -118,30 +91,15 @@ impl NotificationSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_skip_event(&self, event: &FrontendEvent) -> bool {
|
|
||||||
let is_emergency = self.emergency_mode.load(Ordering::Acquire);
|
|
||||||
matches!(
|
|
||||||
(is_emergency, event),
|
|
||||||
(true, FrontendEvent::NoticeMessage { status, .. }) if status == "info"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_to_window(&self, window: &WebviewWindow, event: FrontendEvent) {
|
fn emit_to_window(&self, window: &WebviewWindow, event: FrontendEvent) {
|
||||||
let (event_name, payload) = self.serialize_event(event);
|
let (event_name, payload) = self.serialize_event(event);
|
||||||
|
|
||||||
let Ok(payload) = payload else {
|
let Ok(payload) = payload else {
|
||||||
self.stats.total_errors.fetch_add(1, Ordering::Relaxed);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
match window.emit(event_name, payload) {
|
if let Err(e) = window.emit(event_name, payload) {
|
||||||
Ok(_) => {
|
|
||||||
self.stats.total_sent.fetch_add(1, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
logging!(warn, Type::Frontend, "Event emit failed: {}", e);
|
logging!(warn, Type::Frontend, "Event emit failed: {}", e);
|
||||||
self.handle_emit_error();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,19 +119,8 @@ impl NotificationSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_emit_error(&self) {
|
|
||||||
self.stats.total_errors.fetch_add(1, Ordering::Relaxed);
|
|
||||||
*self.stats.last_error_time.write() = Some(Instant::now());
|
|
||||||
|
|
||||||
let errors = self.stats.total_errors.load(Ordering::Relaxed);
|
|
||||||
if errors > retry::EVENT_EMIT_THRESHOLD && !self.emergency_mode.load(Ordering::Acquire) {
|
|
||||||
logging!(warn, Type::Frontend, "Entering emergency mode after {} errors", errors);
|
|
||||||
self.emergency_mode.store(true, Ordering::Release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_event(&self, event: FrontendEvent) -> bool {
|
pub fn send_event(&self, event: FrontendEvent) -> bool {
|
||||||
if self.should_skip_event(&event) {
|
if !self.is_running() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,8 +132,6 @@ impl NotificationSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(&mut self) {
|
pub fn shutdown(&mut self) {
|
||||||
self.is_running = false;
|
|
||||||
|
|
||||||
if let Some(sender) = self.sender.take() {
|
if let Some(sender) = self.sender.take() {
|
||||||
drop(sender);
|
drop(sender);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,3 @@
|
|||||||
use governor::{DefaultDirectRateLimiter, Quota, RateLimiter};
|
|
||||||
use tauri::tray::TrayIconBuilder;
|
|
||||||
use tauri_plugin_clash_verge_sysinfo::is_current_app_handle_admin;
|
|
||||||
use tauri_plugin_mihomo::models::Proxies;
|
|
||||||
use tokio::fs;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub mod speed_rate;
|
|
||||||
use crate::config::{IProfilePreview, IVerge};
|
use crate::config::{IProfilePreview, IVerge};
|
||||||
use crate::core::service;
|
use crate::core::service;
|
||||||
use crate::core::tray::menu_def::TrayAction;
|
use crate::core::tray::menu_def::TrayAction;
|
||||||
@ -16,6 +9,11 @@ use crate::{
|
|||||||
Type, cmd, config::Config, feat, logging, module::lightweight::is_in_lightweight_mode,
|
Type, cmd, config::Config, feat, logging, module::lightweight::is_in_lightweight_mode,
|
||||||
utils::dirs::find_target_icons,
|
utils::dirs::find_target_icons,
|
||||||
};
|
};
|
||||||
|
use governor::{DefaultDirectRateLimiter, Quota, RateLimiter};
|
||||||
|
use tauri::tray::TrayIconBuilder;
|
||||||
|
use tauri_plugin_clash_verge_sysinfo::is_current_app_handle_admin;
|
||||||
|
use tauri_plugin_mihomo::models::Proxies;
|
||||||
|
use tokio::fs;
|
||||||
|
|
||||||
use super::handle;
|
use super::handle;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -955,7 +953,6 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
|||||||
}
|
}
|
||||||
MenuIds::COPY_ENV => feat::copy_clash_env().await,
|
MenuIds::COPY_ENV => feat::copy_clash_env().await,
|
||||||
MenuIds::CONF_DIR => {
|
MenuIds::CONF_DIR => {
|
||||||
println!("Open directory submenu clicked");
|
|
||||||
let _ = cmd::open_app_dir().await;
|
let _ = cmd::open_app_dir().await;
|
||||||
}
|
}
|
||||||
MenuIds::CORE_DIR => {
|
MenuIds::CORE_DIR => {
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -1,17 +1,9 @@
|
|||||||
#[cfg(feature = "tokio-trace")]
|
|
||||||
use std::any::type_name;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
#[cfg(feature = "tokio-trace")]
|
|
||||||
use std::panic::Location;
|
|
||||||
use tauri::{async_runtime, async_runtime::JoinHandle};
|
use tauri::{async_runtime, async_runtime::JoinHandle};
|
||||||
|
|
||||||
pub struct AsyncHandler;
|
pub struct AsyncHandler;
|
||||||
|
|
||||||
impl AsyncHandler {
|
impl AsyncHandler {
|
||||||
// pub fn handle() -> async_runtime::RuntimeHandle {
|
|
||||||
// async_runtime::handle()
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn spawn<F, Fut>(f: F) -> JoinHandle<()>
|
pub fn spawn<F, Fut>(f: F) -> JoinHandle<()>
|
||||||
@ -19,8 +11,6 @@ impl AsyncHandler {
|
|||||||
F: FnOnce() -> Fut + Send + 'static,
|
F: FnOnce() -> Fut + Send + 'static,
|
||||||
Fut: Future<Output = ()> + Send + 'static,
|
Fut: Future<Output = ()> + Send + 'static,
|
||||||
{
|
{
|
||||||
#[cfg(feature = "tokio-trace")]
|
|
||||||
Self::log_task_info(&f);
|
|
||||||
async_runtime::spawn(f())
|
async_runtime::spawn(f())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +21,6 @@ impl AsyncHandler {
|
|||||||
F: FnOnce() -> T + Send + 'static,
|
F: FnOnce() -> T + Send + 'static,
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
{
|
{
|
||||||
#[cfg(feature = "tokio-trace")]
|
|
||||||
Self::log_task_info(&f);
|
|
||||||
async_runtime::spawn_blocking(f)
|
async_runtime::spawn_blocking(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,40 +30,6 @@ impl AsyncHandler {
|
|||||||
where
|
where
|
||||||
Fut: Future + Send + 'static,
|
Fut: Future + Send + 'static,
|
||||||
{
|
{
|
||||||
#[cfg(feature = "tokio-trace")]
|
|
||||||
Self::log_task_info(&fut);
|
|
||||||
async_runtime::block_on(fut)
|
async_runtime::block_on(fut)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tokio-trace")]
|
|
||||||
#[track_caller]
|
|
||||||
fn log_task_info<F>(f: &F)
|
|
||||||
where
|
|
||||||
F: ?Sized,
|
|
||||||
{
|
|
||||||
const TRACE_SPECIAL_SIZE: [usize; 3] = [0, 4, 24];
|
|
||||||
let size = std::mem::size_of_val(f);
|
|
||||||
if TRACE_SPECIAL_SIZE.contains(&size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let location = Location::caller();
|
|
||||||
let type_str = type_name::<F>();
|
|
||||||
let size_str = format!("{} bytes", size);
|
|
||||||
let loc_str = format!("{}:{}:{}", location.file(), location.line(), location.column());
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"┌────────────────────┬─────────────────────────────────────────────────────────────────────────────┐"
|
|
||||||
);
|
|
||||||
println!("│ {:<18} │ {:<80} │", "Field", "Value");
|
|
||||||
println!(
|
|
||||||
"├────────────────────┼─────────────────────────────────────────────────────────────────────────────┤"
|
|
||||||
);
|
|
||||||
println!("│ {:<18} │ {:<80} │", "Type of task", type_str);
|
|
||||||
println!("│ {:<18} │ {:<80} │", "Size of task", size_str);
|
|
||||||
println!("│ {:<18} │ {:<80} │", "Called from", loc_str);
|
|
||||||
println!(
|
|
||||||
"└────────────────────┴─────────────────────────────────────────────────────────────────────────────┘"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,9 @@ use reqwest::{
|
|||||||
header::{HeaderMap, HeaderValue, USER_AGENT},
|
header::{HeaderMap, HeaderValue, USER_AGENT},
|
||||||
};
|
};
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Duration;
|
||||||
use sysproxy::Sysproxy;
|
use sysproxy::Sysproxy;
|
||||||
use tauri::Url;
|
use tauri::Url;
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HttpResponse {
|
pub struct HttpResponse {
|
||||||
@ -43,13 +42,7 @@ pub enum ProxyType {
|
|||||||
System,
|
System,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NetworkManager {
|
pub struct NetworkManager;
|
||||||
self_proxy_client: Mutex<Option<Client>>,
|
|
||||||
system_proxy_client: Mutex<Option<Client>>,
|
|
||||||
no_proxy_client: Mutex<Option<Client>>,
|
|
||||||
last_connection_error: Mutex<Option<(Instant, String)>>,
|
|
||||||
connection_error_count: Mutex<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for NetworkManager {
|
impl Default for NetworkManager {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -58,44 +51,8 @@ impl Default for NetworkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkManager {
|
impl NetworkManager {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self
|
||||||
self_proxy_client: Mutex::new(None),
|
|
||||||
system_proxy_client: Mutex::new(None),
|
|
||||||
no_proxy_client: Mutex::new(None),
|
|
||||||
last_connection_error: Mutex::new(None),
|
|
||||||
connection_error_count: Mutex::new(0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn record_connection_error(&self, error: &str) {
|
|
||||||
*self.last_connection_error.lock().await = Some((Instant::now(), error.into()));
|
|
||||||
|
|
||||||
let mut count = self.connection_error_count.lock().await;
|
|
||||||
*count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn should_reset_clients(&self) -> bool {
|
|
||||||
let count = *self.connection_error_count.lock().await;
|
|
||||||
if count > 5 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((time, _)) = &*self.last_connection_error.lock().await
|
|
||||||
&& time.elapsed() < Duration::from_secs(30)
|
|
||||||
&& count > 2
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn reset_clients(&self) {
|
|
||||||
*self.self_proxy_client.lock().await = None;
|
|
||||||
*self.system_proxy_client.lock().await = None;
|
|
||||||
*self.no_proxy_client.lock().await = None;
|
|
||||||
*self.connection_error_count.lock().await = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_client(
|
fn build_client(
|
||||||
@ -192,11 +149,7 @@ impl NetworkManager {
|
|||||||
user_agent: Option<String>,
|
user_agent: Option<String>,
|
||||||
accept_invalid_certs: bool,
|
accept_invalid_certs: bool,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
if self.should_reset_clients().await {
|
let mut parsed = Url::parse(url)?;
|
||||||
self.reset_clients().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed = Url::parse(url)?;
|
|
||||||
let mut extra_headers = HeaderMap::new();
|
let mut extra_headers = HeaderMap::new();
|
||||||
|
|
||||||
if !parsed.username().is_empty()
|
if !parsed.username().is_empty()
|
||||||
@ -207,19 +160,15 @@ impl NetworkManager {
|
|||||||
extra_headers.insert("Authorization", HeaderValue::from_str(&format!("Basic {}", encoded))?);
|
extra_headers.insert("Authorization", HeaderValue::from_str(&format!("Basic {}", encoded))?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let clean_url = {
|
parsed.set_username("").ok();
|
||||||
let mut no_auth = parsed.clone();
|
parsed.set_password(None).ok();
|
||||||
no_auth.set_username("").ok();
|
|
||||||
no_auth.set_password(None).ok();
|
|
||||||
no_auth.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
// 创建请求
|
// 创建请求
|
||||||
let client = self
|
let client = self
|
||||||
.create_request(proxy_type, timeout_secs, user_agent, accept_invalid_certs)
|
.create_request(proxy_type, timeout_secs, user_agent, accept_invalid_certs)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut request_builder = client.get(&clean_url);
|
let mut request_builder = client.get(parsed);
|
||||||
|
|
||||||
for (key, value) in extra_headers.iter() {
|
for (key, value) in extra_headers.iter() {
|
||||||
request_builder = request_builder.header(key, value);
|
request_builder = request_builder.header(key, value);
|
||||||
@ -228,18 +177,15 @@ impl NetworkManager {
|
|||||||
let response = match request_builder.send().await {
|
let response = match request_builder.send().await {
|
||||||
Ok(resp) => resp,
|
Ok(resp) => resp,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.record_connection_error(&format!("Request failed: {}", e)).await;
|
|
||||||
return Err(anyhow::anyhow!("Request failed: {}", e));
|
return Err(anyhow::anyhow!("Request failed: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
let headers = response.headers().clone();
|
let headers = response.headers().to_owned();
|
||||||
let body = match response.text().await {
|
let body = match response.text().await {
|
||||||
Ok(text) => text.into(),
|
Ok(text) => text.into(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.record_connection_error(&format!("Failed to read response body: {}", e))
|
|
||||||
.await;
|
|
||||||
return Err(anyhow::anyhow!("Failed to read response body: {}", e));
|
return Err(anyhow::anyhow!("Failed to read response body: {}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -303,8 +303,6 @@ impl WindowManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle::Handle::global().mark_startup_completed();
|
|
||||||
|
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user