Files
clash-verge-rev/src-tauri/src/feat/tun.rs
T

88 lines
2.8 KiB
Rust

//! Reconciles TUN with current Core and Service availability.
use std::sync::atomic::{AtomicBool, Ordering};
use clash_verge_logging::{Type, logging};
use scopeguard::defer;
use crate::{
config::{Config, IVerge},
core::{handle::Handle, manager::RunningMode, runstate::RUN_STATE},
};
/// Prevents recursive runtime disable writes.
static DISABLING_TUN: AtomicBool = AtomicBool::new(false);
/// Suppress TUN for this Windows session when startup confirms the Service is absent.
/// The saved preference remains available for a later Service install.
pub async fn reconcile_startup_tun_availability() {
if !cfg!(target_os = "windows") {
return;
}
// Read fresh state after prior config writes complete.
let _config_write = Config::lock_config_write().await;
let tun_enabled = Config::verge().await.data_arc().enable_tun_mode.unwrap_or(false);
if !RUN_STATE.state().startup_tun_should_be_disabled(tun_enabled) {
return;
}
logging!(
info,
Type::Setup,
"Windows Service is not installed; suppressing TUN mode so the Core can start on Sidecar"
);
Config::suppress_tun_for_session().await;
}
/// Disable TUN when the current settled Run State cannot support it.
pub async fn reconcile_tun_availability() {
if DISABLING_TUN.load(Ordering::Acquire) {
return;
}
// Re-read state and committed config after prior writes complete.
let config_write = Config::lock_config_write().await;
let state = RUN_STATE.state();
// Startup uses the narrower session-suppression path above.
if matches!(state.mode, RunningMode::NotRunning) {
return;
}
if Config::tun_suppressed_for_session() {
return;
}
// Legacy writers may still hold an uncommitted draft.
let tun_enabled = Config::verge().await.data_arc().enable_tun_mode.unwrap_or(false);
if !state.tun_should_be_disabled(tun_enabled) {
return;
}
// The flag coalesces newly spawned tasks while the config lock serializes writers.
DISABLING_TUN.store(true, Ordering::Release);
defer! {
DISABLING_TUN.store(false, Ordering::Release);
}
logging!(
info,
Type::Core,
"TUN mode cannot work in the current run state; turning it off"
);
let patch = IVerge {
enable_tun_mode: Some(false),
..IVerge::default()
};
// Skip recursive reconciliation for this internal patch.
match super::apply_verge_patch_locked(&config_write, &patch, false).await {
Ok(()) => Handle::notice_message("tun_mode::auto_disabled", ""),
Err(error) => {
logging!(error, Type::Core, "failed to turn TUN mode off: {error:#}");
Handle::notice_message("tun_mode::auto_disable_failed", "");
}
}
}