use serde_yaml_ng::{Mapping, Value}; use smartstring::alias::String; use std::collections::{HashMap, HashSet}; use crate::enhance::field::use_keys; const PATCH_CONFIG_INNER: [&str; 4] = ["allow-lan", "ipv6", "log-level", "unified-delay"]; #[derive(Default, Clone)] pub struct IRuntime { pub config: Option, // 记录在订阅中(包括merge和script生成的)出现过的keys // 这些keys不一定都生效 pub exists_keys: HashSet, // TODO 或许可以用 FixMap 来存储以提升效率 pub chain_logs: HashMap>, } impl IRuntime { #[inline] pub fn new() -> Self { Self::default() } #[inline] pub fn clean_all(&mut self) { self.config = None; self.exists_keys.clear(); self.chain_logs.clear(); } // 这里只更改 allow-lan | ipv6 | log-level | tun #[inline] pub fn patch_config(&mut self, patch: &Mapping) { let config = if let Some(config) = self.config.as_mut() { config } else { return; }; for key in PATCH_CONFIG_INNER.iter() { if let Some(value) = patch.get(key) { config.insert((*key).into(), value.clone()); } } let patch_tun = patch.get("tun"); if let Some(patch_tun_value) = patch_tun { let mut tun = config .get("tun") .and_then(|val| val.as_mapping()) .cloned() .unwrap_or_else(Mapping::new); if let Some(patch_tun_mapping) = patch_tun_value.as_mapping() { for key in use_keys(patch_tun_mapping) { if let Some(value) = patch_tun_mapping.get(key.as_str()) { tun.insert(Value::from(key.as_str()), value.clone()); } } } config.insert("tun".into(), Value::from(tun)); } } /// 更新链式代理配置 /// /// 该函数更新 `proxies` 和 `proxy-groups` 配置,并处理链式代理的修改或(传入 None )删除。 /// /// 配置示例: /// /// ```json /// { /// "proxies": [ /// { /// "name": "入口节点", /// "type": "xxx", /// "server": "xxx", /// "port": "xxx", /// "ports": "xxx", /// "password": "xxx", /// "skip-cert-verify": "xxx" /// }, /// { /// "name": "hop_node_1_xxxx", /// "type": "xxx", /// "server": "xxx", /// "port": "xxx", /// "ports": "xxx", /// "password": "xxx", /// "skip-cert-verify": "xxx", /// "dialer-proxy": "入口节点" /// }, /// { /// "name": "出口节点", /// "type": "xxx", /// "server": "xxx", /// "port": "xxx", /// "ports": "xxx", /// "password": "xxx", /// "skip-cert-verify": "xxx", /// "dialer-proxy": "hop_node_1_xxxx" /// } /// ], /// "proxy-groups": [ /// { /// "name": "proxy_chain", /// "type": "select", /// "proxies": ["出口节点"] /// } /// ] /// } /// ``` #[inline] pub fn update_proxy_chain_config(&mut self, proxy_chain_config: Option) { let config = if let Some(config) = self.config.as_mut() { config } else { return; }; if let Some(Value::Sequence(proxies)) = config.get_mut("proxies") { proxies.iter_mut().for_each(|proxy| { if let Some(proxy) = proxy.as_mapping_mut() && proxy.get("dialer-proxy").is_some() { proxy.remove("dialer-proxy"); } }); } if let Some(Value::Sequence(dialer_proxies)) = proxy_chain_config && let Some(Value::Sequence(proxies)) = config.get_mut("proxies") { for (i, dialer_proxy) in dialer_proxies.iter().enumerate() { if let Some(Value::Mapping(proxy)) = proxies.iter_mut().find(|proxy| proxy.get("name") == Some(dialer_proxy)) && i != 0 && let Some(dialer_proxy) = dialer_proxies.get(i - 1) { proxy.insert("dialer-proxy".into(), dialer_proxy.to_owned()); } } } } }