1use std::collections::HashMap;
2use std::ops::Deref;
3
4use serde::{Deserialize, Serialize};
5
6use super::TimeType;
7
8#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
9pub struct Proxies {
10 pub proxies: HashMap<String, Proxy>,
11}
12
13impl Proxies {
14 pub fn normal(&self) -> impl Iterator<Item = (&String, &Proxy)> {
15 self.iter().filter(|(_, x)| x.proxy_type.is_normal())
16 }
17
18 pub fn groups(&self) -> impl Iterator<Item = (&String, &Proxy)> {
19 self.iter().filter(|(_, x)| x.proxy_type.is_group())
20 }
21
22 pub fn selectors(&self) -> impl Iterator<Item = (&String, &Proxy)> {
23 self.iter().filter(|(_, x)| x.proxy_type.is_selector())
24 }
25
26 pub fn built_ins(&self) -> impl Iterator<Item = (&String, &Proxy)> {
27 self.iter().filter(|(_, x)| x.proxy_type.is_built_in())
28 }
29}
30
31impl Deref for Proxies {
32 type Target = HashMap<String, Proxy>;
33 fn deref(&self) -> &Self::Target {
34 &self.proxies
35 }
36}
37
38#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
39pub struct Proxy {
40 #[serde(rename = "type")]
41 pub proxy_type: ProxyType,
42 pub history: Vec<History>,
43 pub udp: Option<bool>,
44
45 pub all: Option<Vec<String>>,
47 pub now: Option<String>,
48}
49
50#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
51pub struct History {
52 pub time: TimeType,
53 pub delay: u64,
54}
55
56#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
57#[cfg_attr(
58 feature = "enum_ext",
59 derive(strum::EnumString, strum::Display, strum::EnumVariantNames),
60 strum(ascii_case_insensitive)
61)]
62pub enum ProxyType {
63 Direct,
65 Reject,
66 Selector,
68 URLTest,
69 Fallback,
70 LoadBalance,
71 Shadowsocks,
73 Vmess,
74 ShadowsocksR,
75 Http,
76 Snell,
77 Trojan,
78 Socks5,
79 Relay,
81 #[serde(other)]
83 Unknown,
84}
85
86impl ProxyType {
87 pub fn is_selector(&self) -> bool {
88 matches!(self, ProxyType::Selector)
89 }
90
91 pub fn is_group(&self) -> bool {
92 matches!(
93 self,
94 ProxyType::Selector
95 | ProxyType::URLTest
96 | ProxyType::Fallback
97 | ProxyType::LoadBalance
98 | ProxyType::Relay
99 )
100 }
101
102 pub fn is_built_in(&self) -> bool {
103 matches!(self, ProxyType::Direct | ProxyType::Reject)
104 }
105
106 pub fn is_normal(&self) -> bool {
107 matches!(
108 self,
109 ProxyType::Shadowsocks
110 | ProxyType::Vmess
111 | ProxyType::ShadowsocksR
112 | ProxyType::Http
113 | ProxyType::Snell
114 | ProxyType::Trojan
115 | ProxyType::Socks5
116 )
117 }
118}
119
120#[test]
121fn test_proxies() {
122 let proxy_kv = [
123 (
124 "test_a".to_owned(),
125 Proxy {
126 proxy_type: ProxyType::Direct,
127 history: vec![],
128 udp: Some(false),
129 all: None,
130 now: None,
131 },
132 ),
133 (
134 "test_b".to_owned(),
135 Proxy {
136 proxy_type: ProxyType::Selector,
137 history: vec![],
138 udp: Some(false),
139 all: Some(vec!["test_c".into()]),
140 now: Some("test_c".into()),
141 },
142 ),
143 (
144 "test_c".to_owned(),
145 Proxy {
146 proxy_type: ProxyType::Shadowsocks,
147 history: vec![],
148 udp: Some(false),
149 all: None,
150 now: None,
151 },
152 ),
153 (
154 "test_d".to_owned(),
155 Proxy {
156 proxy_type: ProxyType::Fallback,
157 history: vec![],
158 udp: Some(false),
159 all: Some(vec!["test_c".into()]),
160 now: Some("test_c".into()),
161 },
162 ),
163 ];
164 let proxies = Proxies {
165 proxies: HashMap::from(proxy_kv),
166 };
167 assert_eq!(
168 {
169 let mut tmp = proxies.groups().map(|x| x.0).collect::<Vec<_>>();
170 tmp.sort();
171 tmp
172 },
173 vec!["test_b", "test_d"]
174 );
175 assert_eq!(
176 proxies.built_ins().map(|x| x.0).collect::<Vec<_>>(),
177 vec!["test_a"]
178 );
179 assert_eq!(
180 proxies.normal().map(|x| x.0).collect::<Vec<_>>(),
181 vec!["test_c"]
182 );
183}