From c51199719d9d899cf87b09cd7db26bb9319b8ba6 Mon Sep 17 00:00:00 2001 From: wonfen Date: Mon, 24 Feb 2025 11:40:28 +0800 Subject: [PATCH] fix: remove node related group info when deleting a node --- src-tauri/src/enhance/seq.rs | 167 ++++++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 42 deletions(-) diff --git a/src-tauri/src/enhance/seq.rs b/src-tauri/src/enhance/seq.rs index 81e722b5..396b1969 100644 --- a/src-tauri/src/enhance/seq.rs +++ b/src-tauri/src/enhance/seq.rs @@ -1,55 +1,138 @@ use serde::{Deserialize, Serialize}; use serde_yaml::{Mapping, Sequence, Value}; + #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct SeqMap { - prepend: Sequence, - append: Sequence, - delete: Sequence, + pub prepend: Sequence, + pub append: Sequence, + pub delete: Vec, } -pub fn use_seq(seq_map: SeqMap, config: Mapping, name: &str) -> Mapping { - let mut prepend = seq_map.prepend; - let append = seq_map.append; - let delete = seq_map.delete; +pub fn use_seq(seq: SeqMap, mut config: Mapping, field: &str) -> Mapping { + let SeqMap { + prepend, + append, + delete, + } = seq; - let origin_seq = config.get(name).map_or(Sequence::default(), |val| { - val.as_sequence().unwrap_or(&Sequence::default()).clone() - }); - let mut seq = origin_seq.clone(); + let mut new_seq = Sequence::new(); + new_seq.extend(prepend); - let mut delete_names = Vec::new(); - for item in delete { - let item = item.clone(); - if let Some(name) = if item.is_string() { - Some(item) - } else { - item.get("name").cloned() - } { - delete_names.push(name.clone()); + if let Some(Value::Sequence(origin)) = config.get(field) { + // Filter out deleted items + let filtered: Sequence = origin + .iter() + .filter(|item| { + if let Value::String(s) = item { + !delete.contains(s) + } else if let Value::Mapping(m) = item { + if let Some(Value::String(name)) = m.get("name") { + !delete.contains(name) + } else { + true + } + } else { + true + } + }) + .cloned() + .collect(); + new_seq.extend(filtered); + } + + new_seq.extend(append); + config.insert(Value::String(field.into()), Value::Sequence(new_seq)); + + // If this is proxies field, we also need to filter proxy-groups + if field == "proxies" { + if let Some(Value::Sequence(groups)) = config.get_mut("proxy-groups") { + let mut new_groups = Sequence::new(); + for group in groups { + if let Value::Mapping(group_map) = group { + let mut new_group = group_map.clone(); + if let Some(Value::Sequence(proxies)) = group_map.get("proxies") { + let filtered_proxies: Sequence = proxies + .iter() + .filter(|p| { + if let Value::String(name) = p { + !delete.contains(name) + } else { + true + } + }) + .cloned() + .collect(); + new_group.insert( + Value::String("proxies".into()), + Value::Sequence(filtered_proxies), + ); + } + new_groups.push(Value::Mapping(new_group)); + } else { + new_groups.push(group.clone()); + } + } + config.insert( + Value::String("proxy-groups".into()), + Value::Sequence(new_groups), + ); } } - seq.retain(|x| { - if let Some(x_name) = if x.is_string() { - Some(x) - } else { - x.get("name") - } { - !delete_names.contains(x_name) - } else { - true - } - }); - prepend.reverse(); - for item in prepend { - seq.insert(0, item); - } - - for item in append { - seq.push(item); - } - - let mut config = config.clone(); - config.insert(Value::from(name), Value::from(seq)); config } + +#[cfg(test)] +mod tests { + use super::*; + use serde_yaml::Value; + + #[test] + fn test_delete_proxy_and_references() { + let config_str = r#" +proxies: +- name: "proxy1" + type: "ss" +- name: "proxy2" + type: "vmess" +proxy-groups: +- name: "group1" + type: "select" + proxies: + - "proxy1" + - "proxy2" +- name: "group2" + type: "select" + proxies: + - "proxy1" +"#; + let mut config: Mapping = serde_yaml::from_str(config_str).unwrap(); + + let seq = SeqMap { + prepend: Sequence::new(), + append: Sequence::new(), + delete: vec!["proxy1".to_string()], + }; + + config = use_seq(seq, config, "proxies"); + + // Check if proxy1 is removed from proxies + let proxies = config.get("proxies").unwrap().as_sequence().unwrap(); + assert_eq!(proxies.len(), 1); + assert_eq!( + proxies[0].as_mapping().unwrap().get("name").unwrap().as_str().unwrap(), + "proxy2" + ); + + // Check if proxy1 is removed from all groups + let groups = config.get("proxy-groups").unwrap().as_sequence().unwrap(); + let group1_proxies = groups[0].as_mapping().unwrap() + .get("proxies").unwrap().as_sequence().unwrap(); + let group2_proxies = groups[1].as_mapping().unwrap() + .get("proxies").unwrap().as_sequence().unwrap(); + + assert_eq!(group1_proxies.len(), 1); + assert_eq!(group1_proxies[0].as_str().unwrap(), "proxy2"); + assert_eq!(group2_proxies.len(), 0); + } +}