mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-20 17:22:08 +08:00
refactor(sysproxy): delegate macOS network monitoring to sysproxy-rs
This commit is contained in:
Generated
+2
-4
@@ -1140,7 +1140,6 @@ dependencies = [
|
||||
"clash-verge-media-unlock",
|
||||
"clash-verge-signal",
|
||||
"clash_verge_service_ipc",
|
||||
"core-foundation 0.9.4",
|
||||
"criterion",
|
||||
"dark-light",
|
||||
"deelevate",
|
||||
@@ -1175,7 +1174,6 @@ dependencies = [
|
||||
"smartstring",
|
||||
"socket2 0.6.5",
|
||||
"sysproxy",
|
||||
"system-configuration",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-autostart",
|
||||
@@ -7015,8 +7013,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysproxy"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/clash-verge-rev/sysproxy-rs.git?branch=main#61118cab4878ce66b8cb12b467b682b493f20e6c"
|
||||
version = "0.7.1"
|
||||
source = "git+https://github.com/clash-verge-rev/sysproxy-rs.git?branch=main#44aaf00ec9c6779e5a461a55d882eddff7841c98"
|
||||
dependencies = [
|
||||
"iptools",
|
||||
"log",
|
||||
|
||||
@@ -115,8 +115,6 @@ libc = "0.2.189"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
tauri-plugin-wdio-webdriver = { version = "=1.3.0", optional = true }
|
||||
core-foundation = "0.9"
|
||||
system-configuration = "0.7"
|
||||
objc2 = "0.6.4"
|
||||
objc2-foundation = { version = "0.3.2", features = [
|
||||
"NSString",
|
||||
|
||||
@@ -476,10 +476,7 @@ impl CoreManager {
|
||||
// rather than fail — only if the watcher is actually live; a user toggling while
|
||||
// offline still fails fast.
|
||||
#[cfg(target_os = "macos")]
|
||||
let watcher_armed = crate::core::network_watch::is_armed();
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let watcher_armed = false;
|
||||
if watcher_armed
|
||||
if crate::core::network_watch::is_armed()
|
||||
&& !crate::utils::resolve::is_resolve_done()
|
||||
&& Config::verge()
|
||||
.await
|
||||
|
||||
@@ -5,53 +5,35 @@
|
||||
|
||||
use crate::{config::Config, core::CoreManager, core::proxy_control, process::AsyncHandler};
|
||||
use clash_verge_logging::{Type, logging};
|
||||
use core_foundation::{
|
||||
array::CFArray,
|
||||
runloop::{CFRunLoop, kCFRunLoopCommonModes},
|
||||
string::CFString,
|
||||
};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use system_configuration::dynamic_store::{SCDynamicStore, SCDynamicStoreBuilder, SCDynamicStoreCallBackContext};
|
||||
use parking_lot::Mutex;
|
||||
use sysproxy::NetworkServiceMonitor;
|
||||
|
||||
/// Set once the subscription is live. Startup defers the proxy write to the watcher only then.
|
||||
static ARMED: AtomicBool = AtomicBool::new(false);
|
||||
static MONITOR: Mutex<Option<NetworkServiceMonitor>> = Mutex::new(None);
|
||||
|
||||
pub fn is_armed() -> bool {
|
||||
ARMED.load(Ordering::Acquire)
|
||||
MONITOR.lock().is_some()
|
||||
}
|
||||
|
||||
/// Subscribe to the primary IPv4 service on the main run loop. Armed on return, so a service
|
||||
/// appearing from here on is never missed.
|
||||
pub fn start() {
|
||||
let store = SCDynamicStoreBuilder::new("clash-verge-rev")
|
||||
.callback_context(SCDynamicStoreCallBackContext {
|
||||
callout: on_change,
|
||||
info: (),
|
||||
})
|
||||
.build();
|
||||
let keys = CFArray::from_CFTypes(&[CFString::from_static_string("State:/Network/Global/IPv4")]);
|
||||
let Some(source) = store
|
||||
.filter(|store| store.set_notification_keys(&keys, &CFArray::<CFString>::from_CFTypes(&[])))
|
||||
.and_then(|store| store.create_run_loop_source())
|
||||
else {
|
||||
logging!(
|
||||
match NetworkServiceMonitor::start(|| {
|
||||
AsyncHandler::spawn(reapply);
|
||||
}) {
|
||||
Ok(monitor) => {
|
||||
*MONITOR.lock() = Some(monitor);
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
"network watch armed; the system proxy is re-applied on network changes"
|
||||
);
|
||||
}
|
||||
Err(error) => logging!(
|
||||
warn,
|
||||
Type::Core,
|
||||
"could not watch the network; the proxy is not re-applied on changes"
|
||||
);
|
||||
return;
|
||||
};
|
||||
CFRunLoop::get_main().add_source(&source, unsafe { kCFRunLoopCommonModes });
|
||||
ARMED.store(true, Ordering::Release);
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
"network watch armed; the system proxy is re-applied on network changes"
|
||||
);
|
||||
}
|
||||
|
||||
fn on_change(_: SCDynamicStore, _: CFArray<CFString>, (): &mut ()) {
|
||||
AsyncHandler::spawn(reapply);
|
||||
"could not watch the network; the proxy is not re-applied on changes: {error}"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
async fn reapply() {
|
||||
@@ -66,10 +48,17 @@ async fn reapply() {
|
||||
.latest_arc()
|
||||
.enable_system_proxy
|
||||
.unwrap_or_default()
|
||||
|| !proxy_control::has_network_service().await
|
||||
{
|
||||
return;
|
||||
}
|
||||
if !proxy_control::has_network_service().await {
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
"network changed without a service to write the proxy on; waiting for the next change"
|
||||
);
|
||||
return;
|
||||
}
|
||||
if let Err(error) = manager.apply_proxy_after_start().await {
|
||||
logging!(
|
||||
warn,
|
||||
|
||||
@@ -385,12 +385,11 @@ async fn current_service_proxy_config(verge: &IVerge) -> Result<MacosProxyConfig
|
||||
}
|
||||
|
||||
/// Whether macOS has a network service to write the proxy on right now.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub async fn has_network_service() -> bool {
|
||||
tokio::task::spawn_blocking(
|
||||
|| !matches!(sysproxy::Sysproxy::get_system_proxy(), Err(error) if is_missing_network_service(&error)),
|
||||
)
|
||||
.await
|
||||
.unwrap_or(true)
|
||||
tokio::task::spawn_blocking(|| sysproxy::Sysproxy::has_network_service().unwrap_or(true))
|
||||
.await
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
pub fn is_reportable(error: &anyhow::Error) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user