clashctl_core/model/
rule.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
6// #[serde(rename_all = "UPPERCASE")]
7#[cfg_attr(
8    feature = "enum_ext",
9    derive(
10        strum::EnumString,
11        strum::Display,
12        strum::AsRefStr,
13        strum::IntoStaticStr,
14        strum::EnumVariantNames
15    ),
16    strum(ascii_case_insensitive)
17)]
18pub enum RuleType {
19    Domain,
20    DomainSuffix,
21    DomainKeyword,
22    GeoIP,
23    IPCIDR,
24    SrcIPCIDR,
25    SrcPort,
26    DstPort,
27    Process,
28    Match,
29    Direct,
30    Reject,
31    #[serde(other)]
32    Unknown,
33}
34
35#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
36pub struct Rule {
37    #[serde(rename = "type")]
38    pub rule_type: RuleType,
39    pub payload: String,
40    pub proxy: String,
41}
42
43#[derive(Serialize, Deserialize, Debug, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
44pub struct Rules {
45    pub rules: Vec<Rule>,
46}
47
48impl Rules {
49    pub fn most_frequent_proxy(&self) -> Option<&str> {
50        self.frequency()
51            .into_iter()
52            .max_by_key(|(_, v)| *v)
53            .map(|(k, _)| k)
54    }
55
56    pub fn frequency(&self) -> HashMap<&str, usize> {
57        let mut counts = HashMap::new();
58        self.rules
59            .iter()
60            .filter(|x| x.proxy != "DIRECT" && x.proxy != "REJECT")
61            .map(|x| x.proxy.as_str())
62            .for_each(|item| *counts.entry(item).or_default() += 1);
63        counts
64    }
65
66    pub fn owned_frequency(&self) -> HashMap<String, usize> {
67        let mut counts = HashMap::new();
68        self.rules
69            .iter()
70            .filter(|x| x.proxy != "DIRECT" && x.proxy != "REJECT")
71            .map(|x| x.proxy.to_owned())
72            .for_each(|item| *counts.entry(item).or_default() += 1);
73        counts
74    }
75}