mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 03:03:46 +08:00
fix: remove node related group info when deleting a node
This commit is contained in:
parent
bf374f2e85
commit
c51199719d
@ -1,55 +1,138 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_yaml::{Mapping, Sequence, Value};
|
use serde_yaml::{Mapping, Sequence, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct SeqMap {
|
pub struct SeqMap {
|
||||||
prepend: Sequence,
|
pub prepend: Sequence,
|
||||||
append: Sequence,
|
pub append: Sequence,
|
||||||
delete: Sequence,
|
pub delete: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_seq(seq_map: SeqMap, config: Mapping, name: &str) -> Mapping {
|
pub fn use_seq(seq: SeqMap, mut config: Mapping, field: &str) -> Mapping {
|
||||||
let mut prepend = seq_map.prepend;
|
let SeqMap {
|
||||||
let append = seq_map.append;
|
prepend,
|
||||||
let delete = seq_map.delete;
|
append,
|
||||||
|
delete,
|
||||||
|
} = seq;
|
||||||
|
|
||||||
let origin_seq = config.get(name).map_or(Sequence::default(), |val| {
|
let mut new_seq = Sequence::new();
|
||||||
val.as_sequence().unwrap_or(&Sequence::default()).clone()
|
new_seq.extend(prepend);
|
||||||
});
|
|
||||||
let mut seq = origin_seq.clone();
|
|
||||||
|
|
||||||
let mut delete_names = Vec::new();
|
if let Some(Value::Sequence(origin)) = config.get(field) {
|
||||||
for item in delete {
|
// Filter out deleted items
|
||||||
let item = item.clone();
|
let filtered: Sequence = origin
|
||||||
if let Some(name) = if item.is_string() {
|
.iter()
|
||||||
Some(item)
|
.filter(|item| {
|
||||||
} else {
|
if let Value::String(s) = item {
|
||||||
item.get("name").cloned()
|
!delete.contains(s)
|
||||||
} {
|
} else if let Value::Mapping(m) = item {
|
||||||
delete_names.push(name.clone());
|
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
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user