mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 08:45:41 +08:00
feat: introduce event-driven proxy manager and optimize proxy config updates
This commit is contained in:
@@ -2,25 +2,20 @@
|
||||
use crate::utils::autostart as startup_shortcut;
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
core::handle::Handle,
|
||||
core::{handle::Handle, EventDrivenProxyManager},
|
||||
logging, logging_error,
|
||||
process::AsyncHandler,
|
||||
utils::logging::Type,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use sysproxy::{Autoproxy, Sysproxy};
|
||||
use tauri::async_runtime::Mutex as TokioMutex;
|
||||
use tauri_plugin_autostart::ManagerExt;
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
pub struct Sysopt {
|
||||
update_sysproxy: Arc<TokioMutex<bool>>,
|
||||
reset_sysproxy: Arc<TokioMutex<bool>>,
|
||||
/// record whether the guard async is running or not
|
||||
guard_state: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -59,12 +54,15 @@ impl Sysopt {
|
||||
SYSOPT.get_or_init(|| Sysopt {
|
||||
update_sysproxy: Arc::new(TokioMutex::new(false)),
|
||||
reset_sysproxy: Arc::new(TokioMutex::new(false)),
|
||||
guard_state: Arc::new(false.into()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init_guard_sysproxy(&self) -> Result<()> {
|
||||
self.guard_proxy();
|
||||
// 使用事件驱动代理管理器
|
||||
let proxy_manager = EventDrivenProxyManager::global();
|
||||
proxy_manager.notify_app_started();
|
||||
|
||||
log::info!(target: "app", "已启用事件驱动代理守卫");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -107,6 +105,8 @@ impl Sysopt {
|
||||
if !sys_enable {
|
||||
sys.set_system_proxy()?;
|
||||
auto.set_auto_proxy()?;
|
||||
let proxy_manager = EventDrivenProxyManager::global();
|
||||
proxy_manager.notify_config_changed();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -115,6 +115,8 @@ impl Sysopt {
|
||||
auto.enable = true;
|
||||
sys.set_system_proxy()?;
|
||||
auto.set_auto_proxy()?;
|
||||
let proxy_manager = EventDrivenProxyManager::global();
|
||||
proxy_manager.notify_config_changed();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -123,13 +125,18 @@ impl Sysopt {
|
||||
sys.enable = true;
|
||||
auto.set_auto_proxy()?;
|
||||
sys.set_system_proxy()?;
|
||||
let proxy_manager = EventDrivenProxyManager::global();
|
||||
proxy_manager.notify_config_changed();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if !sys_enable {
|
||||
return self.reset_sysproxy().await;
|
||||
let result = self.reset_sysproxy().await;
|
||||
let proxy_manager = EventDrivenProxyManager::global();
|
||||
proxy_manager.notify_config_changed();
|
||||
return result;
|
||||
}
|
||||
use crate::{core::handle::Handle, utils::dirs};
|
||||
use anyhow::bail;
|
||||
@@ -169,6 +176,8 @@ impl Sysopt {
|
||||
bail!("sysproxy exe run failed");
|
||||
}
|
||||
}
|
||||
let proxy_manager = EventDrivenProxyManager::global();
|
||||
proxy_manager.notify_config_changed();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -180,7 +189,16 @@ impl Sysopt {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let mut sysproxy: Sysproxy = Sysproxy::get_system_proxy()?;
|
||||
let mut autoproxy = Autoproxy::get_auto_proxy()?;
|
||||
let mut autoproxy = match Autoproxy::get_auto_proxy() {
|
||||
Ok(ap) => ap,
|
||||
Err(e) => {
|
||||
log::warn!(target: "app", "重置代理时获取自动代理配置失败: {}, 使用默认配置", e);
|
||||
Autoproxy {
|
||||
enable: false,
|
||||
url: "".to_string(),
|
||||
}
|
||||
}
|
||||
};
|
||||
sysproxy.enable = false;
|
||||
autoproxy.enable = false;
|
||||
autoproxy.set_auto_proxy()?;
|
||||
@@ -295,167 +313,4 @@ impl Sysopt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn guard_proxy(&self) {
|
||||
let _lock = self.guard_state.lock();
|
||||
|
||||
AsyncHandler::spawn(move || async move {
|
||||
// default duration is 10s
|
||||
let mut wait_secs = 10u64;
|
||||
|
||||
loop {
|
||||
sleep(Duration::from_secs(wait_secs)).await;
|
||||
|
||||
let (enable, guard, guard_duration, pac, proxy_host) = {
|
||||
let verge = Config::verge();
|
||||
let verge = verge.latest();
|
||||
(
|
||||
verge.enable_system_proxy.unwrap_or(false),
|
||||
verge.enable_proxy_guard.unwrap_or(false),
|
||||
verge.proxy_guard_duration.unwrap_or(10),
|
||||
verge.proxy_auto_config.unwrap_or(false),
|
||||
verge
|
||||
.proxy_host
|
||||
.clone()
|
||||
.unwrap_or_else(|| String::from("127.0.0.1")),
|
||||
)
|
||||
};
|
||||
|
||||
// stop loop
|
||||
if !enable || !guard {
|
||||
continue;
|
||||
}
|
||||
|
||||
// update duration
|
||||
wait_secs = guard_duration;
|
||||
|
||||
log::debug!(target: "app", "try to guard the system proxy");
|
||||
|
||||
// 获取期望的代理端口
|
||||
let port = Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
let pac_port = IVerge::get_singleton_port();
|
||||
let bypass = get_bypass();
|
||||
|
||||
// 检查系统代理配置
|
||||
if pac {
|
||||
// 检查 PAC 代理设置
|
||||
let expected_url = format!("http://{}:{}/commands/pac", proxy_host, pac_port);
|
||||
let autoproxy = match Autoproxy::get_auto_proxy() {
|
||||
Ok(ap) => ap,
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "failed to get the auto proxy: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查自动代理是否启用且URL是否正确
|
||||
if !autoproxy.enable || autoproxy.url != expected_url {
|
||||
log::info!(target: "app", "auto proxy settings changed, restoring...");
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let new_autoproxy = Autoproxy {
|
||||
enable: true,
|
||||
url: expected_url,
|
||||
};
|
||||
logging_error!(Type::System, true, new_autoproxy.set_auto_proxy());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use crate::{core::handle::Handle, utils::dirs};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
|
||||
let app_handle = Handle::global().app_handle().unwrap();
|
||||
let binary_path = match dirs::service_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "failed to get service path: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let sysproxy_exe = binary_path.with_file_name("sysproxy.exe");
|
||||
if !sysproxy_exe.exists() {
|
||||
log::error!(target: "app", "sysproxy.exe not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
let shell = app_handle.shell();
|
||||
let output = shell
|
||||
.command(sysproxy_exe.as_path().to_str().unwrap())
|
||||
.args(["pac", expected_url.as_str()])
|
||||
.output()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
log::error!(target: "app", "failed to set auto proxy");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 检查常规系统代理设置
|
||||
let sysproxy = match Sysproxy::get_system_proxy() {
|
||||
Ok(sp) => sp,
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "failed to get the system proxy: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查系统代理是否启用且配置是否匹配
|
||||
if !sysproxy.enable || sysproxy.host != proxy_host || sysproxy.port != port {
|
||||
log::info!(target: "app", "system proxy settings changed, restoring...");
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let new_sysproxy = Sysproxy {
|
||||
enable: true,
|
||||
host: proxy_host.clone(),
|
||||
port,
|
||||
bypass: bypass.clone(),
|
||||
};
|
||||
logging_error!(Type::System, true, new_sysproxy.set_system_proxy());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use crate::{core::handle::Handle, utils::dirs};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
|
||||
let app_handle = Handle::global().app_handle().unwrap();
|
||||
let binary_path = match dirs::service_path() {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "failed to get service path: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let sysproxy_exe = binary_path.with_file_name("sysproxy.exe");
|
||||
if !sysproxy_exe.exists() {
|
||||
log::error!(target: "app", "sysproxy.exe not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
let address = format!("{}:{}", proxy_host, port);
|
||||
let shell = app_handle.shell();
|
||||
let output = shell
|
||||
.command(sysproxy_exe.as_path().to_str().unwrap())
|
||||
.args(["global", address.as_str(), bypass.as_ref()])
|
||||
.output()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
log::error!(target: "app", "failed to set system proxy");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user