mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-08 19:22:44 +08:00
fix(sysproxy): keep the system proxy usable when the core is not ready
This commit is contained in:
@@ -2,7 +2,7 @@ use super::{CoreManager, RunningMode};
|
||||
use crate::config::{Config, IVerge};
|
||||
use crate::core::handle::Handle;
|
||||
use crate::core::manager::CLASH_LOGGER;
|
||||
use crate::core::proxy_control;
|
||||
use crate::core::proxy_control::{self, SysproxyFailure};
|
||||
use crate::core::service::{SERVICE_MANAGER, ServiceStatus};
|
||||
use anyhow::{Result, ensure};
|
||||
use clash_verge_logging::{Type, logging};
|
||||
@@ -304,7 +304,10 @@ impl CoreManager {
|
||||
let _life = self.lifecycle_lock.lock().await;
|
||||
run_core_start_transition(
|
||||
|| self.start_core_inner(),
|
||||
|| !matches!(*self.get_running_mode(), RunningMode::NotRunning),
|
||||
|| {
|
||||
!matches!(*self.get_running_mode(), RunningMode::NotRunning)
|
||||
&& self.current_core_readiness_generation().is_some()
|
||||
},
|
||||
|| self.apply_proxy_after_start(),
|
||||
)
|
||||
.await
|
||||
@@ -330,7 +333,9 @@ impl CoreManager {
|
||||
proxy_control::stop_guard().await;
|
||||
let result = async {
|
||||
self.start_core_inner().await?;
|
||||
if !matches!(*self.get_running_mode(), RunningMode::Sidecar) {
|
||||
if !matches!(*self.get_running_mode(), RunningMode::Sidecar)
|
||||
|| self.current_core_readiness_generation().is_none()
|
||||
{
|
||||
anyhow::bail!("Sidecar did not become ready");
|
||||
}
|
||||
self.apply_proxy_after_start().await
|
||||
@@ -371,7 +376,9 @@ impl CoreManager {
|
||||
},
|
||||
|| async {
|
||||
self.start_core_inner().await?;
|
||||
if !matches!(*self.get_running_mode(), RunningMode::Sidecar) {
|
||||
if !matches!(*self.get_running_mode(), RunningMode::Sidecar)
|
||||
|| self.current_core_readiness_generation().is_none()
|
||||
{
|
||||
anyhow::bail!("Sidecar did not become ready after service uninstall");
|
||||
}
|
||||
self.apply_proxy_after_start().await
|
||||
@@ -423,7 +430,9 @@ impl CoreManager {
|
||||
self.current_core_readiness_generation(),
|
||||
crate::core::service::owner_monitor_generation(),
|
||||
)
|
||||
.ok_or_else(|| anyhow::anyhow!("cannot apply system proxy before core readiness"))?;
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("cannot apply system proxy before core readiness").context(SysproxyFailure::CoreNotReady)
|
||||
})?;
|
||||
proxy_control::apply().await?;
|
||||
if !expectation.is_valid(
|
||||
self.get_running_mode().as_ref(),
|
||||
@@ -433,7 +442,8 @@ impl CoreManager {
|
||||
let clear_result = proxy_control::clear().await;
|
||||
proxy_control::stop_guard().await;
|
||||
clear_result?;
|
||||
anyhow::bail!("core readiness changed while applying system proxy");
|
||||
return Err(anyhow::anyhow!("core readiness changed while applying system proxy")
|
||||
.context(SysproxyFailure::CoreNotReady));
|
||||
}
|
||||
proxy_control::refresh_guard().await?;
|
||||
if !expectation.is_valid(
|
||||
@@ -444,7 +454,10 @@ impl CoreManager {
|
||||
let clear_result = proxy_control::clear().await;
|
||||
proxy_control::stop_guard().await;
|
||||
clear_result?;
|
||||
anyhow::bail!("core readiness changed while refreshing the system proxy guard");
|
||||
return Err(
|
||||
anyhow::anyhow!("core readiness changed while refreshing the system proxy guard")
|
||||
.context(SysproxyFailure::CoreNotReady),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -553,7 +566,9 @@ impl CoreManager {
|
||||
|| self.controlled_stop_core_with_intent(proxy_intent),
|
||||
|| async {
|
||||
self.start_core_inner().await?;
|
||||
if matches!(*self.get_running_mode(), RunningMode::NotRunning) {
|
||||
if matches!(*self.get_running_mode(), RunningMode::NotRunning)
|
||||
|| self.current_core_readiness_generation().is_none()
|
||||
{
|
||||
anyhow::bail!("core did not become ready after restart");
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -38,6 +38,8 @@ pub enum SysproxyFailure {
|
||||
SidecarWhileServiceReady,
|
||||
/// The proxy guard stopped after repeated failures.
|
||||
GuardStopped { detail: String },
|
||||
/// The Core was not ready, so enabling the system proxy was refused.
|
||||
CoreNotReady,
|
||||
}
|
||||
|
||||
impl SysproxyFailure {
|
||||
@@ -48,6 +50,7 @@ impl SysproxyFailure {
|
||||
Self::DirectFallback { .. } => "SYSPROXY_DIRECT_FALLBACK",
|
||||
Self::SidecarWhileServiceReady => "SYSPROXY_SIDECAR_WHILE_SERVICE_READY",
|
||||
Self::GuardStopped { .. } => "SYSPROXY_GUARD_STOPPED",
|
||||
Self::CoreNotReady => "SYSPROXY_CORE_NOT_READY",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +73,7 @@ impl std::fmt::Display for SysproxyFailure {
|
||||
Self::GuardStopped { detail } => {
|
||||
write!(f, "system proxy guard stopped after repeated failures: {detail}")
|
||||
}
|
||||
Self::CoreNotReady => f.write_str("the core is not ready, so the system proxy was not enabled"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
config::{Config, IClashTemp, IProfiles, IVerge},
|
||||
core::{backup, proxy_control::SystemProxyStateUnknown},
|
||||
core::{CoreManager, backup, proxy_control, proxy_control::SystemProxyStateUnknown},
|
||||
process::AsyncHandler,
|
||||
utils::{
|
||||
dirs::{PathBufExec as _, app_home_dir, local_backup_dir, verge_path},
|
||||
@@ -52,10 +52,30 @@ async fn finalize_restored_verge_config(
|
||||
profiles_draft.apply();
|
||||
|
||||
let verge_draft = Config::verge().await;
|
||||
verge_draft.edit_draft(|d| {
|
||||
*d = restored.clone();
|
||||
});
|
||||
verge_draft.apply();
|
||||
{
|
||||
// Hold the write lock so a concurrent patch cannot stage a draft the proxy write reads.
|
||||
let _config_write = Config::lock_config_write().await;
|
||||
verge_draft.edit_draft(|d| {
|
||||
*d = restored.clone();
|
||||
});
|
||||
verge_draft.apply();
|
||||
|
||||
// Turn it off here; a failing core side effect below would otherwise skip this step.
|
||||
if !restored.enable_system_proxy.unwrap_or_default() {
|
||||
let result = async {
|
||||
let _lifecycle = CoreManager::global().lifecycle_lock.lock().await;
|
||||
proxy_control::apply().await?;
|
||||
proxy_control::refresh_guard().await
|
||||
}
|
||||
.await;
|
||||
if let Err(err) = result {
|
||||
logging!(error, Type::Backup, "Failed to turn the system proxy off: {err:#?}");
|
||||
if SystemProxyStateUnknown::is_in(&err) {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run configuration side effects without rewriting the already-restored file.
|
||||
if let Err(err) = super::patch_verge(&restored, true).await {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
core::{CoreManager, autostart, handle, hotkey, logger::Logger, proxy_control::SystemProxyStateUnknown, tray},
|
||||
core::{
|
||||
CoreManager, autostart, handle, hotkey, logger::Logger, proxy_control, proxy_control::SystemProxyStateUnknown,
|
||||
tray,
|
||||
},
|
||||
module::{auto_backup::AutoBackupManager, lightweight},
|
||||
};
|
||||
use anyhow::Result;
|
||||
@@ -223,7 +226,18 @@ async fn process_terminated_flags(update_flags: UpdateFlags, patch: &IVerge) ->
|
||||
if update_flags.contains(UpdateFlags::SYS_PROXY) {
|
||||
let manager = CoreManager::global();
|
||||
let _lifecycle = manager.lifecycle_lock.lock().await;
|
||||
manager.apply_proxy_after_start().await?;
|
||||
// Turning it off only writes OS state, so it must stay available while the Core is down.
|
||||
if Config::verge()
|
||||
.await
|
||||
.latest_arc()
|
||||
.enable_system_proxy
|
||||
.unwrap_or_default()
|
||||
{
|
||||
manager.apply_proxy_after_start().await?;
|
||||
} else {
|
||||
proxy_control::apply().await?;
|
||||
proxy_control::refresh_guard().await?;
|
||||
}
|
||||
}
|
||||
if update_flags.contains(UpdateFlags::HOTKEY)
|
||||
&& let Some(hotkeys) = &patch.hotkeys
|
||||
|
||||
Reference in New Issue
Block a user