Compare commits
2 Commits
dev
...
refactor-p
@@ -1,7 +1,5 @@
|
|||||||
use super::CmdResult;
|
use super::CmdResult;
|
||||||
use crate::cmd::StringifyErr;
|
use crate::cmd::StringifyErr;
|
||||||
use crate::core::{EventDrivenProxyManager, async_proxy_query::AsyncProxyQuery};
|
|
||||||
use crate::process::AsyncHandler;
|
|
||||||
use crate::{logging, utils::logging::Type};
|
use crate::{logging, utils::logging::Type};
|
||||||
use network_interface::NetworkInterface;
|
use network_interface::NetworkInterface;
|
||||||
use serde_yaml_ng::Mapping;
|
use serde_yaml_ng::Mapping;
|
||||||
@@ -11,23 +9,23 @@ use serde_yaml_ng::Mapping;
|
|||||||
pub async fn get_sys_proxy() -> CmdResult<Mapping> {
|
pub async fn get_sys_proxy() -> CmdResult<Mapping> {
|
||||||
logging!(debug, Type::Network, "异步获取系统代理配置");
|
logging!(debug, Type::Network, "异步获取系统代理配置");
|
||||||
|
|
||||||
let current = AsyncProxyQuery::get_system_proxy().await;
|
let sys_proxy = sysproxy::Sysproxy::get_system_proxy().stringify_err()?;
|
||||||
|
|
||||||
let mut map = Mapping::new();
|
let mut map = Mapping::new();
|
||||||
map.insert("enable".into(), current.enable.into());
|
map.insert("enable".into(), sys_proxy.enable.into());
|
||||||
map.insert(
|
map.insert(
|
||||||
"server".into(),
|
"server".into(),
|
||||||
format!("{}:{}", current.host, current.port).into(),
|
format!("{}:{}", sys_proxy.host, sys_proxy.port).into(),
|
||||||
);
|
);
|
||||||
map.insert("bypass".into(), current.bypass.into());
|
map.insert("bypass".into(), sys_proxy.bypass.into());
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
debug,
|
debug,
|
||||||
Type::Network,
|
Type::Network,
|
||||||
"返回系统代理配置: enable={}, {}:{}",
|
"返回系统代理配置: enable={}, {}:{}",
|
||||||
current.enable,
|
sys_proxy.enable,
|
||||||
current.host,
|
sys_proxy.host,
|
||||||
current.port
|
sys_proxy.port
|
||||||
);
|
);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
@@ -37,24 +35,18 @@ pub async fn get_sys_proxy() -> CmdResult<Mapping> {
|
|||||||
pub async fn get_auto_proxy() -> CmdResult<Mapping> {
|
pub async fn get_auto_proxy() -> CmdResult<Mapping> {
|
||||||
logging!(debug, Type::Network, "开始获取自动代理配置(事件驱动)");
|
logging!(debug, Type::Network, "开始获取自动代理配置(事件驱动)");
|
||||||
|
|
||||||
let proxy_manager = EventDrivenProxyManager::global();
|
let auto_proxy = sysproxy::Autoproxy::get_auto_proxy().stringify_err()?;
|
||||||
|
|
||||||
let current = proxy_manager.get_auto_proxy_cached().await;
|
|
||||||
// 异步请求更新,立即返回缓存数据
|
|
||||||
AsyncHandler::spawn(move || 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(), auto_proxy.enable.into());
|
||||||
map.insert("url".into(), current.url.clone().into());
|
map.insert("url".into(), auto_proxy.url.clone().into());
|
||||||
|
|
||||||
logging!(
|
logging!(
|
||||||
debug,
|
debug,
|
||||||
Type::Network,
|
Type::Network,
|
||||||
"返回自动代理配置(缓存): enable={}, url={}",
|
"返回自动代理配置(缓存): enable={}, url={}",
|
||||||
current.enable,
|
auto_proxy.enable,
|
||||||
current.url
|
auto_proxy.url
|
||||||
);
|
);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub mod network {
|
pub mod network {
|
||||||
pub const DEFAULT_PROXY_HOST: &str = "127.0.0.1";
|
|
||||||
pub const DEFAULT_EXTERNAL_CONTROLLER: &str = "127.0.0.1:9097";
|
pub const DEFAULT_EXTERNAL_CONTROLLER: &str = "127.0.0.1:9097";
|
||||||
|
|
||||||
pub mod ports {
|
pub mod ports {
|
||||||
@@ -20,18 +19,6 @@ pub mod network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod bypass {
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub const DEFAULT: &str = "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")]
|
|
||||||
pub const DEFAULT: &str =
|
|
||||||
"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")]
|
|
||||||
pub const DEFAULT: &str = "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>";
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod timing {
|
pub mod timing {
|
||||||
use super::Duration;
|
use super::Duration;
|
||||||
|
|
||||||
|
|||||||
@@ -1,562 +0,0 @@
|
|||||||
#[cfg(target_os = "windows")]
|
|
||||||
use crate::process::AsyncHandler;
|
|
||||||
use crate::{logging, utils::logging::Type};
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tokio::time::{Duration, timeout};
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use anyhow::anyhow;
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
use tokio::process::Command;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
||||||
pub struct AsyncAutoproxy {
|
|
||||||
pub enable: bool,
|
|
||||||
pub url: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct AsyncSysproxy {
|
|
||||||
pub enable: bool,
|
|
||||||
pub host: String,
|
|
||||||
pub port: u16,
|
|
||||||
pub bypass: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AsyncSysproxy {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
enable: false,
|
|
||||||
host: "127.0.0.1".into(),
|
|
||||||
port: 7897,
|
|
||||||
bypass: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AsyncProxyQuery;
|
|
||||||
|
|
||||||
impl AsyncProxyQuery {
|
|
||||||
/// 异步获取自动代理配置(PAC)
|
|
||||||
pub async fn get_auto_proxy() -> AsyncAutoproxy {
|
|
||||||
match timeout(Duration::from_secs(3), Self::get_auto_proxy_impl()).await {
|
|
||||||
Ok(Ok(proxy)) => {
|
|
||||||
logging!(
|
|
||||||
debug,
|
|
||||||
Type::Network,
|
|
||||||
"异步获取自动代理成功: enable={}, url={}",
|
|
||||||
proxy.enable,
|
|
||||||
proxy.url
|
|
||||||
);
|
|
||||||
proxy
|
|
||||||
}
|
|
||||||
Ok(Err(e)) => {
|
|
||||||
logging!(warn, Type::Network, "Warning: 异步获取自动代理失败: {e}");
|
|
||||||
AsyncAutoproxy::default()
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
logging!(warn, Type::Network, "Warning: 异步获取自动代理超时");
|
|
||||||
AsyncAutoproxy::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 异步获取系统代理配置
|
|
||||||
pub async fn get_system_proxy() -> AsyncSysproxy {
|
|
||||||
match timeout(Duration::from_secs(3), Self::get_system_proxy_impl()).await {
|
|
||||||
Ok(Ok(proxy)) => {
|
|
||||||
logging!(
|
|
||||||
debug,
|
|
||||||
Type::Network,
|
|
||||||
"异步获取系统代理成功: enable={}, {}:{}",
|
|
||||||
proxy.enable,
|
|
||||||
proxy.host,
|
|
||||||
proxy.port
|
|
||||||
);
|
|
||||||
proxy
|
|
||||||
}
|
|
||||||
Ok(Err(e)) => {
|
|
||||||
logging!(warn, Type::Network, "Warning: 异步获取系统代理失败: {e}");
|
|
||||||
AsyncSysproxy::default()
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
logging!(warn, Type::Network, "Warning: 异步获取系统代理超时");
|
|
||||||
AsyncSysproxy::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
async fn get_auto_proxy_impl() -> Result<AsyncAutoproxy> {
|
|
||||||
// Windows: 从注册表读取PAC配置
|
|
||||||
AsyncHandler::spawn_blocking(move || -> Result<AsyncAutoproxy> {
|
|
||||||
Self::get_pac_config_from_registry()
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn get_pac_config_from_registry() -> Result<AsyncAutoproxy> {
|
|
||||||
use std::ptr;
|
|
||||||
use winapi::shared::minwindef::{DWORD, HKEY};
|
|
||||||
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
|
|
||||||
use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
|
|
||||||
.encode_utf16()
|
|
||||||
.collect::<Vec<u16>>();
|
|
||||||
|
|
||||||
let mut hkey: HKEY = ptr::null_mut();
|
|
||||||
let result =
|
|
||||||
RegOpenKeyExW(HKEY_CURRENT_USER, key_path.as_ptr(), 0, KEY_READ, &mut hkey);
|
|
||||||
|
|
||||||
if result != 0 {
|
|
||||||
logging!(debug, Type::Network, "无法打开注册表项");
|
|
||||||
return Ok(AsyncAutoproxy::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 检查自动配置是否启用 (AutoConfigURL 存在且不为空即表示启用)
|
|
||||||
let auto_config_url_name = "AutoConfigURL\0".encode_utf16().collect::<Vec<u16>>();
|
|
||||||
let mut url_buffer = vec![0u16; 1024];
|
|
||||||
let mut url_buffer_size: DWORD = (url_buffer.len() * 2) as DWORD;
|
|
||||||
let mut url_value_type: DWORD = 0;
|
|
||||||
|
|
||||||
let url_query_result = RegQueryValueExW(
|
|
||||||
hkey,
|
|
||||||
auto_config_url_name.as_ptr(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
&mut url_value_type,
|
|
||||||
url_buffer.as_mut_ptr() as *mut u8,
|
|
||||||
&mut url_buffer_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut pac_url = String::new();
|
|
||||||
if url_query_result == 0 && url_value_type == REG_SZ && url_buffer_size > 0 {
|
|
||||||
let end_pos = url_buffer
|
|
||||||
.iter()
|
|
||||||
.position(|&x| x == 0)
|
|
||||||
.unwrap_or(url_buffer.len());
|
|
||||||
pac_url = String::from_utf16_lossy(&url_buffer[..end_pos]);
|
|
||||||
logging!(debug, Type::Network, "从注册表读取到PAC URL: {pac_url}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 检查自动检测设置是否启用
|
|
||||||
let auto_detect_name = "AutoDetect\0".encode_utf16().collect::<Vec<u16>>();
|
|
||||||
let mut auto_detect: DWORD = 0;
|
|
||||||
let mut detect_buffer_size: DWORD = 4;
|
|
||||||
let mut detect_value_type: DWORD = 0;
|
|
||||||
|
|
||||||
let detect_query_result = RegQueryValueExW(
|
|
||||||
hkey,
|
|
||||||
auto_detect_name.as_ptr(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
&mut detect_value_type,
|
|
||||||
&mut auto_detect as *mut DWORD as *mut u8,
|
|
||||||
&mut detect_buffer_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
RegCloseKey(hkey);
|
|
||||||
|
|
||||||
// PAC 启用的条件:AutoConfigURL 不为空,或 AutoDetect 被启用
|
|
||||||
let pac_enabled = !pac_url.is_empty()
|
|
||||||
|| (detect_query_result == 0 && detect_value_type == REG_DWORD && auto_detect != 0);
|
|
||||||
|
|
||||||
if pac_enabled {
|
|
||||||
logging!(
|
|
||||||
debug,
|
|
||||||
Type::Network,
|
|
||||||
"PAC配置启用: URL={pac_url}, AutoDetect={auto_detect}"
|
|
||||||
);
|
|
||||||
|
|
||||||
if pac_url.is_empty() && auto_detect != 0 {
|
|
||||||
pac_url = "auto-detect".into();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AsyncAutoproxy {
|
|
||||||
enable: true,
|
|
||||||
url: pac_url,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
logging!(debug, Type::Network, "PAC配置未启用");
|
|
||||||
Ok(AsyncAutoproxy::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
async fn get_auto_proxy_impl() -> Result<AsyncAutoproxy> {
|
|
||||||
// macOS: 使用 scutil --proxy 命令
|
|
||||||
let output = Command::new("scutil").args(["--proxy"]).output().await?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
return Ok(AsyncAutoproxy::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
crate::logging!(
|
|
||||||
debug,
|
|
||||||
crate::utils::logging::Type::Network,
|
|
||||||
"scutil output: {stdout}"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut pac_enabled = false;
|
|
||||||
let mut pac_url = String::new();
|
|
||||||
|
|
||||||
// 解析 scutil 输出
|
|
||||||
for line in stdout.lines() {
|
|
||||||
let line = line.trim();
|
|
||||||
if line.contains("ProxyAutoConfigEnable") && line.contains("1") {
|
|
||||||
pac_enabled = true;
|
|
||||||
} else if line.contains("ProxyAutoConfigURLString") {
|
|
||||||
// 正确解析包含冒号的URL
|
|
||||||
// 格式: "ProxyAutoConfigURLString : http://127.0.0.1:11233/commands/pac"
|
|
||||||
if let Some(colon_pos) = line.find(" : ") {
|
|
||||||
pac_url = line[colon_pos + 3..].trim().into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::logging!(
|
|
||||||
debug,
|
|
||||||
crate::utils::logging::Type::Network,
|
|
||||||
"解析结果: pac_enabled={pac_enabled}, pac_url={pac_url}"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(AsyncAutoproxy {
|
|
||||||
enable: pac_enabled && !pac_url.is_empty(),
|
|
||||||
url: pac_url,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
async fn get_auto_proxy_impl() -> Result<AsyncAutoproxy> {
|
|
||||||
// Linux: 检查环境变量和GNOME设置
|
|
||||||
|
|
||||||
// 首先检查环境变量
|
|
||||||
if let Ok(auto_proxy) = std::env::var("auto_proxy")
|
|
||||||
&& !auto_proxy.is_empty()
|
|
||||||
{
|
|
||||||
return Ok(AsyncAutoproxy {
|
|
||||||
enable: true,
|
|
||||||
url: auto_proxy,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试使用 gsettings 获取 GNOME 代理设置
|
|
||||||
let output = Command::new("gsettings")
|
|
||||||
.args(["get", "org.gnome.system.proxy", "mode"])
|
|
||||||
.output()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Ok(output) = output
|
|
||||||
&& output.status.success()
|
|
||||||
{
|
|
||||||
let mode: String = String::from_utf8_lossy(&output.stdout).trim().into();
|
|
||||||
if mode.contains("auto") {
|
|
||||||
// 获取 PAC URL
|
|
||||||
let pac_output = Command::new("gsettings")
|
|
||||||
.args(["get", "org.gnome.system.proxy", "autoconfig-url"])
|
|
||||||
.output()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Ok(pac_output) = pac_output
|
|
||||||
&& pac_output.status.success()
|
|
||||||
{
|
|
||||||
let pac_url: String = String::from_utf8_lossy(&pac_output.stdout)
|
|
||||||
.trim()
|
|
||||||
.trim_matches('\'')
|
|
||||||
.trim_matches('"')
|
|
||||||
.into();
|
|
||||||
|
|
||||||
if !pac_url.is_empty() {
|
|
||||||
return Ok(AsyncAutoproxy {
|
|
||||||
enable: true,
|
|
||||||
url: pac_url,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AsyncAutoproxy::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
async fn get_system_proxy_impl() -> Result<AsyncSysproxy> {
|
|
||||||
// Windows: 使用注册表直接读取代理设置
|
|
||||||
AsyncHandler::spawn_blocking(move || -> Result<AsyncSysproxy> {
|
|
||||||
Self::get_system_proxy_from_registry()
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn get_system_proxy_from_registry() -> Result<AsyncSysproxy> {
|
|
||||||
use std::ptr;
|
|
||||||
use winapi::shared::minwindef::{DWORD, HKEY};
|
|
||||||
use winapi::um::winnt::{KEY_READ, REG_DWORD, REG_SZ};
|
|
||||||
use winapi::um::winreg::{HKEY_CURRENT_USER, RegCloseKey, RegOpenKeyExW, RegQueryValueExW};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\0"
|
|
||||||
.encode_utf16()
|
|
||||||
.collect::<Vec<u16>>();
|
|
||||||
|
|
||||||
let mut hkey: HKEY = ptr::null_mut();
|
|
||||||
let result =
|
|
||||||
RegOpenKeyExW(HKEY_CURRENT_USER, key_path.as_ptr(), 0, KEY_READ, &mut hkey);
|
|
||||||
|
|
||||||
if result != 0 {
|
|
||||||
return Ok(AsyncSysproxy::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查代理是否启用
|
|
||||||
let proxy_enable_name = "ProxyEnable\0".encode_utf16().collect::<Vec<u16>>();
|
|
||||||
let mut proxy_enable: DWORD = 0;
|
|
||||||
let mut buffer_size: DWORD = 4;
|
|
||||||
let mut value_type: DWORD = 0;
|
|
||||||
|
|
||||||
let enable_result = RegQueryValueExW(
|
|
||||||
hkey,
|
|
||||||
proxy_enable_name.as_ptr(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
&mut value_type,
|
|
||||||
&mut proxy_enable as *mut DWORD as *mut u8,
|
|
||||||
&mut buffer_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
if enable_result != 0 || value_type != REG_DWORD || proxy_enable == 0 {
|
|
||||||
RegCloseKey(hkey);
|
|
||||||
return Ok(AsyncSysproxy::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取代理服务器设置
|
|
||||||
let proxy_server_name = "ProxyServer\0".encode_utf16().collect::<Vec<u16>>();
|
|
||||||
let mut buffer = vec![0u16; 1024];
|
|
||||||
let mut buffer_size: DWORD = (buffer.len() * 2) as DWORD;
|
|
||||||
let mut value_type: DWORD = 0;
|
|
||||||
|
|
||||||
let server_result = RegQueryValueExW(
|
|
||||||
hkey,
|
|
||||||
proxy_server_name.as_ptr(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
&mut value_type,
|
|
||||||
buffer.as_mut_ptr() as *mut u8,
|
|
||||||
&mut buffer_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut proxy_server = String::new();
|
|
||||||
if server_result == 0 && value_type == REG_SZ && buffer_size > 0 {
|
|
||||||
let end_pos = buffer.iter().position(|&x| x == 0).unwrap_or(buffer.len());
|
|
||||||
proxy_server = String::from_utf16_lossy(&buffer[..end_pos]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取代理绕过列表
|
|
||||||
let proxy_override_name = "ProxyOverride\0".encode_utf16().collect::<Vec<u16>>();
|
|
||||||
let mut bypass_buffer = vec![0u16; 1024];
|
|
||||||
let mut bypass_buffer_size: DWORD = (bypass_buffer.len() * 2) as DWORD;
|
|
||||||
let mut bypass_value_type: DWORD = 0;
|
|
||||||
|
|
||||||
let override_result = RegQueryValueExW(
|
|
||||||
hkey,
|
|
||||||
proxy_override_name.as_ptr(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
&mut bypass_value_type,
|
|
||||||
bypass_buffer.as_mut_ptr() as *mut u8,
|
|
||||||
&mut bypass_buffer_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut bypass_list = String::new();
|
|
||||||
if override_result == 0 && bypass_value_type == REG_SZ && bypass_buffer_size > 0 {
|
|
||||||
let end_pos = bypass_buffer
|
|
||||||
.iter()
|
|
||||||
.position(|&x| x == 0)
|
|
||||||
.unwrap_or(bypass_buffer.len());
|
|
||||||
bypass_list = String::from_utf16_lossy(&bypass_buffer[..end_pos]);
|
|
||||||
}
|
|
||||||
|
|
||||||
RegCloseKey(hkey);
|
|
||||||
|
|
||||||
if !proxy_server.is_empty() {
|
|
||||||
// 解析服务器地址和端口
|
|
||||||
let (host, port) = if let Some(colon_pos) = proxy_server.rfind(':') {
|
|
||||||
let host = proxy_server[..colon_pos].into();
|
|
||||||
let port = proxy_server[colon_pos + 1..].parse::<u16>().unwrap_or(8080);
|
|
||||||
(host, port)
|
|
||||||
} else {
|
|
||||||
(proxy_server, 8080)
|
|
||||||
};
|
|
||||||
|
|
||||||
logging!(
|
|
||||||
debug,
|
|
||||||
Type::Network,
|
|
||||||
"从注册表读取到代理设置: {host}:{port}, bypass: {bypass_list}"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(AsyncSysproxy {
|
|
||||||
enable: true,
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
bypass: bypass_list,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(AsyncSysproxy::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
async fn get_system_proxy_impl() -> Result<AsyncSysproxy> {
|
|
||||||
let output = Command::new("scutil").args(["--proxy"]).output().await?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
return Ok(AsyncSysproxy::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
logging!(debug, Type::Network, "scutil proxy output: {stdout}");
|
|
||||||
|
|
||||||
let mut http_enabled = false;
|
|
||||||
let mut http_host = String::new();
|
|
||||||
let mut http_port = 8080u16;
|
|
||||||
let mut exceptions: Vec<String> = Vec::new();
|
|
||||||
|
|
||||||
for line in stdout.lines() {
|
|
||||||
let line = line.trim();
|
|
||||||
if line.contains("HTTPEnable") && line.contains("1") {
|
|
||||||
http_enabled = true;
|
|
||||||
} else if line.contains("HTTPProxy") && !line.contains("Port") {
|
|
||||||
if let Some(host_part) = line.split(':').nth(1) {
|
|
||||||
http_host = host_part.trim().into();
|
|
||||||
}
|
|
||||||
} else if line.contains("HTTPPort") {
|
|
||||||
if let Some(port_part) = line.split(':').nth(1)
|
|
||||||
&& let Ok(port) = port_part.trim().parse::<u16>()
|
|
||||||
{
|
|
||||||
http_port = port;
|
|
||||||
}
|
|
||||||
} else if line.contains("ExceptionsList") {
|
|
||||||
// 解析异常列表
|
|
||||||
if let Some(list_part) = line.split(':').nth(1) {
|
|
||||||
let list = list_part.trim();
|
|
||||||
if !list.is_empty() {
|
|
||||||
exceptions.push(list.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AsyncSysproxy {
|
|
||||||
enable: http_enabled && !http_host.is_empty(),
|
|
||||||
host: http_host,
|
|
||||||
port: http_port,
|
|
||||||
bypass: exceptions.join(","),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
async fn get_system_proxy_impl() -> Result<AsyncSysproxy> {
|
|
||||||
// Linux: 检查环境变量和桌面环境设置
|
|
||||||
|
|
||||||
// 首先检查环境变量
|
|
||||||
if let Ok(http_proxy) = std::env::var("http_proxy")
|
|
||||||
&& let Ok(proxy_info) = Self::parse_proxy_url(&http_proxy)
|
|
||||||
{
|
|
||||||
return Ok(proxy_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(https_proxy) = std::env::var("https_proxy")
|
|
||||||
&& let Ok(proxy_info) = Self::parse_proxy_url(&https_proxy)
|
|
||||||
{
|
|
||||||
return Ok(proxy_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试使用 gsettings 获取 GNOME 代理设置
|
|
||||||
let mode_output = Command::new("gsettings")
|
|
||||||
.args(["get", "org.gnome.system.proxy", "mode"])
|
|
||||||
.output()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Ok(mode_output) = mode_output
|
|
||||||
&& mode_output.status.success()
|
|
||||||
{
|
|
||||||
let mode: String = String::from_utf8_lossy(&mode_output.stdout).trim().into();
|
|
||||||
if mode.contains("manual") {
|
|
||||||
// 获取HTTP代理设置
|
|
||||||
let host_result = Command::new("gsettings")
|
|
||||||
.args(["get", "org.gnome.system.proxy.http", "host"])
|
|
||||||
.output()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let port_result = Command::new("gsettings")
|
|
||||||
.args(["get", "org.gnome.system.proxy.http", "port"])
|
|
||||||
.output()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let (Ok(host_output), Ok(port_output)) = (host_result, port_result)
|
|
||||||
&& host_output.status.success()
|
|
||||||
&& port_output.status.success()
|
|
||||||
{
|
|
||||||
let host: String = String::from_utf8_lossy(&host_output.stdout)
|
|
||||||
.trim()
|
|
||||||
.trim_matches('\'')
|
|
||||||
.trim_matches('"')
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let port = String::from_utf8_lossy(&port_output.stdout)
|
|
||||||
.trim()
|
|
||||||
.parse::<u16>()
|
|
||||||
.unwrap_or(8080);
|
|
||||||
|
|
||||||
if !host.is_empty() {
|
|
||||||
return Ok(AsyncSysproxy {
|
|
||||||
enable: true,
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
bypass: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AsyncSysproxy::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn parse_proxy_url(proxy_url: &str) -> Result<AsyncSysproxy> {
|
|
||||||
// 解析形如 "http://proxy.example.com:8080" 的URL
|
|
||||||
let url = proxy_url.trim();
|
|
||||||
|
|
||||||
// 移除协议前缀
|
|
||||||
let url = if let Some(stripped) = url.strip_prefix("http://") {
|
|
||||||
stripped
|
|
||||||
} else if let Some(stripped) = url.strip_prefix("https://") {
|
|
||||||
stripped
|
|
||||||
} else {
|
|
||||||
url
|
|
||||||
};
|
|
||||||
|
|
||||||
// 解析主机和端口
|
|
||||||
let (host, port) = if let Some(colon_pos) = url.rfind(':') {
|
|
||||||
let host: String = url[..colon_pos].into();
|
|
||||||
let port = url[colon_pos + 1..].parse::<u16>().unwrap_or(8080);
|
|
||||||
(host, port)
|
|
||||||
} else {
|
|
||||||
(url.into(), 8080)
|
|
||||||
};
|
|
||||||
|
|
||||||
if host.is_empty() {
|
|
||||||
return Err(anyhow!("无效的代理URL"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(AsyncSysproxy {
|
|
||||||
enable: true,
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
bypass: std::env::var("no_proxy").unwrap_or_default(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,548 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::RwLock;
|
|
||||||
use tokio::sync::{mpsc, oneshot};
|
|
||||||
use tokio::time::{Duration, sleep, timeout};
|
|
||||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
|
||||||
|
|
||||||
use crate::config::{Config, IVerge};
|
|
||||||
use crate::core::{async_proxy_query::AsyncProxyQuery, handle};
|
|
||||||
use crate::process::AsyncHandler;
|
|
||||||
use crate::{logging, utils::logging::Type};
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use smartstring::alias::String;
|
|
||||||
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,
|
|
||||||
url: "".into(),
|
|
||||||
},
|
|
||||||
sys_proxy: Sysproxy {
|
|
||||||
enable: false,
|
|
||||||
host: "127.0.0.1".into(),
|
|
||||||
port: 7897,
|
|
||||||
bypass: "".into(),
|
|
||||||
},
|
|
||||||
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)]
|
|
||||||
pub struct QueryRequest {
|
|
||||||
response_tx: oneshot::Sender<Autoproxy>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置结构体移到外部
|
|
||||||
struct ProxyConfig {
|
|
||||||
sys_enabled: bool,
|
|
||||||
pac_enabled: bool,
|
|
||||||
guard_enabled: bool,
|
|
||||||
guard_duration: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
let state_clone = Arc::clone(&state);
|
|
||||||
AsyncHandler::spawn(move || Self::start_event_loop(state_clone, event_rx, query_rx));
|
|
||||||
|
|
||||||
Self {
|
|
||||||
state,
|
|
||||||
event_sender: event_tx,
|
|
||||||
query_sender: query_tx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 获取自动代理配置(缓存)
|
|
||||||
pub async fn get_auto_proxy_cached(&self) -> Autoproxy {
|
|
||||||
self.state.read().await.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() {
|
|
||||||
logging!(error, Type::Network, "发送查询请求失败,返回缓存数据");
|
|
||||||
return self.get_auto_proxy_cached().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
match timeout(Duration::from_secs(5), rx).await {
|
|
||||||
Ok(Ok(result)) => result,
|
|
||||||
_ => {
|
|
||||||
logging!(warn, Type::Network, "Warning: 查询超时,返回缓存数据");
|
|
||||||
self.get_auto_proxy_cached().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 通知配置变更
|
|
||||||
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) {
|
|
||||||
logging!(error, Type::Network, "发送代理事件失败: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn start_event_loop(
|
|
||||||
state: Arc<RwLock<ProxyState>>,
|
|
||||||
event_rx: mpsc::UnboundedReceiver<ProxyEvent>,
|
|
||||||
query_rx: mpsc::UnboundedReceiver<QueryRequest>,
|
|
||||||
) {
|
|
||||||
logging!(info, Type::Network, "事件驱动代理管理器启动");
|
|
||||||
|
|
||||||
// 将 mpsc 接收器包装成 Stream,避免每次循环创建 future
|
|
||||||
let mut event_stream = UnboundedReceiverStream::new(event_rx);
|
|
||||||
let mut query_stream = UnboundedReceiverStream::new(query_rx);
|
|
||||||
|
|
||||||
// 初始化定时器,用于周期性检查代理设置
|
|
||||||
let config = Self::get_proxy_config().await;
|
|
||||||
let mut guard_interval = tokio::time::interval(Duration::from_secs(config.guard_duration));
|
|
||||||
// 防止首次立即触发
|
|
||||||
guard_interval.tick().await;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
Some(event) = event_stream.next() => {
|
|
||||||
logging!(debug, Type::Network, "处理代理事件: {event:?}");
|
|
||||||
let event_clone = event.clone(); // 保存一份副本用于后续检查
|
|
||||||
Self::handle_event(&state, event).await;
|
|
||||||
|
|
||||||
// 检查是否是配置变更事件,如果是,则可能需要更新定时器
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(query) = query_stream.next() => {
|
|
||||||
let result = Self::handle_query(&state).await;
|
|
||||||
let _ = query.response_tx.send(result);
|
|
||||||
}
|
|
||||||
_ = guard_interval.tick() => {
|
|
||||||
// 定时检查代理设置
|
|
||||||
let config = Self::get_proxy_config().await;
|
|
||||||
if config.guard_enabled && config.sys_enabled {
|
|
||||||
logging!(debug, Type::Network, "定时检查代理设置");
|
|
||||||
Self::check_and_restore_proxy(&state).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else => {
|
|
||||||
// 两个通道都关闭时退出
|
|
||||||
logging!(info, Type::Network, "事件或查询通道关闭,代理管理器停止");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_event(state: &Arc<RwLock<ProxyState>>, event: ProxyEvent) {
|
|
||||||
match event {
|
|
||||||
ProxyEvent::ConfigChanged => {
|
|
||||||
Self::update_proxy_config(state).await;
|
|
||||||
}
|
|
||||||
ProxyEvent::AppStarted => {
|
|
||||||
Self::initialize_proxy_state(state).await;
|
|
||||||
}
|
|
||||||
ProxyEvent::AppStopping => {
|
|
||||||
logging!(info, Type::Network, "清理代理状态");
|
|
||||||
Self::update_state_timestamp(state, |s| {
|
|
||||||
s.sys_enabled = false;
|
|
||||||
s.pac_enabled = false;
|
|
||||||
s.is_healthy = false;
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
auto_proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn initialize_proxy_state(state: &Arc<RwLock<ProxyState>>) {
|
|
||||||
logging!(info, Type::Network, "初始化代理状态");
|
|
||||||
|
|
||||||
let config = Self::get_proxy_config().await;
|
|
||||||
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;
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
logging!(
|
|
||||||
info,
|
|
||||||
Type::Network,
|
|
||||||
"代理状态初始化完成: sys={}, pac={}",
|
|
||||||
config.sys_enabled,
|
|
||||||
config.pac_enabled
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_proxy_config(state: &Arc<RwLock<ProxyState>>) {
|
|
||||||
logging!(debug, Type::Network, "更新代理配置");
|
|
||||||
|
|
||||||
let config = Self::get_proxy_config().await;
|
|
||||||
|
|
||||||
Self::update_state_timestamp(state, |s| {
|
|
||||||
s.sys_enabled = config.sys_enabled;
|
|
||||||
s.pac_enabled = config.pac_enabled;
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if config.guard_enabled && config.sys_enabled {
|
|
||||||
Self::check_and_restore_proxy(state).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn check_and_restore_proxy(state: &Arc<RwLock<ProxyState>>) {
|
|
||||||
if handle::Handle::global().is_exiting() {
|
|
||||||
logging!(debug, Type::Network, "应用正在退出,跳过系统代理守卫检查");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let (sys_enabled, pac_enabled) = {
|
|
||||||
let s = state.read().await;
|
|
||||||
(s.sys_enabled, s.pac_enabled)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !sys_enabled {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logging!(debug, Type::Network, "检查代理状态");
|
|
||||||
|
|
||||||
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>>) {
|
|
||||||
if handle::Handle::global().is_exiting() {
|
|
||||||
logging!(debug, Type::Network, "应用正在退出,跳过PAC代理恢复检查");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current = Self::get_auto_proxy_with_timeout().await;
|
|
||||||
let expected = Self::get_expected_pac_config().await;
|
|
||||||
|
|
||||||
Self::update_state_timestamp(state, |s| {
|
|
||||||
s.auto_proxy = current.clone();
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if !current.enable || current.url != expected.url {
|
|
||||||
logging!(info, Type::Network, "PAC代理设置异常,正在恢复...");
|
|
||||||
if let Err(e) = Self::restore_pac_proxy(&expected.url).await {
|
|
||||||
logging!(error, Type::Network, "恢复PAC代理失败: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn check_and_restore_sys_proxy(state: &Arc<RwLock<ProxyState>>) {
|
|
||||||
if handle::Handle::global().is_exiting() {
|
|
||||||
logging!(debug, Type::Network, "应用正在退出,跳过系统代理恢复检查");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current = Self::get_sys_proxy_with_timeout().await;
|
|
||||||
let expected = Self::get_expected_sys_proxy().await;
|
|
||||||
|
|
||||||
Self::update_state_timestamp(state, |s| {
|
|
||||||
s.sys_proxy = current.clone();
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if !current.enable || current.host != expected.host || current.port != expected.port {
|
|
||||||
logging!(info, Type::Network, "系统代理设置异常,正在恢复...");
|
|
||||||
if let Err(e) = Self::restore_sys_proxy(&expected).await {
|
|
||||||
logging!(error, Type::Network, "恢复系统代理失败: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_auto_proxy_with_timeout() -> Autoproxy {
|
|
||||||
let async_proxy = AsyncProxyQuery::get_auto_proxy().await;
|
|
||||||
|
|
||||||
// 转换为兼容的结构
|
|
||||||
Autoproxy {
|
|
||||||
enable: async_proxy.enable,
|
|
||||||
url: async_proxy.url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_sys_proxy_with_timeout() -> Sysproxy {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统一的状态更新方法
|
|
||||||
async fn update_state_timestamp<F>(state: &Arc<RwLock<ProxyState>>, update_fn: F)
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut ProxyState),
|
|
||||||
{
|
|
||||||
let mut state_guard = state.write().await;
|
|
||||||
update_fn(&mut state_guard);
|
|
||||||
state_guard.last_updated = std::time::Instant::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_proxy_config() -> ProxyConfig {
|
|
||||||
let (sys_enabled, pac_enabled, guard_enabled, guard_duration) = {
|
|
||||||
let verge_config = Config::verge().await;
|
|
||||||
let verge = verge_config.latest_ref();
|
|
||||||
(
|
|
||||||
verge.enable_system_proxy.unwrap_or(false),
|
|
||||||
verge.proxy_auto_config.unwrap_or(false),
|
|
||||||
verge.enable_proxy_guard.unwrap_or(false),
|
|
||||||
verge.proxy_guard_duration.unwrap_or(30), // 默认30秒
|
|
||||||
)
|
|
||||||
};
|
|
||||||
ProxyConfig {
|
|
||||||
sys_enabled,
|
|
||||||
pac_enabled,
|
|
||||||
guard_enabled,
|
|
||||||
guard_duration,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_expected_pac_config() -> Autoproxy {
|
|
||||||
let proxy_host = {
|
|
||||||
let verge_config = Config::verge().await;
|
|
||||||
let verge = verge_config.latest_ref();
|
|
||||||
verge
|
|
||||||
.proxy_host
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| "127.0.0.1".into())
|
|
||||||
};
|
|
||||||
let pac_port = IVerge::get_singleton_port();
|
|
||||||
Autoproxy {
|
|
||||||
enable: true,
|
|
||||||
url: format!("http://{proxy_host}:{pac_port}/commands/pac"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_expected_sys_proxy() -> Sysproxy {
|
|
||||||
use crate::constants::network;
|
|
||||||
|
|
||||||
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())
|
|
||||||
};
|
|
||||||
|
|
||||||
let default_port = {
|
|
||||||
let clash_config = Config::clash().await;
|
|
||||||
clash_config.latest_ref().get_mixed_port()
|
|
||||||
};
|
|
||||||
|
|
||||||
let port = verge_mixed_port.unwrap_or(default_port);
|
|
||||||
let host = proxy_host
|
|
||||||
.unwrap_or_else(|| network::DEFAULT_PROXY_HOST.into())
|
|
||||||
.into();
|
|
||||||
|
|
||||||
Sysproxy {
|
|
||||||
enable: true,
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
bypass: Self::get_bypass_config().await.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_bypass_config() -> String {
|
|
||||||
use crate::constants::bypass;
|
|
||||||
|
|
||||||
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.into(),
|
|
||||||
(true, false) => format!("{},{}", bypass::DEFAULT, custom).into(),
|
|
||||||
(false, false) => custom.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
async fn restore_pac_proxy(expected_url: &str) -> Result<(), anyhow::Error> {
|
|
||||||
if handle::Handle::global().is_exiting() {
|
|
||||||
logging!(debug, Type::Network, "应用正在退出,跳过PAC代理恢复");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
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> {
|
|
||||||
{
|
|
||||||
let new_autoproxy = Autoproxy {
|
|
||||||
enable: true,
|
|
||||||
url: expected_url.to_string(),
|
|
||||||
};
|
|
||||||
// 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
async fn restore_sys_proxy(expected: &Sysproxy) -> Result<(), anyhow::Error> {
|
|
||||||
if handle::Handle::global().is_exiting() {
|
|
||||||
logging!(debug, Type::Network, "应用正在退出,跳过系统代理恢复");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let address = format!("{}:{}", expected.host, expected.port);
|
|
||||||
Self::execute_sysproxy_command(&["global", &address, &expected.bypass]).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::unused_async)]
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
async fn restore_sys_proxy(expected: &Sysproxy) -> Result<(), anyhow::Error> {
|
|
||||||
{
|
|
||||||
// logging_error!(Type::System, true, expected.set_system_proxy());
|
|
||||||
expected
|
|
||||||
.set_system_proxy()
|
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to set system proxy: {}", e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
async fn execute_sysproxy_command(args: &[&str]) -> Result<(), anyhow::Error> {
|
|
||||||
if handle::Handle::global().is_exiting() {
|
|
||||||
logging!(
|
|
||||||
debug,
|
|
||||||
Type::Network,
|
|
||||||
"应用正在退出,取消调用 sysproxy.exe,参数: {:?}",
|
|
||||||
args
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
use crate::utils::dirs;
|
|
||||||
#[allow(unused_imports)] // creation_flags必须
|
|
||||||
use std::os::windows::process::CommandExt;
|
|
||||||
use tokio::process::Command;
|
|
||||||
|
|
||||||
let binary_path = match dirs::service_path() {
|
|
||||||
Ok(path) => path,
|
|
||||||
Err(e) => {
|
|
||||||
logging!(error, Type::Network, "获取服务路径失败: {e}");
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sysproxy_exe = binary_path.with_file_name("sysproxy.exe");
|
|
||||||
if !sysproxy_exe.exists() {
|
|
||||||
logging!(error, Type::Network, "sysproxy.exe 不存在");
|
|
||||||
}
|
|
||||||
anyhow::ensure!(sysproxy_exe.exists(), "sysproxy.exe does not exist");
|
|
||||||
|
|
||||||
let _output = Command::new(sysproxy_exe)
|
|
||||||
.args(args)
|
|
||||||
.creation_flags(0x08000000) // CREATE_NO_WINDOW - 隐藏窗口
|
|
||||||
.output()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
pub mod async_proxy_query;
|
|
||||||
pub mod backup;
|
pub mod backup;
|
||||||
pub mod event_driven_proxy;
|
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
pub mod hotkey;
|
pub mod hotkey;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
@@ -13,4 +11,4 @@ pub mod tray;
|
|||||||
pub mod validate;
|
pub mod validate;
|
||||||
pub mod win_uwp;
|
pub mod win_uwp;
|
||||||
|
|
||||||
pub use self::{event_driven_proxy::EventDrivenProxyManager, manager::CoreManager, timer::Timer};
|
pub use self::{manager::CoreManager, timer::Timer};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
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::{EventDrivenProxyManager, handle::Handle},
|
core::handle::Handle,
|
||||||
logging, logging_error, singleton_lazy,
|
logging, logging_error, singleton_lazy,
|
||||||
utils::logging::Type,
|
utils::logging::Type,
|
||||||
};
|
};
|
||||||
@@ -100,15 +100,6 @@ impl Sysopt {
|
|||||||
self.initialed.load(Ordering::SeqCst)
|
self.initialed.load(Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_guard_sysproxy(&self) -> Result<()> {
|
|
||||||
// 使用事件驱动代理管理器
|
|
||||||
let proxy_manager = EventDrivenProxyManager::global();
|
|
||||||
proxy_manager.notify_app_started();
|
|
||||||
|
|
||||||
logging!(info, Type::Core, "已启用事件驱动代理守卫");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// init the sysproxy
|
/// init the sysproxy
|
||||||
pub async fn update_sysproxy(&self) -> Result<()> {
|
pub async fn update_sysproxy(&self) -> Result<()> {
|
||||||
self.initialed.store(true, Ordering::SeqCst);
|
self.initialed.store(true, Ordering::SeqCst);
|
||||||
@@ -161,8 +152,6 @@ 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(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,8 +160,6 @@ 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(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,8 +168,6 @@ 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(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,8 +175,6 @@ impl Sysopt {
|
|||||||
{
|
{
|
||||||
if !sys_enable {
|
if !sys_enable {
|
||||||
let result = self.reset_sysproxy().await;
|
let result = self.reset_sysproxy().await;
|
||||||
let proxy_manager = EventDrivenProxyManager::global();
|
|
||||||
proxy_manager.notify_config_changed();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +189,6 @@ impl Sysopt {
|
|||||||
|
|
||||||
execute_sysproxy_command(args).await?;
|
execute_sysproxy_command(args).await?;
|
||||||
}
|
}
|
||||||
let proxy_manager = EventDrivenProxyManager::global();
|
|
||||||
proxy_manager.notify_config_changed();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::core::event_driven_proxy::EventDrivenProxyManager;
|
|
||||||
use crate::core::{CoreManager, handle, sysopt};
|
use crate::core::{CoreManager, handle, sysopt};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use crate::utils::window_manager::WindowManager;
|
use crate::utils::window_manager::WindowManager;
|
||||||
@@ -24,7 +23,6 @@ pub async fn quit() {
|
|||||||
// 获取应用句柄并设置退出标志
|
// 获取应用句柄并设置退出标志
|
||||||
let app_handle = handle::Handle::app_handle();
|
let app_handle = handle::Handle::app_handle();
|
||||||
handle::Handle::global().set_is_exiting();
|
handle::Handle::global().set_is_exiting();
|
||||||
EventDrivenProxyManager::global().notify_app_stopping();
|
|
||||||
|
|
||||||
logging!(info, Type::System, "开始异步清理资源");
|
logging!(info, Type::System, "开始异步清理资源");
|
||||||
let cleanup_result = clean_async().await;
|
let cleanup_result = clean_async().await;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::utils::linux;
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use crate::utils::window_manager::WindowManager;
|
use crate::utils::window_manager::WindowManager;
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{EventDrivenProxyManager, handle, hotkey},
|
core::{handle, hotkey},
|
||||||
process::AsyncHandler,
|
process::AsyncHandler,
|
||||||
utils::{resolve, server},
|
utils::{resolve, server},
|
||||||
};
|
};
|
||||||
@@ -429,7 +429,6 @@ pub fn run() {
|
|||||||
let handle = core::handle::Handle::global();
|
let handle = core::handle::Handle::global();
|
||||||
if !handle.is_exiting() {
|
if !handle.is_exiting() {
|
||||||
handle.set_is_exiting();
|
handle.set_is_exiting();
|
||||||
EventDrivenProxyManager::global().notify_app_stopping();
|
|
||||||
feat::clean();
|
feat::clean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ pub fn resolve_setup_async() {
|
|||||||
init_service_manager().await;
|
init_service_manager().await;
|
||||||
init_core_manager().await;
|
init_core_manager().await;
|
||||||
init_system_proxy().await;
|
init_system_proxy().await;
|
||||||
AsyncHandler::spawn_blocking(init_system_proxy_guard);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let tray_init = async {
|
let tray_init = async {
|
||||||
@@ -168,10 +167,6 @@ pub(super) async fn init_system_proxy() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn init_system_proxy_guard() {
|
|
||||||
logging_error!(Type::Setup, sysopt::Sysopt::global().init_guard_sysproxy());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn refresh_tray_menu() {
|
pub(super) async fn refresh_tray_menu() {
|
||||||
logging_error!(Type::Setup, Tray::global().update_part().await);
|
logging_error!(Type::Setup, Tray::global().update_part().await);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user