use super::SeqMap; use crate::{ config::PrfItem, utils::{dirs, help}, }; use serde_yaml_ng::Mapping; use smartstring::alias::String; use tokio::fs; #[derive(Debug, Clone)] pub struct ChainItem { pub uid: String, pub data: ChainType, } #[derive(Debug, Clone)] pub enum ChainType { Merge(Mapping), Script(String), Rules(SeqMap), Proxies(SeqMap), Groups(SeqMap), } #[derive(Debug, Clone)] pub enum ChainSupport { ClashMeta, ClashMetaAlpha, } // impl From<&PrfItem> for Option { // fn from(item: &PrfItem) -> Self { // let itype = item.itype.as_ref()?.as_str(); // let file = item.file.clone()?; // let uid = item.uid.clone().unwrap_or("".into()); // let path = dirs::app_profiles_dir().ok()?.join(file); // if !path.exists() { // return None; // } // match itype { // "script" => Some(ChainItem { // uid, // data: ChainType::Script(fs::read_to_string(path).ok()?), // }), // "merge" => Some(ChainItem { // uid, // data: ChainType::Merge(help::read_mapping(&path).ok()?), // }), // "rules" => Some(ChainItem { // uid, // data: ChainType::Rules(help::read_seq_map(&path).ok()?), // }), // "proxies" => Some(ChainItem { // uid, // data: ChainType::Proxies(help::read_seq_map(&path).ok()?), // }), // "groups" => Some(ChainItem { // uid, // data: ChainType::Groups(help::read_seq_map(&path).ok()?), // }), // _ => None, // } // } // } // Helper trait to allow async conversion pub trait AsyncChainItemFrom { async fn from_async(item: &PrfItem) -> Option; } impl AsyncChainItemFrom for Option { async fn from_async(item: &PrfItem) -> Self { let itype = item.itype.as_ref()?.as_str(); let file = item.file.clone()?; let uid = item.uid.clone().unwrap_or_else(|| "".into()); let path = dirs::app_profiles_dir().ok()?.join(file.as_str()); if !path.exists() { return None; } match itype { "script" => Some(ChainItem { uid, data: ChainType::Script(fs::read_to_string(path).await.ok()?.into()), }), "merge" => Some(ChainItem { uid, data: ChainType::Merge(help::read_mapping(&path).await.ok()?), }), "rules" => { let seq_map = help::read_seq_map(&path).await.ok()?; Some(ChainItem { uid, data: ChainType::Rules(seq_map), }) } "proxies" => { let seq_map = help::read_seq_map(&path).await.ok()?; Some(ChainItem { uid, data: ChainType::Proxies(seq_map), }) } "groups" => { let seq_map = help::read_seq_map(&path).await.ok()?; Some(ChainItem { uid, data: ChainType::Groups(seq_map), }) } _ => None, } } } impl ChainItem { /// 内建支持一些脚本 pub fn builtin() -> Vec<(ChainSupport, Self)> { // meta 的一些处理 let meta_guard = Self::to_script("verge_meta_guard", include_str!("./builtin/meta_guard.js")); // meta 1.13.2 alpn string 转 数组 let hy_alpn = Self::to_script("verge_hy_alpn", include_str!("./builtin/meta_hy_alpn.js")); // meta 的一些处理 let meta_guard_alpha = Self::to_script("verge_meta_guard", include_str!("./builtin/meta_guard.js")); // meta 1.13.2 alpn string 转 数组 let hy_alpn_alpha = Self::to_script("verge_hy_alpn", include_str!("./builtin/meta_hy_alpn.js")); vec![ (ChainSupport::ClashMeta, hy_alpn), (ChainSupport::ClashMeta, meta_guard), (ChainSupport::ClashMetaAlpha, hy_alpn_alpha), (ChainSupport::ClashMetaAlpha, meta_guard_alpha), ] } pub fn to_script, D: Into>(uid: U, data: D) -> Self { Self { uid: uid.into(), data: ChainType::Script(data.into()), } } } impl ChainSupport { pub fn is_support(&self, core: Option<&String>) -> bool { match core { Some(core) => matches!( (self, core.as_str()), (Self::ClashMeta, "verge-mihomo") | (Self::ClashMetaAlpha, "verge-mihomo-alpha") ), None => true, } } }