>,
+ is_processing: AtomicBool,
}
impl CoreConfigValidator {
pub fn new() -> Self {
- CoreConfigValidator {
- process_status: Arc::new(Mutex::new(ValidationProcessStatus::Completed)),
+ Self {
+ is_processing: AtomicBool::new(false),
}
}
+ pub fn try_start(&self) -> bool {
+ !self.is_processing.swap(true, Ordering::AcqRel)
+ }
+
+ pub fn finish(&self) {
+ self.is_processing.store(false, Ordering::Release)
+ }
+}
+
+impl CoreConfigValidator {
/// 检查文件是否为脚本文件
- fn is_script_file(path: P) -> Result
- where
- P: AsRef + std::fmt::Display,
- {
+ async fn is_script_file(path: &str) -> Result {
// 1. 先通过扩展名快速判断
- if has_ext(&path, "yaml") || has_ext(&path, "yml") {
+ if has_ext(path, "yaml") || has_ext(path, "yml") {
return Ok(false); // YAML文件不是脚本文件
- } else if has_ext(&path, "js") {
+ } else if has_ext(path, "js") {
return Ok(true); // JS文件是脚本文件
}
// 2. 读取文件内容
- let content = match std::fs::read_to_string(&path) {
+ let content = match fs::read_to_string(path).await {
Ok(content) => content,
Err(err) => {
logging!(
@@ -118,11 +112,11 @@ impl CoreConfigValidator {
}
/// 只进行文件语法检查,不进行完整验证
- fn validate_file_syntax(config_path: &str) -> Result<(bool, String)> {
+ async fn validate_file_syntax(config_path: &str) -> Result<(bool, String)> {
logging!(info, Type::Validate, "开始检查文件: {}", config_path);
// 读取文件内容
- let content = match std::fs::read_to_string(config_path) {
+ let content = match fs::read_to_string(config_path).await {
Ok(content) => content,
Err(err) => {
let error_msg = format!("Failed to read file: {err}").into();
@@ -147,9 +141,9 @@ impl CoreConfigValidator {
}
/// 验证脚本文件语法
- fn validate_script_file(path: &str) -> Result<(bool, String)> {
+ async fn validate_script_file(path: &str) -> Result<(bool, String)> {
// 读取脚本内容
- let content = match std::fs::read_to_string(path) {
+ let content = match fs::read_to_string(path).await {
Ok(content) => content,
Err(err) => {
let error_msg = format!("Failed to read script file: {err}").into();
@@ -219,14 +213,14 @@ impl CoreConfigValidator {
"检测到Merge文件,仅进行语法检查: {}",
config_path
);
- return Self::validate_file_syntax(config_path);
+ return Self::validate_file_syntax(config_path).await;
}
// 检查是否为脚本文件
let is_script = if config_path.ends_with(".js") {
true
} else {
- match Self::is_script_file(config_path) {
+ match Self::is_script_file(config_path).await {
Ok(result) => result,
Err(err) => {
// 如果无法确定文件类型,尝试使用Clash内核验证
@@ -249,7 +243,7 @@ impl CoreConfigValidator {
"检测到脚本文件,使用JavaScript验证: {}",
config_path
);
- return Self::validate_script_file(config_path);
+ return Self::validate_script_file(config_path).await;
}
// 对YAML配置文件使用Clash内核验证
@@ -325,22 +319,18 @@ impl CoreConfigValidator {
/// 验证运行时配置
pub async fn validate_config(&self) -> Result<(bool, String)> {
- if *self.process_status.lock().await == ValidationProcessStatus::Ongoing {
+ if !self.try_start() {
logging!(info, Type::Validate, "验证已在进行中,跳过新的验证请求");
return Ok((true, String::new()));
}
- *self.process_status.lock().await = ValidationProcessStatus::Ongoing;
+ defer! {
+ self.finish();
+ }
logging!(info, Type::Validate, "生成临时配置文件用于验证");
- let result = async {
- let config_path = Config::generate_file(ConfigType::Check).await?;
- let config_path = dirs::path_to_str(&config_path)?;
- Self::validate_config_internal(config_path).await
- }
- .await;
-
- *self.process_status.lock().await = ValidationProcessStatus::Completed;
- result
+ let config_path = Config::generate_file(ConfigType::Check).await?;
+ let config_path = dirs::path_to_str(&config_path)?;
+ Self::validate_config_internal(config_path).await
}
}
diff --git a/src-tauri/src/enhance/chain.rs b/src-tauri/src/enhance/chain.rs
index 8238061c..a9a81ac8 100644
--- a/src-tauri/src/enhance/chain.rs
+++ b/src-tauri/src/enhance/chain.rs
@@ -5,7 +5,7 @@ use crate::{
};
use serde_yaml_ng::Mapping;
use smartstring::alias::String;
-use std::fs;
+use tokio::fs;
#[derive(Debug, Clone)]
pub struct ChainItem {
@@ -83,7 +83,7 @@ impl AsyncChainItemFrom for Option {
match itype {
"script" => Some(ChainItem {
uid,
- data: ChainType::Script(fs::read_to_string(path).ok()?.into()),
+ data: ChainType::Script(fs::read_to_string(path).await.ok()?.into()),
}),
"merge" => Some(ChainItem {
uid,
diff --git a/src-tauri/src/enhance/merge.rs b/src-tauri/src/enhance/merge.rs
index 0210851d..3d0e4bf9 100644
--- a/src-tauri/src/enhance/merge.rs
+++ b/src-tauri/src/enhance/merge.rs
@@ -1,3 +1,5 @@
+use crate::{logging, utils::logging::Type};
+
use super::use_lowercase;
use serde_yaml_ng::{self, Mapping, Value};
@@ -19,7 +21,11 @@ pub fn use_merge(merge: Mapping, config: Mapping) -> Mapping {
deep_merge(&mut config, &Value::from(merge));
config.as_mapping().cloned().unwrap_or_else(|| {
- log::error!("Failed to convert merged config to mapping, using empty mapping");
+ logging!(
+ error,
+ Type::Core,
+ "Failed to convert merged config to mapping, using empty mapping"
+ );
Mapping::new()
})
}
diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs
index 704f199f..e9183170 100644
--- a/src-tauri/src/enhance/mod.rs
+++ b/src-tauri/src/enhance/mod.rs
@@ -6,17 +6,45 @@ pub mod seq;
mod tun;
use self::{chain::*, field::*, merge::*, script::*, seq::*, tun::*};
+use crate::constants;
+use crate::utils::dirs;
use crate::{config::Config, utils::tmpl};
+use crate::{logging, utils::logging::Type};
use serde_yaml_ng::Mapping;
use smartstring::alias::String;
use std::collections::{HashMap, HashSet};
+use tokio::fs;
type ResultLog = Vec<(String, String)>;
+#[derive(Debug)]
+struct ConfigValues {
+ clash_config: Mapping,
+ clash_core: Option,
+ enable_tun: bool,
+ enable_builtin: bool,
+ socks_enabled: bool,
+ http_enabled: bool,
+ enable_dns_settings: bool,
+ #[cfg(not(target_os = "windows"))]
+ redir_enabled: bool,
+ #[cfg(target_os = "linux")]
+ tproxy_enabled: bool,
+}
-/// Enhance mode
-/// 返回最终订阅、该订阅包含的键、和script执行的结果
-pub async fn enhance() -> (Mapping, Vec, HashMap) {
- // config.yaml 的订阅
+#[derive(Debug)]
+struct ProfileItems {
+ config: Mapping,
+ merge_item: ChainItem,
+ script_item: ChainItem,
+ rules_item: ChainItem,
+ proxies_item: ChainItem,
+ groups_item: ChainItem,
+ global_merge: ChainItem,
+ global_script: ChainItem,
+ profile_name: String,
+}
+
+async fn get_config_values() -> ConfigValues {
let clash_config = { Config::clash().await.latest_ref().0.clone() };
let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled, enable_dns_settings) = {
@@ -31,12 +59,14 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) {
verge.enable_dns_settings.unwrap_or(false),
)
};
+
#[cfg(not(target_os = "windows"))]
let redir_enabled = {
let verge = Config::verge().await;
let verge = verge.latest_ref();
verge.verge_redir_enabled.unwrap_or(false)
};
+
#[cfg(target_os = "linux")]
let tproxy_enabled = {
let verge = Config::verge().await;
@@ -44,9 +74,189 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) {
verge.verge_tproxy_enabled.unwrap_or(false)
};
+ ConfigValues {
+ clash_config,
+ clash_core,
+ enable_tun,
+ enable_builtin,
+ socks_enabled,
+ http_enabled,
+ enable_dns_settings,
+ #[cfg(not(target_os = "windows"))]
+ redir_enabled,
+ #[cfg(target_os = "linux")]
+ tproxy_enabled,
+ }
+}
+
+async fn collect_profile_items() -> ProfileItems {
// 从profiles里拿东西 - 先收集需要的数据,然后释放锁
let (
- mut config,
+ current,
+ merge_uid,
+ script_uid,
+ rules_uid,
+ proxies_uid,
+ groups_uid,
+ _current_profile_uid,
+ name,
+ ) = {
+ let current = {
+ let profiles = Config::profiles().await;
+ let profiles_clone = profiles.latest_ref().clone();
+ profiles_clone.current_mapping().await.unwrap_or_default()
+ };
+
+ let profiles = Config::profiles().await;
+ let profiles_ref = profiles.latest_ref();
+
+ let merge_uid = profiles_ref.current_merge().unwrap_or_default();
+ let script_uid = profiles_ref.current_script().unwrap_or_default();
+ let rules_uid = profiles_ref.current_rules().unwrap_or_default();
+ let proxies_uid = profiles_ref.current_proxies().unwrap_or_default();
+ let groups_uid = profiles_ref.current_groups().unwrap_or_default();
+ let current_profile_uid = profiles_ref.get_current().unwrap_or_default();
+
+ let name = profiles_ref
+ .get_item(¤t_profile_uid)
+ .ok()
+ .and_then(|item| item.name.clone())
+ .unwrap_or_default();
+
+ (
+ current,
+ merge_uid,
+ script_uid,
+ rules_uid,
+ proxies_uid,
+ groups_uid,
+ current_profile_uid,
+ name,
+ )
+ };
+
+ // 现在获取具体的items,此时profiles锁已经释放
+ let merge_item = {
+ let item = {
+ let profiles = Config::profiles().await;
+ let profiles = profiles.latest_ref();
+ profiles.get_item(merge_uid).ok().cloned()
+ };
+ if let Some(item) = item {
+