fix(sysproxy): wait for the network before the login-time proxy write

This commit is contained in:
wonfen
2026-09-03 22:42:49 +08:00
parent 7ffb0ef23b
commit c89f431cb0
2 changed files with 36 additions and 0 deletions
+19
View File
@@ -17,6 +17,9 @@ const fn should_wait_for_service(tun_enabled: bool, service_ready: bool, is_admi
tun_enabled && !service_ready && !is_admin
}
/// How long a login-time start waits for the network before writing the system proxy.
const STARTUP_NETWORK_WAIT: std::time::Duration = std::time::Duration::from_secs(30);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum StartupDecision {
Service,
@@ -465,6 +468,22 @@ impl CoreManager {
.ok_or_else(|| {
anyhow::anyhow!("cannot apply system proxy before core readiness").context(SysproxyFailure::CoreNotReady)
})?;
// Startup only; a user toggling while offline should fail fast.
if cfg!(target_os = "macos")
&& !crate::utils::resolve::is_resolve_done()
&& Config::verge()
.await
.latest_arc()
.enable_system_proxy
.unwrap_or_default()
&& !proxy_control::wait_for_network_service(STARTUP_NETWORK_WAIT).await
{
logging!(
warn,
Type::Core,
"no network service {STARTUP_NETWORK_WAIT:?} after startup; applying the system proxy anyway"
);
}
proxy_control::apply().await?;
if !expectation.is_valid(
self.get_running_mode().as_ref(),
+17
View File
@@ -384,6 +384,23 @@ async fn current_service_proxy_config(verge: &IVerge) -> Result<MacosProxyConfig
service_proxy_config(verge, mixed_port, 0)
}
/// Wait, up to `limit`, for a network service to write the proxy on. At login the app usually
/// comes up before the network does, and nothing re-applies a proxy the first write missed.
pub async fn wait_for_network_service(limit: Duration) -> bool {
let no_service = || {
tokio::task::spawn_blocking(
|| matches!(sysproxy::Sysproxy::get_system_proxy(), Err(error) if is_missing_network_service(&error)),
)
};
tokio::time::timeout(limit, async {
while no_service().await.unwrap_or(false) {
tokio::time::sleep(Duration::from_secs(1)).await;
}
})
.await
.is_ok()
}
pub fn is_reportable(error: &anyhow::Error) -> bool {
is_reportable_given(error, notification::has_pending_failure)
}