diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c1bdfecd4..4c01e0311 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -962,9 +962,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.44" +version = "1.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" dependencies = [ "find-msvc-tools", "jobserver", @@ -1161,8 +1161,8 @@ dependencies = [ [[package]] name = "clash_verge_logger" -version = "0.2.1" -source = "git+https://github.com/clash-verge-rev/clash-verge-logger#955f1b709890640ff01fd30009df0f35816bbca6" +version = "0.2.0" +source = "git+https://github.com/clash-verge-rev/clash-verge-logger#9bb189b5b5c4c2eee35168ff4997e8fb10901c81" dependencies = [ "arraydeque", "compact_str", @@ -8752,9 +8752,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version-compare" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "version_check" diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index f429e4fd2..37033f481 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -41,10 +41,7 @@ pub async fn patch_clash_mode(payload: String) -> CmdResult { pub async fn change_clash_core(clash_core: String) -> CmdResult> { logging!(info, Type::Config, "changing core to {clash_core}"); - match CoreManager::global() - .change_core(Some(clash_core.clone())) - .await - { + match CoreManager::global().change_core(&clash_core).await { Ok(_) => { // 切换内核后重启内核 match CoreManager::global().restart_core().await { diff --git a/src-tauri/src/cmd/profile.rs b/src-tauri/src/cmd/profile.rs index 5ed734d25..8080fe125 100644 --- a/src-tauri/src/cmd/profile.rs +++ b/src-tauri/src/cmd/profile.rs @@ -99,7 +99,7 @@ pub async fn import_profile(url: std::string::String, option: Option) logging!(info, Type::Cmd, "[导入订阅] 开始导入: {}", url); // 直接依赖 PrfItem::from_url 自身的超时/重试逻辑,不再使用 tokio::time::timeout 包裹 - let item = match PrfItem::from_url(&url, None, None, option).await { + let item = &mut match PrfItem::from_url(&url, None, None, option.as_ref()).await { Ok(it) => { logging!(info, Type::Cmd, "[导入订阅] 下载完成,开始保存配置"); it @@ -110,7 +110,7 @@ pub async fn import_profile(url: std::string::String, option: Option) } }; - match profiles_append_item_safe(item.clone()).await { + match profiles_append_item_safe(item).await { Ok(_) => match profiles_save_file_safe().await { Ok(_) => { logging!(info, Type::Cmd, "[导入订阅] 配置文件保存成功"); @@ -145,7 +145,7 @@ pub async fn import_profile(url: std::string::String, option: Option) /// 调整profile的顺序 #[tauri::command] pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult { - match profiles_reorder_safe(active_id, over_id).await { + match profiles_reorder_safe(&active_id, &over_id).await { Ok(_) => { log::info!(target: "app", "重新排序配置文件"); Ok(()) @@ -161,7 +161,7 @@ pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult { /// 创建一个新的配置文件 #[tauri::command] pub async fn create_profile(item: PrfItem, file_data: Option) -> CmdResult { - match profiles_append_item_with_filedata_safe(item.clone(), file_data).await { + match profiles_append_item_with_filedata_safe(&item, file_data).await { Ok(_) => { // 发送配置变更通知 if let Some(uid) = &item.uid { @@ -180,7 +180,7 @@ pub async fn create_profile(item: PrfItem, file_data: Option) -> CmdResu /// 更新配置文件 #[tauri::command] pub async fn update_profile(index: String, option: Option) -> CmdResult { - match feat::update_profile(index, option, Some(true), Some(true)).await { + match feat::update_profile(&index, option.as_ref(), true, true).await { Ok(_) => Ok(()), Err(e) => { log::error!(target: "app", "{}", e); @@ -194,9 +194,7 @@ pub async fn update_profile(index: String, option: Option) -> CmdResu pub async fn delete_profile(index: String) -> CmdResult { println!("delete_profile: {}", index); // 使用Send-safe helper函数 - let should_update = profiles_delete_item_safe(index.clone()) - .await - .stringify_err()?; + let should_update = profiles_delete_item_safe(&index).await.stringify_err()?; profiles_save_file_safe().await.stringify_err()?; if should_update { @@ -585,7 +583,7 @@ pub async fn patch_profile(index: String, profile: PrfItem) -> CmdResult { false }; - profiles_patch_item_safe(index.clone(), profile) + profiles_patch_item_safe(&index, &profile) .await .stringify_err()?; diff --git a/src-tauri/src/cmd/save_profile.rs b/src-tauri/src/cmd/save_profile.rs index cb216e8b6..1e905e638 100644 --- a/src-tauri/src/cmd/save_profile.rs +++ b/src-tauri/src/cmd/save_profile.rs @@ -141,7 +141,7 @@ async fn handle_full_validation( Type::Config, "[cmd配置save] YAML配置文件验证失败,发送通知" ); - let result = (false, error_msg.clone()); + let result = (false, error_msg.to_owned()); crate::cmd::validate::handle_yaml_validation_notice(&result, "YAML配置文件"); } else if is_script_error(&error_msg, file_path_str) { logging!( @@ -149,7 +149,7 @@ async fn handle_full_validation( Type::Config, "[cmd配置save] 脚本文件验证失败,发送通知" ); - let result = (false, error_msg.clone()); + let result = (false, error_msg.to_owned()); crate::cmd::validate::handle_script_validation_notice(&result, "脚本文件"); } else { logging!( diff --git a/src-tauri/src/cmd/verge.rs b/src-tauri/src/cmd/verge.rs index eb74339fd..cce4043de 100644 --- a/src-tauri/src/cmd/verge.rs +++ b/src-tauri/src/cmd/verge.rs @@ -9,12 +9,12 @@ pub async fn get_verge_config() -> CmdResult { let ref_data = verge.latest_ref(); ref_data.clone() }; - let verge_response = IVergeResponse::from(*verge_data); + let verge_response = IVergeResponse::from(verge_data); Ok(verge_response) } /// 修改Verge配置 #[tauri::command] pub async fn patch_verge_config(payload: IVerge) -> CmdResult { - feat::patch_verge(payload, false).await.stringify_err() + feat::patch_verge(&payload, false).await.stringify_err() } diff --git a/src-tauri/src/cmd/webdav.rs b/src-tauri/src/cmd/webdav.rs index 6c27868db..1de27b70d 100644 --- a/src-tauri/src/cmd/webdav.rs +++ b/src-tauri/src/cmd/webdav.rs @@ -12,10 +12,7 @@ pub async fn save_webdav_config(url: String, username: String, password: String) webdav_password: Some(password), ..IVerge::default() }; - Config::verge() - .await - .draft_mut() - .patch_config(patch.clone()); + Config::verge().await.draft_mut().patch_config(&patch); Config::verge().await.apply(); // 分离数据获取和异步调用 diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index 246a4c6b4..f9bbcf0a8 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -83,13 +83,13 @@ impl Config { // Ensure "Merge" and "Script" profile items exist, adding them if missing. async fn ensure_default_profile_items() -> Result<()> { let profiles = Self::profiles().await; - if profiles.latest_ref().get_item(&"Merge".into()).is_err() { - let merge_item = PrfItem::from_merge(Some("Merge".into()))?; - profiles_append_item_safe(merge_item.clone()).await?; + if profiles.latest_ref().get_item("Merge").is_err() { + let merge_item = &mut PrfItem::from_merge(Some("Merge".into()))?; + profiles_append_item_safe(merge_item).await?; } - if profiles.latest_ref().get_item(&"Script".into()).is_err() { - let script_item = PrfItem::from_script(Some("Script".into()))?; - profiles_append_item_safe(script_item.clone()).await?; + if profiles.latest_ref().get_item("Script").is_err() { + let script_item = &mut PrfItem::from_script(Some("Script".into()))?; + profiles_append_item_safe(script_item).await?; } Ok(()) } diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index d26eac70a..d6b54b56c 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -1,7 +1,10 @@ -use crate::utils::{ - dirs, help, - network::{NetworkManager, ProxyType}, - tmpl, +use crate::{ + config::profiles, + utils::{ + dirs, help, + network::{NetworkManager, ProxyType}, + tmpl, + }, }; use anyhow::{Context, Result, bail}; use serde::{Deserialize, Serialize}; @@ -119,26 +122,29 @@ pub struct PrfOption { } impl PrfOption { - pub fn merge(one: Option, other: Option) -> Option { + pub fn merge(one: Option<&Self>, other: Option<&Self>) -> Option { match (one, other) { - (Some(mut a), Some(b)) => { - a.user_agent = b.user_agent.or(a.user_agent); - a.with_proxy = b.with_proxy.or(a.with_proxy); - a.self_proxy = b.self_proxy.or(a.self_proxy); - a.danger_accept_invalid_certs = b + (Some(a_ref), Some(b_ref)) => { + let mut result = a_ref.clone(); + result.user_agent = b_ref.user_agent.clone().or(result.user_agent); + result.with_proxy = b_ref.with_proxy.or(result.with_proxy); + result.self_proxy = b_ref.self_proxy.or(result.self_proxy); + result.danger_accept_invalid_certs = b_ref .danger_accept_invalid_certs - .or(a.danger_accept_invalid_certs); - a.allow_auto_update = b.allow_auto_update.or(a.allow_auto_update); - a.update_interval = b.update_interval.or(a.update_interval); - a.merge = b.merge.or(a.merge); - a.script = b.script.or(a.script); - a.rules = b.rules.or(a.rules); - a.proxies = b.proxies.or(a.proxies); - a.groups = b.groups.or(a.groups); - a.timeout_seconds = b.timeout_seconds.or(a.timeout_seconds); - Some(a) + .or(result.danger_accept_invalid_certs); + result.allow_auto_update = b_ref.allow_auto_update.or(result.allow_auto_update); + result.update_interval = b_ref.update_interval.or(result.update_interval); + result.merge = b_ref.merge.clone().or(result.merge); + result.script = b_ref.script.clone().or(result.script); + result.rules = b_ref.rules.clone().or(result.rules); + result.proxies = b_ref.proxies.clone().or(result.proxies); + result.groups = b_ref.groups.clone().or(result.groups); + result.timeout_seconds = b_ref.timeout_seconds.or(result.timeout_seconds); + Some(result) } - t => t.0.or(t.1), + (Some(a_ref), None) => Some(a_ref.clone()), + (None, Some(b_ref)) => Some(b_ref.clone()), + (None, None) => None, } } } @@ -146,13 +152,14 @@ impl PrfOption { impl PrfItem { /// From partial item /// must contain `itype` - pub async fn from(item: PrfItem, file_data: Option) -> Result { + pub async fn from(item: &PrfItem, file_data: Option) -> Result { if item.itype.is_none() { bail!("type should not be null"); } let itype = item .itype + .as_ref() .ok_or_else(|| anyhow::anyhow!("type should not be null"))?; match itype.as_str() { "remote" => { @@ -160,14 +167,16 @@ impl PrfItem { .url .as_ref() .ok_or_else(|| anyhow::anyhow!("url should not be null"))?; - let name = item.name; - let desc = item.desc; - PrfItem::from_url(url, name, desc, item.option).await + let name = item.name.as_ref(); + let desc = item.desc.as_ref(); + let option = item.option.as_ref(); + PrfItem::from_url(url, name, desc, option).await } "local" => { - let name = item.name.unwrap_or_else(|| "Local File".into()); - let desc = item.desc.unwrap_or_else(|| "".into()); - PrfItem::from_local(name, desc, file_data, item.option).await + let name = item.name.clone().unwrap_or_else(|| "Local File".into()); + let desc = item.desc.clone().unwrap_or_else(|| "".into()); + let option = item.option.as_ref(); + PrfItem::from_local(name, desc, file_data, option).await } typ => bail!("invalid profile item type \"{typ}\""), } @@ -179,7 +188,7 @@ impl PrfItem { name: String, desc: String, file_data: Option, - option: Option, + option: Option<&PrfOption>, ) -> Result { let uid = help::get_uid("L").into(); let file = format!("{uid}.yaml").into(); @@ -192,29 +201,29 @@ impl PrfItem { let mut groups = opt_ref.and_then(|o| o.groups.clone()); if merge.is_none() { - let merge_item = PrfItem::from_merge(None)?; - crate::config::profiles::profiles_append_item_safe(merge_item.clone()).await?; - merge = merge_item.uid; + let merge_item = &mut PrfItem::from_merge(None)?; + profiles::profiles_append_item_safe(merge_item).await?; + merge = merge_item.uid.clone(); } if script.is_none() { - let script_item = PrfItem::from_script(None)?; - crate::config::profiles::profiles_append_item_safe(script_item.clone()).await?; - script = script_item.uid; + let script_item = &mut PrfItem::from_script(None)?; + profiles::profiles_append_item_safe(script_item).await?; + script = script_item.uid.clone(); } if rules.is_none() { - let rules_item = PrfItem::from_rules()?; - crate::config::profiles::profiles_append_item_safe(rules_item.clone()).await?; - rules = rules_item.uid; + let rules_item = &mut PrfItem::from_rules()?; + profiles::profiles_append_item_safe(rules_item).await?; + rules = rules_item.uid.clone(); } if proxies.is_none() { - let proxies_item = PrfItem::from_proxies()?; - crate::config::profiles::profiles_append_item_safe(proxies_item.clone()).await?; - proxies = proxies_item.uid; + let proxies_item = &mut PrfItem::from_proxies()?; + profiles::profiles_append_item_safe(proxies_item).await?; + proxies = proxies_item.uid.clone(); } if groups.is_none() { - let groups_item = PrfItem::from_groups()?; - crate::config::profiles::profiles_append_item_safe(groups_item.clone()).await?; - groups = groups_item.uid; + let groups_item = &mut PrfItem::from_groups()?; + profiles::profiles_append_item_safe(groups_item).await?; + groups = groups_item.uid.clone(); } Ok(PrfItem { uid: Some(uid), @@ -244,24 +253,23 @@ impl PrfItem { /// create a new item from url pub async fn from_url( url: &str, - name: Option, - desc: Option, - option: Option, + name: Option<&String>, + desc: Option<&String>, + option: Option<&PrfOption>, ) -> Result { - let opt_ref = option.as_ref(); - let with_proxy = opt_ref.is_some_and(|o| o.with_proxy.unwrap_or(false)); - let self_proxy = opt_ref.is_some_and(|o| o.self_proxy.unwrap_or(false)); + let with_proxy = option.is_some_and(|o| o.with_proxy.unwrap_or(false)); + let self_proxy = option.is_some_and(|o| o.self_proxy.unwrap_or(false)); let accept_invalid_certs = - opt_ref.is_some_and(|o| o.danger_accept_invalid_certs.unwrap_or(false)); - let allow_auto_update = opt_ref.map(|o| o.allow_auto_update.unwrap_or(true)); - let user_agent = opt_ref.and_then(|o| o.user_agent.clone()); - let update_interval = opt_ref.and_then(|o| o.update_interval); - let timeout = opt_ref.and_then(|o| o.timeout_seconds).unwrap_or(20); - let mut merge = opt_ref.and_then(|o| o.merge.clone()); - let mut script = opt_ref.and_then(|o| o.script.clone()); - let mut rules = opt_ref.and_then(|o| o.rules.clone()); - let mut proxies = opt_ref.and_then(|o| o.proxies.clone()); - let mut groups = opt_ref.and_then(|o| o.groups.clone()); + option.is_some_and(|o| o.danger_accept_invalid_certs.unwrap_or(false)); + let allow_auto_update = option.map(|o| o.allow_auto_update.unwrap_or(true)); + let user_agent = option.and_then(|o| o.user_agent.clone()); + let update_interval = option.and_then(|o| o.update_interval); + let timeout = option.and_then(|o| o.timeout_seconds).unwrap_or(20); + let mut merge = option.and_then(|o| o.merge.clone()); + let mut script = option.and_then(|o| o.script.clone()); + let mut rules = option.and_then(|o| o.rules.clone()); + let mut proxies = option.and_then(|o| o.proxies.clone()); + let mut groups = option.and_then(|o| o.groups.clone()); // 选择代理类型 let proxy_type = if self_proxy { @@ -366,7 +374,11 @@ impl PrfItem { let uid = help::get_uid("R").into(); let file = format!("{uid}.yaml").into(); - let name = name.unwrap_or_else(|| filename.unwrap_or_else(|| "Remote File".into()).into()); + let name = name.map(|s| s.to_owned()).unwrap_or_else(|| { + filename + .map(|s| s.into()) + .unwrap_or_else(|| "Remote File".into()) + }); let data = resp.text_with_charset()?; // process the charset "UTF-8 with BOM" @@ -381,36 +393,36 @@ impl PrfItem { } if merge.is_none() { - let merge_item = PrfItem::from_merge(None)?; - crate::config::profiles::profiles_append_item_safe(merge_item.clone()).await?; - merge = merge_item.uid; + let merge_item = &mut PrfItem::from_merge(None)?; + profiles::profiles_append_item_safe(merge_item).await?; + merge = merge_item.uid.clone(); } if script.is_none() { - let script_item = PrfItem::from_script(None)?; - crate::config::profiles::profiles_append_item_safe(script_item.clone()).await?; - script = script_item.uid; + let script_item = &mut PrfItem::from_script(None)?; + profiles::profiles_append_item_safe(script_item).await?; + script = script_item.uid.clone(); } if rules.is_none() { - let rules_item = PrfItem::from_rules()?; - crate::config::profiles::profiles_append_item_safe(rules_item.clone()).await?; - rules = rules_item.uid; + let rules_item = &mut PrfItem::from_rules()?; + profiles::profiles_append_item_safe(rules_item).await?; + rules = rules_item.uid.clone(); } if proxies.is_none() { - let proxies_item = PrfItem::from_proxies()?; - crate::config::profiles::profiles_append_item_safe(proxies_item.clone()).await?; - proxies = proxies_item.uid; + let proxies_item = &mut PrfItem::from_proxies()?; + profiles::profiles_append_item_safe(proxies_item).await?; + proxies = proxies_item.uid.clone(); } if groups.is_none() { - let groups_item = PrfItem::from_groups()?; - crate::config::profiles::profiles_append_item_safe(groups_item.clone()).await?; - groups = groups_item.uid; + let groups_item = &mut PrfItem::from_groups()?; + profiles::profiles_append_item_safe(groups_item).await?; + groups = groups_item.uid.clone(); } Ok(PrfItem { uid: Some(uid), itype: Some("remote".into()), name: Some(name), - desc, + desc: desc.cloned(), file: Some(file), url: Some(url.into()), selected: None, diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index 1601fb669..d8d9a003a 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -31,7 +31,7 @@ pub struct CleanupResult { macro_rules! patch { ($lv: expr, $rv: expr, $key: tt) => { if ($rv.$key).is_some() { - $lv.$key = $rv.$key; + $lv.$key = $rv.$key.clone(); } }; } @@ -122,28 +122,30 @@ impl IProfiles { } /// find the item by the uid - pub fn get_item(&self, uid: &String) -> Result<&PrfItem> { - if let Some(items) = self.items.as_ref() { - let some_uid = Some(uid.clone()); + pub fn get_item(&self, uid: impl AsRef) -> Result<&PrfItem> { + let uid_str = uid.as_ref(); + if let Some(items) = self.items.as_ref() { for each in items.iter() { - if each.uid == some_uid { + if let Some(uid_val) = &each.uid + && uid_val.as_str() == uid_str + { return Ok(each); } } } - bail!("failed to get the profile item \"uid:{uid}\""); + bail!("failed to get the profile item \"uid:{}\"", uid_str); } /// append new item /// if the file_data is some /// then should save the data to file - pub async fn append_item(&mut self, mut item: PrfItem) -> Result<()> { - if item.uid.is_none() { + pub async fn append_item(&mut self, item: &mut PrfItem) -> Result<()> { + let uid = &item.uid; + if uid.is_none() { bail!("the uid should not be null"); } - let uid = item.uid.clone(); // save the file data // move the field value after save @@ -165,7 +167,7 @@ impl IProfiles { if self.current.is_none() && (item.itype == Some("remote".into()) || item.itype == Some("local".into())) { - self.current = uid; + self.current = uid.to_owned(); } if self.items.is_none() { @@ -173,24 +175,23 @@ impl IProfiles { } if let Some(items) = self.items.as_mut() { - items.push(item) + items.push(item.to_owned()); } - // self.save_file().await Ok(()) } /// reorder items - pub async fn reorder(&mut self, active_id: String, over_id: String) -> Result<()> { + pub async fn reorder(&mut self, active_id: &String, over_id: &String) -> Result<()> { let mut items = self.items.take().unwrap_or_default(); let mut old_index = None; let mut new_index = None; for (i, _) in items.iter().enumerate() { - if items[i].uid == Some(active_id.clone()) { + if items[i].uid.as_ref() == Some(active_id) { old_index = Some(i); } - if items[i].uid == Some(over_id.clone()) { + if items[i].uid.as_ref() == Some(over_id) { new_index = Some(i); } } @@ -206,11 +207,11 @@ impl IProfiles { } /// update the item value - pub async fn patch_item(&mut self, uid: String, item: PrfItem) -> Result<()> { + pub async fn patch_item(&mut self, uid: &String, item: &PrfItem) -> Result<()> { let mut items = self.items.take().unwrap_or_default(); for each in items.iter_mut() { - if each.uid == Some(uid.clone()) { + if each.uid.as_ref() == Some(uid) { patch!(each, item, itype); patch!(each, item, name); patch!(each, item, desc); @@ -232,13 +233,13 @@ impl IProfiles { /// be used to update the remote item /// only patch `updated` `extra` `file_data` - pub async fn update_item(&mut self, uid: String, mut item: PrfItem) -> Result<()> { + pub async fn update_item(&mut self, uid: &String, item: &mut PrfItem) -> Result<()> { if self.items.is_none() { self.items = Some(vec![]); } // find the item - let _ = self.get_item(&uid)?; + let _ = self.get_item(uid)?; if let Some(items) = self.items.as_mut() { let some_uid = Some(uid.clone()); @@ -247,8 +248,8 @@ impl IProfiles { if each.uid == some_uid { each.extra = item.extra; each.updated = item.updated; - each.home = item.home; - each.option = PrfOption::merge(each.option.clone(), item.option); + each.home = item.home.to_owned(); + each.option = PrfOption::merge(each.option.as_ref(), item.option.as_ref()); // save the file data // move the field value after save if let Some(file_data) = item.file_data.take() { @@ -279,10 +280,10 @@ impl IProfiles { /// delete item /// if delete the current then return true - pub async fn delete_item(&mut self, uid: String) -> Result { - let current = self.current.as_ref().unwrap_or(&uid); + pub async fn delete_item(&mut self, uid: &String) -> Result { + let current = self.current.as_ref().unwrap_or(uid); let current = current.clone(); - let item = self.get_item(&uid)?; + let item = self.get_item(uid)?; let merge_uid = item.option.as_ref().and_then(|e| e.merge.clone()); let script_uid = item.option.as_ref().and_then(|e| e.script.clone()); let rules_uid = item.option.as_ref().and_then(|e| e.rules.clone()); @@ -330,7 +331,7 @@ impl IProfiles { .await; } // delete the original uid - if current == uid { + if current == *uid { self.current = None; for item in items.iter() { if item.itype == Some("remote".into()) || item.itype == Some("local".into()) { @@ -342,7 +343,7 @@ impl IProfiles { self.items = Some(items); self.save_file().await?; - Ok(current == uid) + Ok(current == *uid) } /// 获取current指向的订阅内容 @@ -626,14 +627,14 @@ impl IProfiles { use crate::config::Config; pub async fn profiles_append_item_with_filedata_safe( - item: PrfItem, + item: &PrfItem, file_data: Option, ) -> Result<()> { - let item = PrfItem::from(item, file_data).await?; + let item = &mut PrfItem::from(item, file_data).await?; profiles_append_item_safe(item).await } -pub async fn profiles_append_item_safe(item: PrfItem) -> Result<()> { +pub async fn profiles_append_item_safe(item: &mut PrfItem) -> Result<()> { Config::profiles() .await .with_data_modify(|mut profiles| async move { @@ -643,7 +644,7 @@ pub async fn profiles_append_item_safe(item: PrfItem) -> Result<()> { .await } -pub async fn profiles_patch_item_safe(index: String, item: PrfItem) -> Result<()> { +pub async fn profiles_patch_item_safe(index: &String, item: &PrfItem) -> Result<()> { Config::profiles() .await .with_data_modify(|mut profiles| async move { @@ -653,7 +654,7 @@ pub async fn profiles_patch_item_safe(index: String, item: PrfItem) -> Result<() .await } -pub async fn profiles_delete_item_safe(index: String) -> Result { +pub async fn profiles_delete_item_safe(index: &String) -> Result { Config::profiles() .await .with_data_modify(|mut profiles| async move { @@ -663,7 +664,7 @@ pub async fn profiles_delete_item_safe(index: String) -> Result { .await } -pub async fn profiles_reorder_safe(active_id: String, over_id: String) -> Result<()> { +pub async fn profiles_reorder_safe(active_id: &String, over_id: &String) -> Result<()> { Config::profiles() .await .with_data_modify(|mut profiles| async move { @@ -683,7 +684,7 @@ pub async fn profiles_save_file_safe() -> Result<()> { .await } -pub async fn profiles_draft_update_item_safe(index: String, item: PrfItem) -> Result<()> { +pub async fn profiles_draft_update_item_safe(index: &String, item: &mut PrfItem) -> Result<()> { Config::profiles() .await .with_data_modify(|mut profiles| async move { diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 25edd04b1..61f69ea97 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -437,11 +437,11 @@ impl IVerge { /// patch verge config /// only save to file #[allow(clippy::cognitive_complexity)] - pub fn patch_config(&mut self, patch: IVerge) { + pub fn patch_config(&mut self, patch: &IVerge) { macro_rules! patch { ($key: tt) => { if patch.$key.is_some() { - self.$key = patch.$key; + self.$key = patch.$key.clone(); } }; } @@ -696,3 +696,9 @@ impl From for IVergeResponse { } } } + +impl From> for IVergeResponse { + fn from(verge: Box) -> Self { + IVergeResponse::from(*verge) + } +} diff --git a/src-tauri/src/core/manager/lifecycle.rs b/src-tauri/src/core/manager/lifecycle.rs index a766aeef2..8f0c6a882 100644 --- a/src-tauri/src/core/manager/lifecycle.rs +++ b/src-tauri/src/core/manager/lifecycle.rs @@ -1,4 +1,5 @@ use super::{CoreManager, RunningMode}; +use crate::config::{Config, ConfigType, IVerge}; use crate::{ core::{ logger::CLASH_LOGGER, @@ -41,18 +42,12 @@ impl CoreManager { self.start_core().await } - pub async fn change_core(&self, clash_core: Option) -> Result<(), String> { - use crate::config::{Config, ConfigType, IVerge}; - - let core = clash_core - .as_ref() - .ok_or_else(|| "Clash core cannot be None".to_string())?; - - if !IVerge::VALID_CLASH_CORES.contains(&core.as_str()) { - return Err(format!("Invalid clash core: {}", core).into()); + pub async fn change_core(&self, clash_core: &String) -> Result<(), String> { + if !IVerge::VALID_CLASH_CORES.contains(&clash_core.as_str()) { + return Err(format!("Invalid clash core: {}", clash_core).into()); } - Config::verge().await.draft_mut().clash_core = clash_core; + Config::verge().await.draft_mut().clash_core = clash_core.to_owned().into(); Config::verge().await.apply(); let verge_data = Config::verge().await.latest_ref().clone(); diff --git a/src-tauri/src/core/timer.rs b/src-tauri/src/core/timer.rs index 47fc7f2ff..31ad95cb8 100644 --- a/src-tauri/src/core/timer.rs +++ b/src-tauri/src/core/timer.rs @@ -390,7 +390,7 @@ impl Timer { .spawn_async_routine(move || { let uid = uid.clone(); Box::pin(async move { - Self::async_task(uid).await; + Self::async_task(&uid).await; }) as Pin + Send>> }) .context("failed to create timer task")?; @@ -476,14 +476,14 @@ impl Timer { } /// Async task with better error handling and logging - async fn async_task(uid: String) { + async fn async_task(uid: &String) { let task_start = std::time::Instant::now(); logging!(info, Type::Timer, "Running timer task for profile: {}", uid); match tokio::time::timeout(std::time::Duration::from_secs(40), async { - Self::emit_update_event(&uid, true); + Self::emit_update_event(uid, true); - let is_current = Config::profiles().await.latest_ref().current.as_ref() == Some(&uid); + let is_current = Config::profiles().await.latest_ref().current.as_ref() == Some(uid); logging!( info, Type::Timer, @@ -492,7 +492,7 @@ impl Timer { is_current ); - feat::update_profile(uid.clone(), None, Some(is_current), None).await + feat::update_profile(uid, None, is_current, false).await }) .await { @@ -517,7 +517,7 @@ impl Timer { } // Emit completed event - Self::emit_update_event(&uid, false); + Self::emit_update_event(uid, false); } } diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index 7f7d71c81..05f2191bd 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -138,7 +138,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&merge_uid).ok().cloned() + profiles.get_item(merge_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -155,7 +155,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&script_uid).ok().cloned() + profiles.get_item(script_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -172,7 +172,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&rules_uid).ok().cloned() + profiles.get_item(rules_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -189,7 +189,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&proxies_uid).ok().cloned() + profiles.get_item(proxies_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -206,7 +206,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&groups_uid).ok().cloned() + profiles.get_item(groups_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -223,7 +223,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&"Merge".into()).ok().cloned() + profiles.get_item("Merge").ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -240,7 +240,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - profiles.get_item(&"Script".into()).ok().cloned() + profiles.get_item("Script").ok().cloned() }; if let Some(item) = item { >::from_async(&item).await diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs index 7d0bf9a8e..fcc8d0480 100644 --- a/src-tauri/src/feat/backup.rs +++ b/src-tauri/src/feat/backup.rs @@ -106,7 +106,7 @@ pub async fn restore_webdav_backup(filename: String) -> Result<()> { logging_error!( Type::Backup, super::patch_verge( - IVerge { + &IVerge { webdav_url, webdav_username, webdav_password, @@ -253,7 +253,7 @@ pub async fn restore_local_backup(filename: String) -> Result<()> { logging_error!( Type::Backup, super::patch_verge( - IVerge { + &IVerge { webdav_url, webdav_username, webdav_password, diff --git a/src-tauri/src/feat/config.rs b/src-tauri/src/feat/config.rs index 4f1d190af..1ca9669c9 100644 --- a/src-tauri/src/feat/config.rs +++ b/src-tauri/src/feat/config.rs @@ -226,15 +226,12 @@ async fn process_terminated_flags(update_flags: i32, patch: &IVerge) -> Result<( Ok(()) } -pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> { - Config::verge() - .await - .draft_mut() - .patch_config(patch.clone()); +pub async fn patch_verge(patch: &IVerge, not_save_file: bool) -> Result<()> { + Config::verge().await.draft_mut().patch_config(patch); - let update_flags = determine_update_flags(&patch); + let update_flags = determine_update_flags(patch); let process_flag_result: std::result::Result<(), anyhow::Error> = { - process_terminated_flags(update_flags, &patch).await?; + process_terminated_flags(update_flags, patch).await?; Ok(()) }; @@ -245,7 +242,7 @@ pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> { Config::verge().await.apply(); if !not_save_file { // 分离数据获取和异步调用 - let verge_data = Config::verge().await.data_mut().clone(); + let verge_data = Config::verge().await.data_ref().clone(); verge_data.save_file().await?; } Ok(()) diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index 7f2ce798f..4ebd4d068 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -24,12 +24,12 @@ pub async fn toggle_proxy_profile(profile_index: String) { } async fn should_update_profile( - uid: String, + uid: &String, ignore_auto_update: bool, ) -> Result)>> { let profiles = Config::profiles().await; let profiles = profiles.latest_ref(); - let item = profiles.get_item(&uid)?; + let item = profiles.get_item(uid)?; let is_remote = item.itype.as_ref().is_some_and(|s| s == "remote"); if !is_remote { @@ -63,19 +63,19 @@ async fn should_update_profile( } async fn perform_profile_update( - uid: String, - url: String, - opt: Option, - option: Option, + uid: &String, + url: &String, + opt: Option<&PrfOption>, + option: Option<&PrfOption>, ) -> Result { log::info!(target: "app", "[订阅更新] 开始下载新的订阅内容"); - let merged_opt = PrfOption::merge(opt.clone(), option.clone()); + let merged_opt = PrfOption::merge(opt, option); - match PrfItem::from_url(&url, None, None, merged_opt.clone()).await { - Ok(item) => { + match PrfItem::from_url(url, None, None, merged_opt.as_ref()).await { + Ok(mut item) => { log::info!(target: "app", "[订阅更新] 更新订阅配置成功"); let profiles = Config::profiles().await; - profiles_draft_update_item_safe(uid.clone(), item).await?; + profiles_draft_update_item_safe(uid, &mut item).await?; let is_current = Some(uid.clone()) == profiles.latest_ref().get_current(); log::info!(target: "app", "[订阅更新] 是否为当前使用的订阅: {is_current}"); Ok(is_current) @@ -91,7 +91,7 @@ async fn perform_profile_update( fallback_opt.with_proxy = Some(false); fallback_opt.self_proxy = Some(true); - match PrfItem::from_url(&url, None, None, Some(fallback_opt)).await { + match PrfItem::from_url(url, None, None, Some(&fallback_opt)).await { Ok(mut item) => { log::info!(target: "app", "[订阅更新] 使用Clash代理更新成功"); @@ -101,7 +101,7 @@ async fn perform_profile_update( } let profiles = Config::profiles().await; - profiles_draft_update_item_safe(uid.clone(), item.clone()).await?; + profiles_draft_update_item_safe(uid, &mut item).await?; let profile_name = item.name.clone().unwrap_or_else(|| uid.clone()); handle::Handle::notice_message("update_with_clash_proxy", profile_name); @@ -124,20 +124,17 @@ async fn perform_profile_update( } pub async fn update_profile( - uid: String, - option: Option, - auto_refresh: Option, - ignore_auto_update: Option, + uid: &String, + option: Option<&PrfOption>, + auto_refresh: bool, + ignore_auto_update: bool, ) -> Result<()> { logging!(info, Type::Config, "[订阅更新] 开始更新订阅 {}", uid); - let auto_refresh = auto_refresh.unwrap_or(true); - let ignore_auto_update = ignore_auto_update.unwrap_or(false); - - let url_opt = should_update_profile(uid.clone(), ignore_auto_update).await?; + let url_opt = should_update_profile(uid, ignore_auto_update).await?; let should_refresh = match url_opt { Some((url, opt)) => { - perform_profile_update(uid.clone(), url, opt, option).await? && auto_refresh + perform_profile_update(uid, &url, opt.as_ref(), option).await? && auto_refresh } None => auto_refresh, }; diff --git a/src-tauri/src/feat/proxy.rs b/src-tauri/src/feat/proxy.rs index 9178bd2d6..67d94efb3 100644 --- a/src-tauri/src/feat/proxy.rs +++ b/src-tauri/src/feat/proxy.rs @@ -20,7 +20,7 @@ pub async fn toggle_system_proxy() { } let patch_result = super::patch_verge( - IVerge { + &IVerge { enable_system_proxy: Some(!enable), ..IVerge::default() }, @@ -40,7 +40,7 @@ pub async fn toggle_tun_mode(not_save_file: Option) { let enable = enable.unwrap_or(false); match super::patch_verge( - IVerge { + &IVerge { enable_tun_mode: Some(!enable), ..IVerge::default() }, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index d7446d9fe..caa7261d7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -93,14 +93,14 @@ mod app_init { } app.deep_link().on_open_url(|event| { - let url = event.urls().first().map(|u| u.to_string()); - if let Some(url) = url { - AsyncHandler::spawn(|| async { - if let Err(e) = resolve::resolve_scheme(url.into()).await { - logging!(error, Type::Setup, "Failed to resolve scheme: {}", e); - } - }); - } + let urls = event.urls(); + AsyncHandler::spawn(move || async move { + if let Some(url) = urls.first() + && let Err(e) = resolve::resolve_scheme(url.as_ref()).await + { + logging!(error, Type::Setup, "Failed to resolve scheme: {}", e); + } + }); }); Ok(()) @@ -117,7 +117,7 @@ mod app_init { { auto_start_plugin_builder = auto_start_plugin_builder .macos_launcher(MacosLauncher::LaunchAgent) - .app_name(app.config().identifier.clone()); + .app_name(&app.config().identifier); } app.handle().plugin(auto_start_plugin_builder.build())?; Ok(()) diff --git a/src-tauri/src/utils/draft.rs b/src-tauri/src/utils/draft.rs index 76465db97..c34bbfb65 100644 --- a/src-tauri/src/utils/draft.rs +++ b/src-tauri/src/utils/draft.rs @@ -29,6 +29,11 @@ impl From for Draft { /// - `apply`: Commits the draft data, replacing the committed data and returning the old committed value if a draft existed. /// - `discard`: Discards the draft data and returns it if it existed. impl Draft> { + /// 正式数据视图 + pub fn data_ref(&self) -> MappedRwLockReadGuard<'_, Box> { + RwLockReadGuard::map(self.inner.read(), |inner| &inner.0) + } + /// 可写正式数据 pub fn data_mut(&self) -> MappedRwLockWriteGuard<'_, Box> { RwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.0) diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index 63b481d9c..72f19b082 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -429,26 +429,8 @@ pub async fn init_resources() -> Result<()> { let src_path = res_dir.join(file); let dest_path = app_dir.join(file); - let handle_copy = |src: PathBuf, dest: PathBuf, file: String| async move { - match fs::copy(&src, &dest).await { - Ok(_) => { - logging!(debug, Type::Setup, "resources copied '{}'", file); - } - Err(err) => { - logging!( - error, - Type::Setup, - "failed to copy resources '{}' to '{:?}', {}", - file, - dest, - err - ); - } - }; - }; - if src_path.exists() && !dest_path.exists() { - handle_copy(src_path.clone(), dest_path.clone(), (*file).into()).await; + handle_copy(&src_path, &dest_path, file).await; continue; } @@ -458,12 +440,12 @@ pub async fn init_resources() -> Result<()> { match (src_modified, dest_modified) { (Ok(src_modified), Ok(dest_modified)) => { if src_modified > dest_modified { - handle_copy(src_path.clone(), dest_path.clone(), (*file).into()).await; + handle_copy(&src_path, &dest_path, file).await; } } _ => { logging!(debug, Type::Setup, "failed to get modified '{}'", file); - handle_copy(src_path.clone(), dest_path.clone(), (*file).into()).await; + handle_copy(&src_path, &dest_path, file).await; } }; } @@ -563,3 +545,21 @@ pub async fn startup_script() -> Result<()> { Ok(()) } + +async fn handle_copy(src: &PathBuf, dest: &PathBuf, file: &str) { + match fs::copy(src, dest).await { + Ok(_) => { + logging!(debug, Type::Setup, "resources copied '{}'", file); + } + Err(err) => { + logging!( + error, + Type::Setup, + "failed to copy resources '{}' to '{:?}', {}", + file, + dest, + err + ); + } + }; +} diff --git a/src-tauri/src/utils/resolve/mod.rs b/src-tauri/src/utils/resolve/mod.rs index ac7255343..cb0989b16 100644 --- a/src-tauri/src/utils/resolve/mod.rs +++ b/src-tauri/src/utils/resolve/mod.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use smartstring::alias::String; use crate::{ config::Config, @@ -99,7 +98,7 @@ pub(super) async fn resolve_setup_logger() { logging_error!(Type::Setup, init::init_logger().await); } -pub async fn resolve_scheme(param: String) -> Result<()> { +pub async fn resolve_scheme(param: &str) -> Result<()> { logging_error!(Type::Setup, scheme::resolve_scheme(param).await); Ok(()) } diff --git a/src-tauri/src/utils/resolve/scheme.rs b/src-tauri/src/utils/resolve/scheme.rs index 4c7ace907..487969a39 100644 --- a/src-tauri/src/utils/resolve/scheme.rs +++ b/src-tauri/src/utils/resolve/scheme.rs @@ -3,9 +3,14 @@ use percent_encoding::percent_decode_str; use smartstring::alias::String; use tauri::Url; -use crate::{config::PrfItem, core::handle, logging, logging_error, utils::logging::Type}; +use crate::{ + config::{PrfItem, profiles}, + core::handle, + logging, logging_error, + utils::logging::Type, +}; -pub(super) async fn resolve_scheme(param: String) -> Result<()> { +pub(super) async fn resolve_scheme(param: &str) -> Result<()> { log::info!(target:"app", "received deep link: {param}"); let param_str = if param.starts_with("[") && param.len() > 4 { @@ -13,7 +18,7 @@ pub(super) async fn resolve_scheme(param: String) -> Result<()> { .get(2..param.len() - 2) .ok_or_else(|| anyhow::anyhow!("Invalid string slice boundaries"))? } else { - param.as_str() + param }; // 解析 URL @@ -25,10 +30,11 @@ pub(super) async fn resolve_scheme(param: String) -> Result<()> { }; if link_parsed.scheme() == "clash" || link_parsed.scheme() == "clash-verge" { - let name = link_parsed + let name_owned: Option = link_parsed .query_pairs() .find(|(key, _)| key == "name") - .map(|(_, value)| value.into()); + .map(|(_, value)| value.into_owned().into()); + let name = name_owned.as_ref(); let url_param = if let Some(query) = link_parsed.query() { let prefix = "url="; @@ -43,10 +49,10 @@ pub(super) async fn resolve_scheme(param: String) -> Result<()> { }; match url_param { - Some(url) => { + Some(ref url) => { log::info!(target:"app", "decoded subscription url: {url}"); - match PrfItem::from_url(url.as_ref(), name, None, None).await { - Ok(item) => { + match PrfItem::from_url(url, name, None, None).await { + Ok(mut item) => { let uid = match item.uid.clone() { Some(uid) => uid, None => { @@ -58,7 +64,7 @@ pub(super) async fn resolve_scheme(param: String) -> Result<()> { return Ok(()); } }; - let result = crate::config::profiles::profiles_append_item_safe(item).await; + let result = profiles::profiles_append_item_safe(&mut item).await; logging_error!( Type::Config, "failed to import subscription url: {:?}", diff --git a/src-tauri/src/utils/resolve/window.rs b/src-tauri/src/utils/resolve/window.rs index f415f5069..387145ec0 100644 --- a/src-tauri/src/utils/resolve/window.rs +++ b/src-tauri/src/utils/resolve/window.rs @@ -21,16 +21,14 @@ const MINIMAL_HEIGHT: f64 = 520.0; pub async fn build_new_window() -> Result { let app_handle = handle::Handle::app_handle(); - let start_page = Config::verge() - .await - .latest_ref() - .start_page - .clone() - .unwrap_or_else(|| "/".into()); + let config = Config::verge().await; + let latest = config.latest_ref(); + let start_page = latest.start_page.as_deref().unwrap_or("/"); + match tauri::WebviewWindowBuilder::new( app_handle, "main", /* the unique window label */ - tauri::WebviewUrl::App(start_page.as_str().into()), + tauri::WebviewUrl::App(start_page.into()), ) .title("Clash Verge") .center() diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs index 991e29de7..12985c2ac 100644 --- a/src-tauri/src/utils/server.rs +++ b/src-tauri/src/utils/server.rs @@ -107,9 +107,8 @@ pub fn embed_server() { let scheme = warp::path!("commands" / "scheme") .and(warp::query::()) .map(|query: QueryParam| { - let param = query.param.clone(); tokio::task::spawn_local(async move { - logging_error!(Type::Setup, resolve::resolve_scheme(param).await); + logging_error!(Type::Setup, resolve::resolve_scheme(&query.param).await); }); warp::reply::with_status::( "ok".to_string(),