clashctl_core/model/
rule.rs1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
6#[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}