fix(core): serialize runtime config updates

This commit is contained in:
Tunglies
2026-05-28 17:41:39 +08:00
parent 43843f1eca
commit 08fd2ce68b
3 changed files with 48 additions and 8 deletions
+3 -5
View File
@@ -94,12 +94,10 @@ pub async fn get_runtime_proxy_chain_config(proxy_chain_exit_node: String) -> Cm
/// 更新运行时链式代理配置
#[tauri::command]
pub async fn update_proxy_chain_config_in_runtime(proxy_chain_config: Option<serde_yaml_ng::Value>) -> CmdResult<()> {
match CoreManager::global()
.update_runtime_config(|d| d.update_proxy_chain_config(proxy_chain_config))
.await
{
let runtime = Config::runtime().await;
runtime.edit_draft(|d| d.update_proxy_chain_config(proxy_chain_config));
// 我们需要在 CoreManager 中验证并应用配置,这里不应该直接调用 runtime.apply()
}
match CoreManager::global().apply_generate_config().await {
Ok(outcome) if outcome.is_valid() => {}
Ok(outcome) => logging!(
warn,
+27 -2
View File
@@ -10,6 +10,7 @@ use crate::{
};
use anyhow::{Result, anyhow};
use clash_verge_logging::{Type, logging};
use scopeguard::defer;
use smartstring::alias::String;
use std::{collections::HashSet, path::PathBuf, time::Instant};
use tauri_plugin_mihomo::Error as MihomoError;
@@ -45,6 +46,14 @@ impl CoreManager {
});
}
if !self.try_start_config_update() {
logging!(info, Type::Core, "Configuration update is already running");
return Ok(ValidationOutcome::Busy);
}
defer! {
self.finish_config_update();
}
if !force && !self.should_update_config() {
logging!(debug, Type::Core, "Skipping config update due to debounce");
return Ok(ValidationOutcome::Skipped {
@@ -89,10 +98,26 @@ impl CoreManager {
return Ok(ValidationOutcome::invalid_from_message(message));
}
self.apply_generate_config().await
self.apply_generate_config_inner().await
}
pub async fn apply_generate_config(&self) -> Result<ValidationOutcome> {
pub(crate) async fn update_runtime_config<F>(&self, f: F) -> Result<ValidationOutcome>
where
F: FnOnce(&mut IRuntime),
{
if !self.try_start_config_update() {
logging!(info, Type::Core, "Configuration update is already running");
return Ok(ValidationOutcome::Busy);
}
defer! {
self.finish_config_update();
}
Config::runtime().await.edit_draft(f);
self.apply_generate_config_inner().await
}
async fn apply_generate_config_inner(&self) -> Result<ValidationOutcome> {
match CoreConfigValidator::global().validate_config_outcome().await {
Ok(outcome) if outcome.is_valid() => {
let run_path = Config::generate_file(ConfigType::Run).await?;
+18 -1
View File
@@ -6,7 +6,14 @@ use anyhow::Result;
use arc_swap::{ArcSwap, ArcSwapOption};
use clash_verge_logger::AsyncLogger;
use once_cell::sync::Lazy;
use std::{fmt, sync::Arc, time::Instant};
use std::{
fmt,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
time::Instant,
};
use tauri_plugin_shell::process::CommandChild;
use crate::singleton;
@@ -34,6 +41,7 @@ impl fmt::Display for RunningMode {
pub struct CoreManager {
state: ArcSwap<State>,
last_update: ArcSwapOption<Instant>,
config_update_in_progress: AtomicBool,
}
#[derive(Debug)]
@@ -56,6 +64,7 @@ impl Default for CoreManager {
Self {
state: ArcSwap::new(Arc::new(State::default())),
last_update: ArcSwapOption::new(None),
config_update_in_progress: AtomicBool::new(false),
}
}
}
@@ -95,6 +104,14 @@ impl CoreManager {
self.last_update.store(Some(Arc::new(time)));
}
fn try_start_config_update(&self) -> bool {
!self.config_update_in_progress.swap(true, Ordering::AcqRel)
}
fn finish_config_update(&self) {
self.config_update_in_progress.store(false, Ordering::Release);
}
pub async fn init(&self) -> Result<()> {
self.start_core().await?;
Ok(())