2025-06-21 21:38:42 +08:00
|
|
|
|
use std::sync::Arc;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
use tokio::sync::RwLock;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
use tokio::sync::{mpsc, oneshot};
|
edition 2024 (#4702)
* feat: update Cargo.toml for 2024 edition and optimize release profiles
* feat: refactor environment variable settings for Linux and improve code organization
* Refactor conditional statements to use `&&` for improved readability
- Updated multiple files to combine nested `if let` statements using `&&` for better clarity and conciseness.
- This change enhances the readability of the code by reducing indentation levels and making the conditions more straightforward.
- Affected files include: media_unlock_checker.rs, profile.rs, clash.rs, profiles.rs, async_proxy_query.rs, core.rs, handle.rs, hotkey.rs, service.rs, timer.rs, tray/mod.rs, merge.rs, seq.rs, config.rs, proxy.rs, window.rs, general.rs, dirs.rs, i18n.rs, init.rs, network.rs, and window.rs in the resolve module.
* refactor: streamline conditional checks using `&&` for improved readability
* fix: update release profile settings for panic behavior and optimization
* fix: adjust optimization level in Cargo.toml and reorder imports in lightweight.rs
2025-09-10 09:49:06 +08:00
|
|
|
|
use tokio::time::{Duration, sleep, timeout};
|
|
|
|
|
|
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
use crate::config::{Config, IVerge};
|
2025-10-11 16:49:47 +08:00
|
|
|
|
use crate::core::{async_proxy_query::AsyncProxyQuery, handle};
|
2025-08-22 03:41:14 +08:00
|
|
|
|
use crate::process::AsyncHandler;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
|
use sysproxy::{Autoproxy, Sysproxy};
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub enum ProxyEvent {
|
|
|
|
|
|
/// 配置变更事件
|
|
|
|
|
|
ConfigChanged,
|
|
|
|
|
|
/// 应用启动事件
|
|
|
|
|
|
AppStarted,
|
|
|
|
|
|
/// 应用关闭事件
|
|
|
|
|
|
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,
|
2025-10-14 09:24:39 +08:00
|
|
|
|
url: "".into(),
|
2025-06-21 21:38:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
sys_proxy: Sysproxy {
|
|
|
|
|
|
enable: false,
|
2025-10-14 09:24:39 +08:00
|
|
|
|
host: "127.0.0.1".into(),
|
2025-07-30 19:59:11 +08:00
|
|
|
|
port: 7897,
|
2025-10-14 09:24:39 +08:00
|
|
|
|
bypass: "".into(),
|
2025-06-21 21:38:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
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)]
|
2025-08-22 03:16:59 +08:00
|
|
|
|
pub struct QueryRequest {
|
2025-06-21 21:38:42 +08:00
|
|
|
|
response_tx: oneshot::Sender<Autoproxy>,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 配置结构体移到外部
|
|
|
|
|
|
struct ProxyConfig {
|
|
|
|
|
|
sys_enabled: bool,
|
|
|
|
|
|
pac_enabled: bool,
|
|
|
|
|
|
guard_enabled: bool,
|
2025-10-07 07:18:07 +08:00
|
|
|
|
guard_duration: u64,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-21 22:39:12 +08:00
|
|
|
|
static PROXY_MANAGER: Lazy<EventDrivenProxyManager> = Lazy::new(EventDrivenProxyManager::new);
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let state_clone = Arc::clone(&state);
|
|
|
|
|
|
AsyncHandler::spawn(move || Self::start_event_loop(state_clone, event_rx, query_rx));
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
|
state,
|
|
|
|
|
|
event_sender: event_tx,
|
|
|
|
|
|
query_sender: query_tx,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 获取自动代理配置(缓存)
|
2025-08-26 01:49:51 +08:00
|
|
|
|
pub async fn get_auto_proxy_cached(&self) -> Autoproxy {
|
|
|
|
|
|
self.state.read().await.auto_proxy.clone()
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 异步获取最新的自动代理配置
|
|
|
|
|
|
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", "发送查询请求失败,返回缓存数据");
|
2025-08-26 01:49:51 +08:00
|
|
|
|
return self.get_auto_proxy_cached().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
match timeout(Duration::from_secs(5), rx).await {
|
|
|
|
|
|
Ok(Ok(result)) => result,
|
|
|
|
|
|
_ => {
|
|
|
|
|
|
log::warn!(target: "app", "查询超时,返回缓存数据");
|
2025-08-26 01:49:51 +08:00
|
|
|
|
self.get_auto_proxy_cached().await
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 通知配置变更
|
|
|
|
|
|
pub fn notify_config_changed(&self) {
|
|
|
|
|
|
self.send_event(ProxyEvent::ConfigChanged);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 通知应用启动
|
|
|
|
|
|
pub fn notify_app_started(&self) {
|
|
|
|
|
|
self.send_event(ProxyEvent::AppStarted);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 通知应用即将关闭
|
|
|
|
|
|
pub fn notify_app_stopping(&self) {
|
|
|
|
|
|
self.send_event(ProxyEvent::AppStopping);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn send_event(&self, event: ProxyEvent) {
|
|
|
|
|
|
if let Err(e) = self.event_sender.send(event) {
|
2025-06-27 23:30:35 +08:00
|
|
|
|
log::error!(target: "app", "发送代理事件失败: {e}");
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
pub async fn start_event_loop(
|
2025-06-21 21:38:42 +08:00
|
|
|
|
state: Arc<RwLock<ProxyState>>,
|
2025-08-22 03:16:59 +08:00
|
|
|
|
event_rx: mpsc::UnboundedReceiver<ProxyEvent>,
|
|
|
|
|
|
query_rx: mpsc::UnboundedReceiver<QueryRequest>,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
) {
|
2025-08-26 01:49:51 +08:00
|
|
|
|
log::info!(target: "app", "事件驱动代理管理器启动");
|
|
|
|
|
|
|
|
|
|
|
|
// 将 mpsc 接收器包装成 Stream,避免每次循环创建 future
|
|
|
|
|
|
let mut event_stream = UnboundedReceiverStream::new(event_rx);
|
|
|
|
|
|
let mut query_stream = UnboundedReceiverStream::new(query_rx);
|
|
|
|
|
|
|
2025-10-07 07:18:07 +08:00
|
|
|
|
// 初始化定时器,用于周期性检查代理设置
|
|
|
|
|
|
let config = Self::get_proxy_config().await;
|
|
|
|
|
|
let mut guard_interval = tokio::time::interval(Duration::from_secs(config.guard_duration));
|
|
|
|
|
|
// 防止首次立即触发
|
|
|
|
|
|
guard_interval.tick().await;
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
loop {
|
|
|
|
|
|
tokio::select! {
|
|
|
|
|
|
Some(event) = event_stream.next() => {
|
|
|
|
|
|
log::debug!(target: "app", "处理代理事件: {event:?}");
|
2025-10-07 07:18:07 +08:00
|
|
|
|
let event_clone = event.clone(); // 保存一份副本用于后续检查
|
2025-08-26 01:49:51 +08:00
|
|
|
|
Self::handle_event(&state, event).await;
|
2025-10-07 07:18:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查是否是配置变更事件,如果是,则可能需要更新定时器
|
|
|
|
|
|
if matches!(event_clone, ProxyEvent::ConfigChanged | ProxyEvent::AppStarted) {
|
|
|
|
|
|
let new_config = Self::get_proxy_config().await;
|
|
|
|
|
|
// 重新设置定时器间隔
|
|
|
|
|
|
guard_interval = tokio::time::interval(Duration::from_secs(new_config.guard_duration));
|
|
|
|
|
|
// 防止首次立即触发
|
|
|
|
|
|
guard_interval.tick().await;
|
|
|
|
|
|
}
|
2025-08-26 01:49:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
Some(query) = query_stream.next() => {
|
|
|
|
|
|
let result = Self::handle_query(&state).await;
|
|
|
|
|
|
let _ = query.response_tx.send(result);
|
|
|
|
|
|
}
|
2025-10-07 07:18:07 +08:00
|
|
|
|
_ = guard_interval.tick() => {
|
|
|
|
|
|
// 定时检查代理设置
|
|
|
|
|
|
let config = Self::get_proxy_config().await;
|
|
|
|
|
|
if config.guard_enabled && config.sys_enabled {
|
|
|
|
|
|
log::debug!(target: "app", "定时检查代理设置");
|
|
|
|
|
|
Self::check_and_restore_proxy(&state).await;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-26 01:49:51 +08:00
|
|
|
|
else => {
|
|
|
|
|
|
// 两个通道都关闭时退出
|
|
|
|
|
|
log::info!(target: "app", "事件或查询通道关闭,代理管理器停止");
|
|
|
|
|
|
break;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-26 01:49:51 +08:00
|
|
|
|
}
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async fn handle_event(state: &Arc<RwLock<ProxyState>>, event: ProxyEvent) {
|
|
|
|
|
|
match event {
|
2025-10-17 20:12:03 +08:00
|
|
|
|
ProxyEvent::ConfigChanged => {
|
2025-06-21 21:38:42 +08:00
|
|
|
|
Self::update_proxy_config(state).await;
|
|
|
|
|
|
}
|
|
|
|
|
|
ProxyEvent::AppStarted => {
|
|
|
|
|
|
Self::initialize_proxy_state(state).await;
|
|
|
|
|
|
}
|
|
|
|
|
|
ProxyEvent::AppStopping => {
|
|
|
|
|
|
log::info!(target: "app", "清理代理状态");
|
2025-10-11 16:49:47 +08:00
|
|
|
|
Self::update_state_timestamp(state, |s| {
|
|
|
|
|
|
s.sys_enabled = false;
|
|
|
|
|
|
s.pac_enabled = false;
|
|
|
|
|
|
s.is_healthy = false;
|
|
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
auto_proxy
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async fn initialize_proxy_state(state: &Arc<RwLock<ProxyState>>) {
|
|
|
|
|
|
log::info!(target: "app", "初始化代理状态");
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let config = Self::get_proxy_config().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
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;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
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", "更新代理配置");
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let config = Self::get_proxy_config().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
Self::update_state_timestamp(state, |s| {
|
|
|
|
|
|
s.sys_enabled = config.sys_enabled;
|
|
|
|
|
|
s.pac_enabled = config.pac_enabled;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
if config.guard_enabled && config.sys_enabled {
|
|
|
|
|
|
Self::check_and_restore_proxy(state).await;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async fn check_and_restore_proxy(state: &Arc<RwLock<ProxyState>>) {
|
2025-10-11 16:49:47 +08:00
|
|
|
|
if handle::Handle::global().is_exiting() {
|
|
|
|
|
|
log::debug!(target: "app", "应用正在退出,跳过系统代理守卫检查");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-21 21:38:42 +08:00
|
|
|
|
let (sys_enabled, pac_enabled) = {
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let s = state.read().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
(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>>) {
|
2025-10-11 16:49:47 +08:00
|
|
|
|
if handle::Handle::global().is_exiting() {
|
|
|
|
|
|
log::debug!(target: "app", "应用正在退出,跳过PAC代理恢复检查");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-21 21:38:42 +08:00
|
|
|
|
let current = Self::get_auto_proxy_with_timeout().await;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let expected = Self::get_expected_pac_config().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
Self::update_state_timestamp(state, |s| {
|
|
|
|
|
|
s.auto_proxy = current.clone();
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
if !current.enable || current.url != expected.url {
|
|
|
|
|
|
log::info!(target: "app", "PAC代理设置异常,正在恢复...");
|
2025-08-18 02:02:25 +08:00
|
|
|
|
if let Err(e) = Self::restore_pac_proxy(&expected.url).await {
|
|
|
|
|
|
log::error!(target: "app", "恢复PAC代理失败: {}", e);
|
|
|
|
|
|
}
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
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;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async fn check_and_restore_sys_proxy(state: &Arc<RwLock<ProxyState>>) {
|
2025-10-11 16:49:47 +08:00
|
|
|
|
if handle::Handle::global().is_exiting() {
|
|
|
|
|
|
log::debug!(target: "app", "应用正在退出,跳过系统代理恢复检查");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-21 21:38:42 +08:00
|
|
|
|
let current = Self::get_sys_proxy_with_timeout().await;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let expected = Self::get_expected_sys_proxy().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
Self::update_state_timestamp(state, |s| {
|
|
|
|
|
|
s.sys_proxy = current.clone();
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
if !current.enable || current.host != expected.host || current.port != expected.port {
|
|
|
|
|
|
log::info!(target: "app", "系统代理设置异常,正在恢复...");
|
2025-08-18 02:02:25 +08:00
|
|
|
|
if let Err(e) = Self::restore_sys_proxy(&expected).await {
|
|
|
|
|
|
log::error!(target: "app", "恢复系统代理失败: {}", e);
|
|
|
|
|
|
}
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
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;
|
2025-08-26 01:49:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async fn get_auto_proxy_with_timeout() -> Autoproxy {
|
2025-06-21 21:48:39 +08:00
|
|
|
|
let async_proxy = AsyncProxyQuery::get_auto_proxy().await;
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为兼容的结构
|
|
|
|
|
|
Autoproxy {
|
|
|
|
|
|
enable: async_proxy.enable,
|
|
|
|
|
|
url: async_proxy.url,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async fn get_sys_proxy_with_timeout() -> Sysproxy {
|
2025-06-21 21:48:39 +08:00
|
|
|
|
let async_proxy = AsyncProxyQuery::get_system_proxy().await;
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为兼容的结构
|
|
|
|
|
|
Sysproxy {
|
|
|
|
|
|
enable: async_proxy.enable,
|
|
|
|
|
|
host: async_proxy.host,
|
|
|
|
|
|
port: async_proxy.port,
|
|
|
|
|
|
bypass: async_proxy.bypass,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统一的状态更新方法
|
2025-08-26 01:49:51 +08:00
|
|
|
|
async fn update_state_timestamp<F>(state: &Arc<RwLock<ProxyState>>, update_fn: F)
|
2025-06-21 21:38:42 +08:00
|
|
|
|
where
|
|
|
|
|
|
F: FnOnce(&mut ProxyState),
|
|
|
|
|
|
{
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let mut state_guard = state.write().await;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
update_fn(&mut state_guard);
|
|
|
|
|
|
state_guard.last_updated = std::time::Instant::now();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
async fn get_proxy_config() -> ProxyConfig {
|
2025-10-07 07:18:07 +08:00
|
|
|
|
let (sys_enabled, pac_enabled, guard_enabled, guard_duration) = {
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let verge_config = Config::verge().await;
|
2025-07-04 22:43:23 +08:00
|
|
|
|
let verge = verge_config.latest_ref();
|
2025-07-04 12:22:22 +08:00
|
|
|
|
(
|
|
|
|
|
|
verge.enable_system_proxy.unwrap_or(false),
|
|
|
|
|
|
verge.proxy_auto_config.unwrap_or(false),
|
|
|
|
|
|
verge.enable_proxy_guard.unwrap_or(false),
|
2025-10-07 07:18:07 +08:00
|
|
|
|
verge.proxy_guard_duration.unwrap_or(30), // 默认30秒
|
2025-07-04 12:22:22 +08:00
|
|
|
|
)
|
|
|
|
|
|
};
|
2025-06-21 21:38:42 +08:00
|
|
|
|
ProxyConfig {
|
2025-07-04 12:22:22 +08:00
|
|
|
|
sys_enabled,
|
|
|
|
|
|
pac_enabled,
|
|
|
|
|
|
guard_enabled,
|
2025-10-07 07:18:07 +08:00
|
|
|
|
guard_duration,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
async fn get_expected_pac_config() -> Autoproxy {
|
2025-07-04 12:22:22 +08:00
|
|
|
|
let proxy_host = {
|
2025-08-26 01:49:51 +08:00
|
|
|
|
let verge_config = Config::verge().await;
|
2025-07-04 22:43:23 +08:00
|
|
|
|
let verge = verge_config.latest_ref();
|
2025-06-21 21:38:42 +08:00
|
|
|
|
verge
|
|
|
|
|
|
.proxy_host
|
|
|
|
|
|
.clone()
|
2025-10-14 09:24:39 +08:00
|
|
|
|
.unwrap_or_else(|| "127.0.0.1".into())
|
2025-07-04 12:22:22 +08:00
|
|
|
|
};
|
|
|
|
|
|
let pac_port = IVerge::get_singleton_port();
|
2025-06-21 21:38:42 +08:00
|
|
|
|
Autoproxy {
|
|
|
|
|
|
enable: true,
|
2025-06-27 23:30:35 +08:00
|
|
|
|
url: format!("http://{proxy_host}:{pac_port}/commands/pac"),
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
async fn get_expected_sys_proxy() -> Sysproxy {
|
2025-10-21 17:51:12 +08:00
|
|
|
|
use crate::constants::network;
|
2025-10-21 17:53:02 +08:00
|
|
|
|
|
2025-10-21 17:51:12 +08:00
|
|
|
|
let (verge_mixed_port, proxy_host) = {
|
|
|
|
|
|
let verge_config = Config::verge().await;
|
|
|
|
|
|
let verge_ref = verge_config.latest_ref();
|
|
|
|
|
|
(verge_ref.verge_mixed_port, verge_ref.proxy_host.clone())
|
|
|
|
|
|
};
|
2025-10-21 17:53:02 +08:00
|
|
|
|
|
2025-10-21 17:51:12 +08:00
|
|
|
|
let default_port = {
|
|
|
|
|
|
let clash_config = Config::clash().await;
|
|
|
|
|
|
clash_config.latest_ref().get_mixed_port()
|
|
|
|
|
|
};
|
2025-10-21 17:53:02 +08:00
|
|
|
|
|
2025-10-21 17:51:12 +08:00
|
|
|
|
let port = verge_mixed_port.unwrap_or(default_port);
|
|
|
|
|
|
let host = proxy_host.unwrap_or_else(|| network::DEFAULT_PROXY_HOST.into());
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
Sysproxy {
|
|
|
|
|
|
enable: true,
|
2025-10-21 17:51:12 +08:00
|
|
|
|
host,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
port,
|
2025-08-26 01:49:51 +08:00
|
|
|
|
bypass: Self::get_bypass_config().await,
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-26 01:49:51 +08:00
|
|
|
|
async fn get_bypass_config() -> String {
|
2025-10-21 17:51:12 +08:00
|
|
|
|
use crate::constants::bypass;
|
2025-10-21 17:53:02 +08:00
|
|
|
|
|
2025-10-21 17:51:12 +08:00
|
|
|
|
let verge_config = Config::verge().await;
|
|
|
|
|
|
let verge = verge_config.latest_ref();
|
|
|
|
|
|
let use_default = verge.use_default_bypass.unwrap_or(true);
|
|
|
|
|
|
let custom = verge.system_proxy_bypass.as_deref().unwrap_or("");
|
|
|
|
|
|
|
|
|
|
|
|
match (use_default, custom.is_empty()) {
|
|
|
|
|
|
(_, true) => bypass::DEFAULT.to_string(),
|
|
|
|
|
|
(true, false) => format!("{},{}", bypass::DEFAULT, custom),
|
|
|
|
|
|
(false, false) => custom.to_string(),
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-18 02:02:25 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
|
async fn restore_pac_proxy(expected_url: &str) -> Result<(), anyhow::Error> {
|
2025-10-11 16:49:47 +08:00
|
|
|
|
if handle::Handle::global().is_exiting() {
|
|
|
|
|
|
log::debug!(target: "app", "应用正在退出,跳过PAC代理恢复");
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
}
|
2025-08-18 02:02:25 +08:00
|
|
|
|
Self::execute_sysproxy_command(&["pac", expected_url]).await
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(clippy::unused_async)]
|
|
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
|
|
async fn restore_pac_proxy(expected_url: &str) -> Result<(), anyhow::Error> {
|
2025-06-21 21:38:42 +08:00
|
|
|
|
{
|
|
|
|
|
|
let new_autoproxy = Autoproxy {
|
|
|
|
|
|
enable: true,
|
|
|
|
|
|
url: expected_url.to_string(),
|
|
|
|
|
|
};
|
2025-08-18 02:02:25 +08:00
|
|
|
|
// logging_error!(Type::System, true, new_autoproxy.set_auto_proxy());
|
|
|
|
|
|
new_autoproxy
|
|
|
|
|
|
.set_auto_proxy()
|
|
|
|
|
|
.map_err(|e| anyhow::anyhow!("Failed to set auto proxy: {}", e))
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-18 02:02:25 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
|
async fn restore_sys_proxy(expected: &Sysproxy) -> Result<(), anyhow::Error> {
|
2025-10-11 16:49:47 +08:00
|
|
|
|
if handle::Handle::global().is_exiting() {
|
|
|
|
|
|
log::debug!(target: "app", "应用正在退出,跳过系统代理恢复");
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
}
|
2025-08-18 02:02:25 +08:00
|
|
|
|
let address = format!("{}:{}", expected.host, expected.port);
|
|
|
|
|
|
Self::execute_sysproxy_command(&["global", &address, &expected.bypass]).await
|
|
|
|
|
|
}
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
2025-08-18 02:02:25 +08:00
|
|
|
|
#[allow(clippy::unused_async)]
|
|
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
|
|
async fn restore_sys_proxy(expected: &Sysproxy) -> Result<(), anyhow::Error> {
|
2025-06-21 21:38:42 +08:00
|
|
|
|
{
|
2025-08-18 02:02:25 +08:00
|
|
|
|
// logging_error!(Type::System, true, expected.set_system_proxy());
|
|
|
|
|
|
expected
|
|
|
|
|
|
.set_system_proxy()
|
|
|
|
|
|
.map_err(|e| anyhow::anyhow!("Failed to set system proxy: {}", e))
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
2025-08-18 02:02:25 +08:00
|
|
|
|
async fn execute_sysproxy_command(args: &[&str]) -> Result<(), anyhow::Error> {
|
2025-10-11 16:49:47 +08:00
|
|
|
|
if handle::Handle::global().is_exiting() {
|
|
|
|
|
|
log::debug!(
|
|
|
|
|
|
target: "app",
|
|
|
|
|
|
"应用正在退出,取消调用 sysproxy.exe,参数: {:?}",
|
|
|
|
|
|
args
|
|
|
|
|
|
);
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-22 21:05:50 +08:00
|
|
|
|
use crate::utils::dirs;
|
|
|
|
|
|
#[allow(unused_imports)] // creation_flags必须
|
|
|
|
|
|
use std::os::windows::process::CommandExt;
|
|
|
|
|
|
use tokio::process::Command;
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
|
|
|
|
|
let binary_path = match dirs::service_path() {
|
|
|
|
|
|
Ok(path) => path,
|
|
|
|
|
|
Err(e) => {
|
2025-06-30 20:48:20 +08:00
|
|
|
|
log::error!(target: "app", "获取服务路径失败: {e}");
|
2025-08-18 02:02:25 +08:00
|
|
|
|
return Err(e);
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let sysproxy_exe = binary_path.with_file_name("sysproxy.exe");
|
|
|
|
|
|
if !sysproxy_exe.exists() {
|
|
|
|
|
|
log::error!(target: "app", "sysproxy.exe 不存在");
|
|
|
|
|
|
}
|
2025-08-18 02:02:25 +08:00
|
|
|
|
anyhow::ensure!(sysproxy_exe.exists(), "sysproxy.exe does not exist");
|
2025-06-21 21:38:42 +08:00
|
|
|
|
|
2025-08-18 02:02:25 +08:00
|
|
|
|
let _output = Command::new(sysproxy_exe)
|
2025-06-21 21:38:42 +08:00
|
|
|
|
.args(args)
|
2025-06-22 21:05:50 +08:00
|
|
|
|
.creation_flags(0x08000000) // CREATE_NO_WINDOW - 隐藏窗口
|
2025-06-21 21:38:42 +08:00
|
|
|
|
.output()
|
2025-08-18 02:02:25 +08:00
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2025-06-21 21:38:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|