From 97769cf93a874cc2d6e55a2cc14cd1ea4251d42c Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:01:22 +0800 Subject: [PATCH] feat: add methods to retrieve current subscription details in PrfItem and refactor profile handling in IProfiles --- src-tauri/src/config/prfitem.rs | 27 ++++++++ src-tauri/src/config/profiles.rs | 105 +++++++------------------------ src-tauri/src/core/handle.rs | 1 + src-tauri/src/core/tray/mod.rs | 4 +- src-tauri/src/enhance/mod.rs | 90 +++++++++++++++++++------- src-tauri/src/feat/profile.rs | 14 ++--- 6 files changed, 127 insertions(+), 114 deletions(-) diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index d6b54b56..a649333b 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -584,6 +584,33 @@ impl PrfItem { } } +impl PrfItem { + /// 获取current指向的订阅的merge + pub fn current_merge(&self) -> Option { + self.option.as_ref().and_then(|o| o.merge.clone()) + } + + /// 获取current指向的订阅的script + pub fn current_script(&self) -> Option { + self.option.as_ref().and_then(|o| o.script.clone()) + } + + /// 获取current指向的订阅的rules + pub fn current_rules(&self) -> Option { + self.option.as_ref().and_then(|o| o.rules.clone()) + } + + /// 获取current指向的订阅的proxies + pub fn current_proxies(&self) -> Option { + self.option.as_ref().and_then(|o| o.proxies.clone()) + } + + /// 获取current指向的订阅的groups + pub fn current_groups(&self) -> Option { + self.option.as_ref().and_then(|o| o.groups.clone()) + } +} + // 向前兼容,默认为订阅启用自动更新 fn default_allow_auto_update() -> Option { Some(true) diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index f210acb9..51dd6172 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -8,7 +8,7 @@ use anyhow::{Context, Result, bail}; use serde::{Deserialize, Serialize}; use serde_yaml_ng::Mapping; use smartstring::alias::String; -use std::collections::HashSet; +use std::{collections::HashSet, sync::Arc}; use tokio::fs; /// Define the `profiles.yaml` schema @@ -104,8 +104,8 @@ impl IProfiles { Ok(()) } - pub fn get_current(&self) -> Option { - self.current.clone() + pub fn get_current(&self) -> Option<&String> { + self.current.as_ref() } /// get items ref @@ -130,6 +130,15 @@ impl IProfiles { bail!("failed to get the profile item \"uid:{}\"", uid_str); } + pub fn get_item_arc(&self, uid: &str) -> Option> { + self.items.as_ref().and_then(|items| { + items + .iter() + .find(|it| it.uid.as_deref() == Some(uid)) + .map(|it| Arc::new(it.clone())) + }) + } + /// append new item /// if the file_data is some /// then should save the data to file @@ -355,76 +364,6 @@ impl IProfiles { } } - /// 获取current指向的订阅的merge - pub fn current_merge(&self) -> Option { - match (self.current.as_ref(), self.items.as_ref()) { - (Some(current), Some(items)) => { - if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { - let merge = item.option.as_ref().and_then(|e| e.merge.clone()); - return merge; - } - None - } - _ => None, - } - } - - /// 获取current指向的订阅的script - pub fn current_script(&self) -> Option { - match (self.current.as_ref(), self.items.as_ref()) { - (Some(current), Some(items)) => { - if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { - let script = item.option.as_ref().and_then(|e| e.script.clone()); - return script; - } - None - } - _ => None, - } - } - - /// 获取current指向的订阅的rules - pub fn current_rules(&self) -> Option { - match (self.current.as_ref(), self.items.as_ref()) { - (Some(current), Some(items)) => { - if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { - let rules = item.option.as_ref().and_then(|e| e.rules.clone()); - return rules; - } - None - } - _ => None, - } - } - - /// 获取current指向的订阅的proxies - pub fn current_proxies(&self) -> Option { - match (self.current.as_ref(), self.items.as_ref()) { - (Some(current), Some(items)) => { - if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { - let proxies = item.option.as_ref().and_then(|e| e.proxies.clone()); - return proxies; - } - None - } - _ => None, - } - } - - /// 获取current指向的订阅的groups - pub fn current_groups(&self) -> Option { - match (self.current.as_ref(), self.items.as_ref()) { - (Some(current), Some(items)) => { - if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { - let groups = item.option.as_ref().and_then(|e| e.groups.clone()); - return groups; - } - None - } - _ => None, - } - } - /// 判断profile是否是current指向的 pub fn is_current_profile_index(&self, index: &String) -> bool { self.current.as_ref() == Some(index) @@ -447,11 +386,11 @@ impl IProfiles { } /// 通过 uid 获取名称 - pub fn get_name_by_uid(&self, uid: &String) -> Option { + pub fn get_name_by_uid(&self, uid: &String) -> Option<&String> { if let Some(items) = &self.items { for item in items { if item.uid.as_ref() == Some(uid) { - return item.name.clone(); + return item.name.as_ref(); } } } @@ -549,14 +488,14 @@ impl IProfiles { } /// 获取所有 active profile 关联的文件名 - fn get_all_active_files(&self) -> HashSet { - let mut active_files = HashSet::new(); + fn get_all_active_files(&self) -> HashSet<&str> { + let mut active_files: HashSet<&str> = HashSet::new(); if let Some(items) = &self.items { for item in items { // 收集所有类型 profile 的文件 if let Some(file) = &item.file { - active_files.insert(file.clone()); + active_files.insert(file); } // 对于主 profile 类型(remote/local),还需要收集其关联的扩展文件 @@ -569,35 +508,35 @@ impl IProfiles { && let Ok(merge_item) = self.get_item(merge_uid) && let Some(file) = &merge_item.file { - active_files.insert(file.clone()); + active_files.insert(file); } if let Some(script_uid) = &option.script && let Ok(script_item) = self.get_item(script_uid) && let Some(file) = &script_item.file { - active_files.insert(file.clone()); + active_files.insert(file); } if let Some(rules_uid) = &option.rules && let Ok(rules_item) = self.get_item(rules_uid) && let Some(file) = &rules_item.file { - active_files.insert(file.clone()); + active_files.insert(file); } if let Some(proxies_uid) = &option.proxies && let Ok(proxies_item) = self.get_item(proxies_uid) && let Some(file) = &proxies_item.file { - active_files.insert(file.clone()); + active_files.insert(file); } if let Some(groups_uid) = &option.groups && let Ok(groups_item) = self.get_item(groups_uid) && let Some(file) = &groups_item.file { - active_files.insert(file.clone()); + active_files.insert(file); } } } diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index ef868f59..f15cc0fb 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -102,6 +102,7 @@ impl Handle { Self::send_event(FrontendEvent::ProfileUpdateCompleted { uid }); } + // TODO 利用 &str 等缩短 Clone pub fn notice_message, M: Into>(status: S, msg: M) { let handle = Self::global(); let status_str = status.into(); diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 01818eb9..6b91f06a 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -455,7 +455,7 @@ impl Tray { let profiles = Config::profiles().await; let profiles = profiles.latest_arc(); if let Some(current_profile_uid) = profiles.get_current() - && let Ok(profile) = profiles.get_item(¤t_profile_uid) + && let Ok(profile) = profiles.get_item(current_profile_uid) { current_profile_name = match &profile.name { Some(profile_name) => profile_name.to_string(), @@ -842,7 +842,7 @@ async fn create_tray_menu( let profiles_ref = profiles_config.latest_arc(); profiles_ref .get_current() - .and_then(|uid| profiles_ref.get_item(&uid).ok()) + .and_then(|uid| profiles_ref.get_item(uid).ok()) .and_then(|profile| profile.selected.clone()) .unwrap_or_default() }; diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index ad1a52d1..f2e5a191 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -44,6 +44,43 @@ struct ProfileItems { profile_name: String, } +impl Default for ProfileItems { + fn default() -> Self { + Self { + config: Default::default(), + profile_name: Default::default(), + merge_item: ChainItem { + uid: "".into(), + data: ChainType::Merge(Mapping::new()), + }, + script_item: ChainItem { + uid: "".into(), + data: ChainType::Script(tmpl::ITEM_SCRIPT.into()), + }, + rules_item: ChainItem { + uid: "".into(), + data: ChainType::Rules(SeqMap::default()), + }, + proxies_item: ChainItem { + uid: "".into(), + data: ChainType::Proxies(SeqMap::default()), + }, + groups_item: ChainItem { + uid: "".into(), + data: ChainType::Groups(SeqMap::default()), + }, + global_merge: ChainItem { + uid: "Merge".into(), + data: ChainType::Merge(Mapping::new()), + }, + global_script: ChainItem { + uid: "Script".into(), + data: ChainType::Script(tmpl::ITEM_SCRIPT.into()), + }, + } + } +} + async fn get_config_values() -> ConfigValues { let clash_config = { Config::clash().await.latest_arc().0.clone() }; @@ -89,18 +126,10 @@ async fn get_config_values() -> ConfigValues { } } +#[allow(clippy::cognitive_complexity)] async fn collect_profile_items() -> ProfileItems { // 从profiles里拿东西 - 先收集需要的数据,然后释放锁 - let ( - current, - merge_uid, - script_uid, - rules_uid, - proxies_uid, - groups_uid, - _current_profile_uid, - name, - ) = { + let (current, merge_uid, script_uid, rules_uid, proxies_uid, groups_uid, name) = { let current = { let profiles = Config::profiles().await; let profiles_clone = profiles.latest_arc(); @@ -109,13 +138,31 @@ async fn collect_profile_items() -> ProfileItems { let profiles = Config::profiles().await; let profiles_ref = profiles.latest_arc(); + let current_profile_uid = match profiles_ref.get_current() { + Some(uid) => uid.clone(), + None => return ProfileItems::default(), + }; - 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 current_item = match profiles_ref.get_item_arc(¤t_profile_uid) { + Some(item) => item, + None => return ProfileItems::default(), + }; + + let merge_uid = current_item + .current_merge() + .unwrap_or_else(|| "Merge".into()); + let script_uid = current_item + .current_script() + .unwrap_or_else(|| "Script".into()); + let rules_uid = current_item + .current_rules() + .unwrap_or_else(|| "Rules".into()); + let proxies_uid = current_item + .current_proxies() + .unwrap_or_else(|| "Proxies".into()); + let groups_uid = current_item + .current_groups() + .unwrap_or_else(|| "Groups".into()); let name = profiles_ref .get_item(¤t_profile_uid) @@ -130,7 +177,6 @@ async fn collect_profile_items() -> ProfileItems { rules_uid, proxies_uid, groups_uid, - current_profile_uid, name, ) }; @@ -140,7 +186,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_arc(); - profiles.get_item(merge_uid).ok().cloned() + profiles.get_item(&merge_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -157,7 +203,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_arc(); - profiles.get_item(script_uid).ok().cloned() + profiles.get_item(&script_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -174,7 +220,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_arc(); - profiles.get_item(rules_uid).ok().cloned() + profiles.get_item(&rules_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -191,7 +237,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_arc(); - profiles.get_item(proxies_uid).ok().cloned() + profiles.get_item(&proxies_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await @@ -208,7 +254,7 @@ async fn collect_profile_items() -> ProfileItems { let item = { let profiles = Config::profiles().await; let profiles = profiles.latest_arc(); - profiles.get_item(groups_uid).ok().cloned() + profiles.get_item(&groups_uid).ok().cloned() }; if let Some(item) = item { >::from_async(&item).await diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index b43c8950..b8c93655 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -152,13 +152,13 @@ async fn perform_profile_update( let profiles = Config::profiles().await; profiles.latest_arc().is_current_profile_index(uid) }; - let profile_name = { - let profiles = Config::profiles().await; - profiles - .latest_arc() - .get_name_by_uid(uid) - .unwrap_or_default() - }; + let profiles = Config::profiles().await; + let profiles_arc = profiles.latest_arc(); + let profile_name = profiles_arc + .get_name_by_uid(uid) + .cloned() + .unwrap_or_else(|| String::from("UnKown Profile")); + let mut last_err; match PrfItem::from_url(url, None, None, merged_opt.as_ref()).await {