mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
feat: introduce event-driven proxy manager and optimize proxy config updates
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
use super::CmdResult;
|
use super::CmdResult;
|
||||||
|
use crate::core::EventDrivenProxyManager;
|
||||||
use crate::wrap_err;
|
use crate::wrap_err;
|
||||||
use network_interface::NetworkInterface;
|
use network_interface::NetworkInterface;
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use sysproxy::{Autoproxy, Sysproxy};
|
use sysproxy::Sysproxy;
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
|
|
||||||
/// get the system proxy
|
/// get the system proxy
|
||||||
@@ -24,18 +25,24 @@ pub async fn get_sys_proxy() -> CmdResult<Mapping> {
|
|||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the system proxy
|
/// 获取自动代理配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_auto_proxy() -> CmdResult<Mapping> {
|
pub async fn get_auto_proxy() -> CmdResult<Mapping> {
|
||||||
let current = spawn_blocking(Autoproxy::get_auto_proxy)
|
log::debug!(target: "app", "开始获取自动代理配置(事件驱动)");
|
||||||
.await
|
|
||||||
.map_err(|e| format!("Failed to spawn blocking task for autoproxy: {}", e))?
|
let proxy_manager = EventDrivenProxyManager::global();
|
||||||
.map_err(|e| format!("Failed to get auto proxy: {}", e))?;
|
|
||||||
|
let current = proxy_manager.get_auto_proxy_cached();
|
||||||
|
// 异步请求更新,立即返回缓存数据
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let _ = proxy_manager.get_auto_proxy_async().await;
|
||||||
|
});
|
||||||
|
|
||||||
let mut map = Mapping::new();
|
let mut map = Mapping::new();
|
||||||
map.insert("enable".into(), current.enable.into());
|
map.insert("enable".into(), current.enable.into());
|
||||||
map.insert("url".into(), current.url.into());
|
map.insert("url".into(), current.url.clone().into());
|
||||||
|
|
||||||
|
log::debug!(target: "app", "返回自动代理配置(缓存): enable={}, url={}", current.enable, current.url);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
603
src-tauri/src/core/event_driven_proxy.rs
Normal file
603
src-tauri/src/core/event_driven_proxy.rs
Normal file
@@ -0,0 +1,603 @@
|
|||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
use tokio::time::{sleep, timeout, Duration};
|
||||||
|
|
||||||
|
use crate::config::{Config, IVerge};
|
||||||
|
use crate::logging_error;
|
||||||
|
use crate::utils::logging::Type;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use sysproxy::{Autoproxy, Sysproxy};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ProxyEvent {
|
||||||
|
/// 配置变更事件
|
||||||
|
ConfigChanged,
|
||||||
|
/// 强制检查代理状态
|
||||||
|
#[allow(dead_code)]
|
||||||
|
ForceCheck,
|
||||||
|
/// 启用系统代理
|
||||||
|
#[allow(dead_code)]
|
||||||
|
EnableProxy,
|
||||||
|
/// 禁用系统代理
|
||||||
|
#[allow(dead_code)]
|
||||||
|
DisableProxy,
|
||||||
|
/// 切换到PAC模式
|
||||||
|
#[allow(dead_code)]
|
||||||
|
SwitchToPac,
|
||||||
|
/// 切换到HTTP代理模式
|
||||||
|
#[allow(dead_code)]
|
||||||
|
SwitchToHttp,
|
||||||
|
/// 应用启动事件
|
||||||
|
AppStarted,
|
||||||
|
/// 应用关闭事件
|
||||||
|
#[allow(dead_code)]
|
||||||
|
AppStopping,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ProxyState {
|
||||||
|
pub sys_enabled: bool,
|
||||||
|
pub pac_enabled: bool,
|
||||||
|
pub auto_proxy: Autoproxy,
|
||||||
|
pub sys_proxy: Sysproxy,
|
||||||
|
pub last_updated: std::time::Instant,
|
||||||
|
pub is_healthy: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ProxyState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
sys_enabled: false,
|
||||||
|
pac_enabled: false,
|
||||||
|
auto_proxy: Autoproxy {
|
||||||
|
enable: false,
|
||||||
|
url: "".to_string(),
|
||||||
|
},
|
||||||
|
sys_proxy: Sysproxy {
|
||||||
|
enable: false,
|
||||||
|
host: "127.0.0.1".to_string(),
|
||||||
|
port: 7890,
|
||||||
|
bypass: "".to_string(),
|
||||||
|
},
|
||||||
|
last_updated: std::time::Instant::now(),
|
||||||
|
is_healthy: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventDrivenProxyManager {
|
||||||
|
state: Arc<RwLock<ProxyState>>,
|
||||||
|
event_sender: mpsc::UnboundedSender<ProxyEvent>,
|
||||||
|
query_sender: mpsc::UnboundedSender<QueryRequest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct QueryRequest {
|
||||||
|
response_tx: oneshot::Sender<Autoproxy>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置结构体移到外部
|
||||||
|
struct ProxyConfig {
|
||||||
|
sys_enabled: bool,
|
||||||
|
pac_enabled: bool,
|
||||||
|
guard_enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
static PROXY_MANAGER: Lazy<EventDrivenProxyManager> = Lazy::new(|| EventDrivenProxyManager::new());
|
||||||
|
|
||||||
|
impl EventDrivenProxyManager {
|
||||||
|
pub fn global() -> &'static EventDrivenProxyManager {
|
||||||
|
&PROXY_MANAGER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
let state = Arc::new(RwLock::new(ProxyState::default()));
|
||||||
|
let (event_tx, event_rx) = mpsc::unbounded_channel();
|
||||||
|
let (query_tx, query_rx) = mpsc::unbounded_channel();
|
||||||
|
|
||||||
|
Self::start_event_loop(state.clone(), event_rx, query_rx);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
state,
|
||||||
|
event_sender: event_tx,
|
||||||
|
query_sender: query_tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取自动代理配置(缓存)
|
||||||
|
pub fn get_auto_proxy_cached(&self) -> Autoproxy {
|
||||||
|
self.state.read().auto_proxy.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 异步获取最新的自动代理配置
|
||||||
|
pub async fn get_auto_proxy_async(&self) -> Autoproxy {
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let query = QueryRequest { response_tx: tx };
|
||||||
|
|
||||||
|
if self.query_sender.send(query).is_err() {
|
||||||
|
log::error!(target: "app", "发送查询请求失败,返回缓存数据");
|
||||||
|
return self.get_auto_proxy_cached();
|
||||||
|
}
|
||||||
|
|
||||||
|
match timeout(Duration::from_secs(5), rx).await {
|
||||||
|
Ok(Ok(result)) => result,
|
||||||
|
_ => {
|
||||||
|
log::warn!(target: "app", "查询超时,返回缓存数据");
|
||||||
|
self.get_auto_proxy_cached()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 通知配置变更
|
||||||
|
pub fn notify_config_changed(&self) {
|
||||||
|
self.send_event(ProxyEvent::ConfigChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 通知应用启动
|
||||||
|
pub fn notify_app_started(&self) {
|
||||||
|
self.send_event(ProxyEvent::AppStarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 通知应用即将关闭
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn notify_app_stopping(&self) {
|
||||||
|
self.send_event(ProxyEvent::AppStopping);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 启用系统代理
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn enable_proxy(&self) {
|
||||||
|
self.send_event(ProxyEvent::EnableProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 禁用系统代理
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn disable_proxy(&self) {
|
||||||
|
self.send_event(ProxyEvent::DisableProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 强制检查代理状态
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn force_check(&self) {
|
||||||
|
self.send_event(ProxyEvent::ForceCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_event(&self, event: ProxyEvent) {
|
||||||
|
if let Err(e) = self.event_sender.send(event) {
|
||||||
|
log::error!(target: "app", "发送代理事件失败: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_event_loop(
|
||||||
|
state: Arc<RwLock<ProxyState>>,
|
||||||
|
mut event_rx: mpsc::UnboundedReceiver<ProxyEvent>,
|
||||||
|
mut query_rx: mpsc::UnboundedReceiver<QueryRequest>,
|
||||||
|
) {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
log::info!(target: "app", "事件驱动代理管理器启动");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
event = event_rx.recv() => {
|
||||||
|
match event {
|
||||||
|
Some(event) => {
|
||||||
|
log::debug!(target: "app", "处理代理事件: {:?}", event);
|
||||||
|
Self::handle_event(&state, event).await;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::info!(target: "app", "事件通道关闭,代理管理器停止");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query = query_rx.recv() => {
|
||||||
|
match query {
|
||||||
|
Some(query) => {
|
||||||
|
let result = Self::handle_query(&state).await;
|
||||||
|
let _ = query.response_tx.send(result);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::info!(target: "app", "查询通道关闭");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_event(state: &Arc<RwLock<ProxyState>>, event: ProxyEvent) {
|
||||||
|
match event {
|
||||||
|
ProxyEvent::ConfigChanged | ProxyEvent::ForceCheck => {
|
||||||
|
Self::update_proxy_config(state).await;
|
||||||
|
}
|
||||||
|
ProxyEvent::EnableProxy => {
|
||||||
|
Self::enable_system_proxy(state).await;
|
||||||
|
}
|
||||||
|
ProxyEvent::DisableProxy => {
|
||||||
|
Self::disable_system_proxy(state).await;
|
||||||
|
}
|
||||||
|
ProxyEvent::SwitchToPac => {
|
||||||
|
Self::switch_proxy_mode(state, true).await;
|
||||||
|
}
|
||||||
|
ProxyEvent::SwitchToHttp => {
|
||||||
|
Self::switch_proxy_mode(state, false).await;
|
||||||
|
}
|
||||||
|
ProxyEvent::AppStarted => {
|
||||||
|
Self::initialize_proxy_state(state).await;
|
||||||
|
}
|
||||||
|
ProxyEvent::AppStopping => {
|
||||||
|
log::info!(target: "app", "清理代理状态");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_query(state: &Arc<RwLock<ProxyState>>) -> Autoproxy {
|
||||||
|
let auto_proxy = Self::get_auto_proxy_with_timeout().await;
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.auto_proxy = auto_proxy.clone();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto_proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn initialize_proxy_state(state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
log::info!(target: "app", "初始化代理状态");
|
||||||
|
|
||||||
|
let config = Self::get_proxy_config();
|
||||||
|
let auto_proxy = Self::get_auto_proxy_with_timeout().await;
|
||||||
|
let sys_proxy = Self::get_sys_proxy_with_timeout().await;
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.sys_enabled = config.sys_enabled;
|
||||||
|
s.pac_enabled = config.pac_enabled;
|
||||||
|
s.auto_proxy = auto_proxy;
|
||||||
|
s.sys_proxy = sys_proxy;
|
||||||
|
s.is_healthy = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
log::info!(target: "app", "代理状态初始化完成: sys={}, pac={}", config.sys_enabled, config.pac_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_proxy_config(state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
log::debug!(target: "app", "更新代理配置");
|
||||||
|
|
||||||
|
let config = Self::get_proxy_config();
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.sys_enabled = config.sys_enabled;
|
||||||
|
s.pac_enabled = config.pac_enabled;
|
||||||
|
});
|
||||||
|
|
||||||
|
if config.guard_enabled && config.sys_enabled {
|
||||||
|
Self::check_and_restore_proxy(state).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_and_restore_proxy(state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
let (sys_enabled, pac_enabled) = {
|
||||||
|
let s = state.read();
|
||||||
|
(s.sys_enabled, s.pac_enabled)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !sys_enabled {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!(target: "app", "检查代理状态");
|
||||||
|
|
||||||
|
if pac_enabled {
|
||||||
|
Self::check_and_restore_pac_proxy(state).await;
|
||||||
|
} else {
|
||||||
|
Self::check_and_restore_sys_proxy(state).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_and_restore_pac_proxy(state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
let current = Self::get_auto_proxy_with_timeout().await;
|
||||||
|
let expected = Self::get_expected_pac_config();
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.auto_proxy = current.clone();
|
||||||
|
});
|
||||||
|
|
||||||
|
if !current.enable || current.url != expected.url {
|
||||||
|
log::info!(target: "app", "PAC代理设置异常,正在恢复...");
|
||||||
|
Self::restore_pac_proxy(&expected.url).await;
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(500)).await;
|
||||||
|
let restored = Self::get_auto_proxy_with_timeout().await;
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.is_healthy = restored.enable && restored.url == expected.url;
|
||||||
|
s.auto_proxy = restored;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_and_restore_sys_proxy(state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
let current = Self::get_sys_proxy_with_timeout().await;
|
||||||
|
let expected = Self::get_expected_sys_proxy();
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.sys_proxy = current.clone();
|
||||||
|
});
|
||||||
|
|
||||||
|
if !current.enable || current.host != expected.host || current.port != expected.port {
|
||||||
|
log::info!(target: "app", "系统代理设置异常,正在恢复...");
|
||||||
|
Self::restore_sys_proxy(&expected).await;
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(500)).await;
|
||||||
|
let restored = Self::get_sys_proxy_with_timeout().await;
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| {
|
||||||
|
s.is_healthy = restored.enable
|
||||||
|
&& restored.host == expected.host
|
||||||
|
&& restored.port == expected.port;
|
||||||
|
s.sys_proxy = restored;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn enable_system_proxy(state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
log::info!(target: "app", "启用系统代理");
|
||||||
|
|
||||||
|
let pac_enabled = state.read().pac_enabled;
|
||||||
|
|
||||||
|
if pac_enabled {
|
||||||
|
let expected = Self::get_expected_pac_config();
|
||||||
|
Self::restore_pac_proxy(&expected.url).await;
|
||||||
|
} else {
|
||||||
|
let expected = Self::get_expected_sys_proxy();
|
||||||
|
Self::restore_sys_proxy(&expected).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::check_and_restore_proxy(state).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn disable_system_proxy(_state: &Arc<RwLock<ProxyState>>) {
|
||||||
|
log::info!(target: "app", "禁用系统代理");
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
let disabled_sys = Sysproxy::default();
|
||||||
|
let disabled_auto = Autoproxy::default();
|
||||||
|
|
||||||
|
logging_error!(Type::System, true, disabled_auto.set_auto_proxy());
|
||||||
|
logging_error!(Type::System, true, disabled_sys.set_system_proxy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn switch_proxy_mode(state: &Arc<RwLock<ProxyState>>, to_pac: bool) {
|
||||||
|
log::info!(target: "app", "切换到{}模式", if to_pac { "PAC" } else { "HTTP代理" });
|
||||||
|
|
||||||
|
if to_pac {
|
||||||
|
let disabled_sys = Sysproxy::default();
|
||||||
|
logging_error!(Type::System, true, disabled_sys.set_system_proxy());
|
||||||
|
|
||||||
|
let expected = Self::get_expected_pac_config();
|
||||||
|
Self::restore_pac_proxy(&expected.url).await;
|
||||||
|
} else {
|
||||||
|
let disabled_auto = Autoproxy::default();
|
||||||
|
logging_error!(Type::System, true, disabled_auto.set_auto_proxy());
|
||||||
|
|
||||||
|
let expected = Self::get_expected_sys_proxy();
|
||||||
|
Self::restore_sys_proxy(&expected).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::update_state_timestamp(state, |s| s.pac_enabled = to_pac);
|
||||||
|
Self::check_and_restore_proxy(state).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_auto_proxy_with_timeout() -> Autoproxy {
|
||||||
|
let result = timeout(
|
||||||
|
Duration::from_secs(2),
|
||||||
|
tokio::task::spawn_blocking(|| Autoproxy::get_auto_proxy()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Ok(Ok(proxy))) => proxy,
|
||||||
|
Ok(Ok(Err(e))) => {
|
||||||
|
log::warn!(target: "app", "获取自动代理失败: {}", e);
|
||||||
|
Autoproxy {
|
||||||
|
enable: false,
|
||||||
|
url: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
log::error!(target: "app", "spawn_blocking失败: {}", e);
|
||||||
|
Autoproxy {
|
||||||
|
enable: false,
|
||||||
|
url: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
log::warn!(target: "app", "获取自动代理超时");
|
||||||
|
Autoproxy {
|
||||||
|
enable: false,
|
||||||
|
url: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_sys_proxy_with_timeout() -> Sysproxy {
|
||||||
|
let result = timeout(
|
||||||
|
Duration::from_secs(2),
|
||||||
|
tokio::task::spawn_blocking(|| Sysproxy::get_system_proxy()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Ok(Ok(proxy))) => proxy,
|
||||||
|
_ => {
|
||||||
|
log::warn!(target: "app", "获取系统代理失败或超时");
|
||||||
|
Sysproxy {
|
||||||
|
enable: false,
|
||||||
|
host: "127.0.0.1".to_string(),
|
||||||
|
port: 7890,
|
||||||
|
bypass: "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一的状态更新方法
|
||||||
|
fn update_state_timestamp<F>(state: &Arc<RwLock<ProxyState>>, update_fn: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut ProxyState),
|
||||||
|
{
|
||||||
|
let mut state_guard = state.write();
|
||||||
|
update_fn(&mut state_guard);
|
||||||
|
state_guard.last_updated = std::time::Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_proxy_config() -> ProxyConfig {
|
||||||
|
let verge_config = Config::verge();
|
||||||
|
let verge = verge_config.latest();
|
||||||
|
ProxyConfig {
|
||||||
|
sys_enabled: verge.enable_system_proxy.unwrap_or(false),
|
||||||
|
pac_enabled: verge.proxy_auto_config.unwrap_or(false),
|
||||||
|
guard_enabled: verge.enable_proxy_guard.unwrap_or(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_expected_pac_config() -> Autoproxy {
|
||||||
|
let verge_config = Config::verge();
|
||||||
|
let verge = verge_config.latest();
|
||||||
|
let (proxy_host, pac_port) = (
|
||||||
|
verge
|
||||||
|
.proxy_host
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| "127.0.0.1".to_string()),
|
||||||
|
IVerge::get_singleton_port(),
|
||||||
|
);
|
||||||
|
Autoproxy {
|
||||||
|
enable: true,
|
||||||
|
url: format!("http://{}:{}/commands/pac", proxy_host, pac_port),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_expected_sys_proxy() -> Sysproxy {
|
||||||
|
let verge_config = Config::verge();
|
||||||
|
let verge = verge_config.latest();
|
||||||
|
let port = verge
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||||
|
let proxy_host = verge
|
||||||
|
.proxy_host
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| "127.0.0.1".to_string());
|
||||||
|
|
||||||
|
Sysproxy {
|
||||||
|
enable: true,
|
||||||
|
host: proxy_host,
|
||||||
|
port,
|
||||||
|
bypass: Self::get_bypass_config(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bypass_config() -> String {
|
||||||
|
let verge_config = Config::verge();
|
||||||
|
let verge = verge_config.latest();
|
||||||
|
let use_default = verge.use_default_bypass.unwrap_or(true);
|
||||||
|
let custom_bypass = verge.system_proxy_bypass.clone().unwrap_or_default();
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let default_bypass = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;<local>";
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let default_bypass =
|
||||||
|
"localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,::1";
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let default_bypass = "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,172.29.0.0/16,localhost,*.local,*.crashlytics.com,<local>";
|
||||||
|
|
||||||
|
if custom_bypass.is_empty() {
|
||||||
|
default_bypass.to_string()
|
||||||
|
} else if use_default {
|
||||||
|
format!("{},{}", default_bypass, custom_bypass)
|
||||||
|
} else {
|
||||||
|
custom_bypass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn restore_pac_proxy(expected_url: &str) {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
let new_autoproxy = Autoproxy {
|
||||||
|
enable: true,
|
||||||
|
url: expected_url.to_string(),
|
||||||
|
};
|
||||||
|
logging_error!(Type::System, true, new_autoproxy.set_auto_proxy());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
Self::execute_sysproxy_command(&["pac", expected_url]).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn restore_sys_proxy(expected: &Sysproxy) {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
logging_error!(Type::System, true, expected.set_system_proxy());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
let address = format!("{}:{}", expected.host, expected.port);
|
||||||
|
Self::execute_sysproxy_command(&["global", &address, &expected.bypass]).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
async fn execute_sysproxy_command(args: &[&str]) {
|
||||||
|
use crate::{core::handle::Handle, utils::dirs};
|
||||||
|
use tauri_plugin_shell::ShellExt;
|
||||||
|
|
||||||
|
let app_handle = match Handle::global().app_handle() {
|
||||||
|
Ok(handle) => handle,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(target: "app", "获取应用句柄失败: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let binary_path = match dirs::service_path() {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(target: "app", "获取服务路径失败: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sysproxy_exe = binary_path.with_file_name("sysproxy.exe");
|
||||||
|
if !sysproxy_exe.exists() {
|
||||||
|
log::error!(target: "app", "sysproxy.exe 不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shell = app_handle.shell();
|
||||||
|
let output = shell
|
||||||
|
.command(sysproxy_exe.as_path().to_str().unwrap())
|
||||||
|
.args(args)
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match output {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
log::error!(target: "app", "执行sysproxy命令失败: {:?}", args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(target: "app", "执行sysproxy命令出错: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod backup;
|
pub mod backup;
|
||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
mod core;
|
mod core;
|
||||||
|
pub mod event_driven_proxy;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
pub mod hotkey;
|
pub mod hotkey;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
@@ -10,4 +11,4 @@ pub mod timer;
|
|||||||
pub mod tray;
|
pub mod tray;
|
||||||
pub mod win_uwp;
|
pub mod win_uwp;
|
||||||
|
|
||||||
pub use self::{core::*, timer::Timer};
|
pub use self::{core::*, event_driven_proxy::EventDrivenProxyManager, timer::Timer};
|
||||||
|
|||||||
@@ -2,25 +2,20 @@
|
|||||||
use crate::utils::autostart as startup_shortcut;
|
use crate::utils::autostart as startup_shortcut;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, IVerge},
|
config::{Config, IVerge},
|
||||||
core::handle::Handle,
|
core::{handle::Handle, EventDrivenProxyManager},
|
||||||
logging, logging_error,
|
logging, logging_error,
|
||||||
process::AsyncHandler,
|
|
||||||
utils::logging::Type,
|
utils::logging::Type,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use sysproxy::{Autoproxy, Sysproxy};
|
use sysproxy::{Autoproxy, Sysproxy};
|
||||||
use tauri::async_runtime::Mutex as TokioMutex;
|
use tauri::async_runtime::Mutex as TokioMutex;
|
||||||
use tauri_plugin_autostart::ManagerExt;
|
use tauri_plugin_autostart::ManagerExt;
|
||||||
use tokio::time::{sleep, Duration};
|
|
||||||
|
|
||||||
pub struct Sysopt {
|
pub struct Sysopt {
|
||||||
update_sysproxy: Arc<TokioMutex<bool>>,
|
update_sysproxy: Arc<TokioMutex<bool>>,
|
||||||
reset_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")]
|
#[cfg(target_os = "windows")]
|
||||||
@@ -59,12 +54,15 @@ impl Sysopt {
|
|||||||
SYSOPT.get_or_init(|| Sysopt {
|
SYSOPT.get_or_init(|| Sysopt {
|
||||||
update_sysproxy: Arc::new(TokioMutex::new(false)),
|
update_sysproxy: Arc::new(TokioMutex::new(false)),
|
||||||
reset_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<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +105,8 @@ impl Sysopt {
|
|||||||
if !sys_enable {
|
if !sys_enable {
|
||||||
sys.set_system_proxy()?;
|
sys.set_system_proxy()?;
|
||||||
auto.set_auto_proxy()?;
|
auto.set_auto_proxy()?;
|
||||||
|
let proxy_manager = EventDrivenProxyManager::global();
|
||||||
|
proxy_manager.notify_config_changed();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +115,8 @@ impl Sysopt {
|
|||||||
auto.enable = true;
|
auto.enable = true;
|
||||||
sys.set_system_proxy()?;
|
sys.set_system_proxy()?;
|
||||||
auto.set_auto_proxy()?;
|
auto.set_auto_proxy()?;
|
||||||
|
let proxy_manager = EventDrivenProxyManager::global();
|
||||||
|
proxy_manager.notify_config_changed();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,13 +125,18 @@ impl Sysopt {
|
|||||||
sys.enable = true;
|
sys.enable = true;
|
||||||
auto.set_auto_proxy()?;
|
auto.set_auto_proxy()?;
|
||||||
sys.set_system_proxy()?;
|
sys.set_system_proxy()?;
|
||||||
|
let proxy_manager = EventDrivenProxyManager::global();
|
||||||
|
proxy_manager.notify_config_changed();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
if !sys_enable {
|
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 crate::{core::handle::Handle, utils::dirs};
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
@@ -169,6 +176,8 @@ impl Sysopt {
|
|||||||
bail!("sysproxy exe run failed");
|
bail!("sysproxy exe run failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let proxy_manager = EventDrivenProxyManager::global();
|
||||||
|
proxy_manager.notify_config_changed();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -180,7 +189,16 @@ impl Sysopt {
|
|||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
let mut sysproxy: Sysproxy = Sysproxy::get_system_proxy()?;
|
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;
|
sysproxy.enable = false;
|
||||||
autoproxy.enable = false;
|
autoproxy.enable = false;
|
||||||
autoproxy.set_auto_proxy()?;
|
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [editorOpen, setEditorOpen] = useState(false);
|
const [editorOpen, setEditorOpen] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const { verge, patchVerge } = useVerge();
|
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||||
const [hostOptions, setHostOptions] = useState<string[]>([]);
|
const [hostOptions, setHostOptions] = useState<string[]>([]);
|
||||||
|
|
||||||
type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
|
type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
|
||||||
@@ -281,7 +281,8 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
try {
|
setOpen(false);
|
||||||
|
setSaving(false);
|
||||||
const patch: Partial<IVergeConfig> = {};
|
const patch: Partial<IVergeConfig> = {};
|
||||||
|
|
||||||
if (value.guard !== enable_proxy_guard) {
|
if (value.guard !== enable_proxy_guard) {
|
||||||
@@ -334,40 +335,54 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
value.bypass !== system_proxy_bypass ||
|
value.bypass !== system_proxy_bypass ||
|
||||||
value.use_default !== use_default_bypass;
|
value.use_default !== use_default_bypass;
|
||||||
|
|
||||||
|
Promise.resolve().then(async () => {
|
||||||
|
try {
|
||||||
|
// 乐观更新本地状态
|
||||||
|
if (Object.keys(patch).length > 0) {
|
||||||
|
mutateVerge({ ...verge, ...patch }, false);
|
||||||
|
}
|
||||||
|
if (Object.keys(patch).length > 0) {
|
||||||
await patchVerge(patch);
|
await patchVerge(patch);
|
||||||
|
}
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
await Promise.all([
|
||||||
|
mutate("getSystemProxy"),
|
||||||
|
mutate("getAutotemProxy"),
|
||||||
|
]);
|
||||||
|
|
||||||
// 更新系统代理状态,以便UI立即反映变化
|
// 如果需要重置代理且代理当前启用
|
||||||
await Promise.all([mutate("getSystemProxy"), mutate("getAutotemProxy")]);
|
if (needResetProxy && enabled) {
|
||||||
|
const [currentSysProxy, currentAutoProxy] = await Promise.all([
|
||||||
|
getSystemProxy(),
|
||||||
|
getAutotemProxy(),
|
||||||
|
]);
|
||||||
|
|
||||||
// 只有在修改了影响系统代理的配置且系统代理当前启用时,才重置系统代理
|
const isProxyActive = value.pac
|
||||||
if (needResetProxy) {
|
? currentAutoProxy?.enable
|
||||||
const currentSysProxy = await getSystemProxy();
|
: currentSysProxy?.enable;
|
||||||
const currentAutoProxy = await getAutotemProxy();
|
|
||||||
|
|
||||||
if (value.pac ? currentAutoProxy?.enable : currentSysProxy?.enable) {
|
if (isProxyActive) {
|
||||||
// 临时关闭系统代理
|
|
||||||
await patchVergeConfig({ enable_system_proxy: false });
|
await patchVergeConfig({ enable_system_proxy: false });
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||||
// 减少等待时间
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
||||||
|
|
||||||
// 重新开启系统代理
|
|
||||||
await patchVergeConfig({ enable_system_proxy: true });
|
await patchVergeConfig({ enable_system_proxy: true });
|
||||||
|
|
||||||
// 更新UI状态
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
mutate("getSystemProxy"),
|
mutate("getSystemProxy"),
|
||||||
mutate("getAutotemProxy"),
|
mutate("getAutotemProxy"),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
setOpen(false);
|
console.warn("代理状态更新失败:", err);
|
||||||
} catch (err: any) {
|
|
||||||
showNotice("error", err.toString());
|
|
||||||
} finally {
|
|
||||||
setSaving(false);
|
|
||||||
}
|
}
|
||||||
|
}, 50);
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("配置保存失败:", err);
|
||||||
|
mutateVerge();
|
||||||
|
showNotice("error", err.toString());
|
||||||
|
// setOpen(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -479,7 +479,19 @@ const Layout = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SWRConfig value={{ errorRetryCount: 3 }}>
|
<SWRConfig
|
||||||
|
value={{
|
||||||
|
errorRetryCount: 3,
|
||||||
|
errorRetryInterval: 5000,
|
||||||
|
onError: (error, key) => {
|
||||||
|
console.error(`[SWR Error] Key: ${key}, Error:`, error);
|
||||||
|
if (key !== "getAutotemProxy") {
|
||||||
|
console.error(`SWR Error for ${key}:`, error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dedupingInterval: 2000,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<NoticeManager />
|
<NoticeManager />
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -111,10 +111,21 @@ export async function getSystemProxy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getAutotemProxy() {
|
export async function getAutotemProxy() {
|
||||||
return invoke<{
|
try {
|
||||||
|
console.log("[API] 开始调用 get_auto_proxy");
|
||||||
|
const result = await invoke<{
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
url: string;
|
url: string;
|
||||||
}>("get_auto_proxy");
|
}>("get_auto_proxy");
|
||||||
|
console.log("[API] get_auto_proxy 调用成功:", result);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[API] get_auto_proxy 调用失败:", error);
|
||||||
|
return {
|
||||||
|
enable: false,
|
||||||
|
url: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAutoLaunchStatus() {
|
export async function getAutoLaunchStatus() {
|
||||||
@@ -122,7 +133,6 @@ export async function getAutoLaunchStatus() {
|
|||||||
return await invoke<boolean>("get_auto_launch_status");
|
return await invoke<boolean>("get_auto_launch_status");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取自启动状态失败:", error);
|
console.error("获取自启动状态失败:", error);
|
||||||
// 出错时返回false作为默认值
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user