libsubconverter/models/
proxy.rs

1//! Proxy model definitions
2//!
3//! Contains the core data structures for proxy configurations.
4
5use std::collections::HashSet;
6
7use serde::{Deserialize, Serialize};
8
9use super::proxy_node::combined::CombinedProxy;
10
11/// Represents the type of a proxy.
12/// This is the canonical enum used for proxy type identification across the
13/// application.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum ProxyType {
16    Unknown,
17    Shadowsocks,
18    ShadowsocksR,
19    VMess,
20    Trojan,
21    Snell,
22    HTTP,
23    HTTPS,
24    Socks5,
25    WireGuard,
26    Hysteria,
27    Hysteria2,
28    // new proxy types could be added as enum combined proxy types
29    Vless,
30    AnyTls,
31}
32
33/// Converts a `ProxyType` into a human-readable name.
34impl ProxyType {
35    pub fn to_string(self) -> &'static str {
36        match self {
37            ProxyType::Shadowsocks => "SS",
38            ProxyType::ShadowsocksR => "SSR",
39            ProxyType::VMess => "VMess",
40            ProxyType::Trojan => "Trojan",
41            ProxyType::Snell => "Snell",
42            ProxyType::HTTP => "HTTP",
43            ProxyType::HTTPS => "HTTPS",
44            ProxyType::Socks5 => "SOCKS5",
45            ProxyType::WireGuard => "WireGuard",
46            ProxyType::Hysteria => "Hysteria",
47            ProxyType::Hysteria2 => "Hysteria2",
48            ProxyType::Vless => "Vless",
49            ProxyType::AnyTls => "AnyTLS",
50            ProxyType::Unknown => "Unknown",
51        }
52    }
53}
54
55/// Represents a proxy configuration. Serialized for JavaScripts.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(rename_all = "PascalCase")]
58pub struct Proxy {
59    pub proxy_type: ProxyType,
60    #[serde(flatten)]
61    pub combined_proxy: Option<CombinedProxy>,
62    pub id: u32,
63    pub group_id: i32,
64    pub group: String,
65    pub remark: String,
66    pub hostname: String,
67    pub port: u16,
68
69    pub username: Option<String>,
70    pub password: Option<String>,
71    pub encrypt_method: Option<String>,
72    pub plugin: Option<String>,
73    /// Plugin options in the format of `key1=value1;key2=value2`
74    pub plugin_option: Option<String>,
75    pub protocol: Option<String>,
76    pub protocol_param: Option<String>,
77    pub obfs: Option<String>,
78    pub obfs_param: Option<String>,
79    pub user_id: Option<String>,
80    pub alter_id: u16,
81    pub transfer_protocol: Option<String>,
82    pub fake_type: Option<String>,
83    pub tls_secure: bool,
84
85    pub host: Option<String>,
86    pub path: Option<String>,
87    pub edge: Option<String>,
88
89    pub quic_secure: Option<String>,
90    pub quic_secret: Option<String>,
91
92    pub udp: Option<bool>,
93    pub tcp_fast_open: Option<bool>,
94    pub allow_insecure: Option<bool>,
95    pub tls13: Option<bool>,
96
97    pub underlying_proxy: Option<String>,
98
99    pub snell_version: u16,
100    pub server_name: Option<String>,
101
102    pub self_ip: Option<String>,
103    pub self_ipv6: Option<String>,
104    pub public_key: Option<String>,
105    pub private_key: Option<String>,
106    pub pre_shared_key: Option<String>,
107    pub dns_servers: HashSet<String>,
108    pub mtu: u16,
109    pub allowed_ips: String,
110    pub keep_alive: u16,
111    pub test_url: Option<String>,
112    pub client_id: Option<String>,
113
114    pub ports: Option<String>,
115    /// upload speed in Mbps
116    pub up_speed: u32,
117    /// download speed in Mbps
118    pub down_speed: u32,
119    pub auth: Option<String>,
120    pub auth_str: Option<String>,
121    pub sni: Option<String>,
122    pub fingerprint: Option<String>,
123    pub ca: Option<String>,
124    pub ca_str: Option<String>,
125    pub recv_window_conn: u32,
126    pub recv_window: u32,
127    pub disable_mtu_discovery: Option<bool>,
128    pub hop_interval: u32,
129    pub alpn: HashSet<String>,
130
131    pub cwnd: u32,
132}
133
134/// Implement Default for Proxy
135impl Default for Proxy {
136    fn default() -> Self {
137        Proxy {
138            proxy_type: ProxyType::Unknown,
139            combined_proxy: None,
140            id: 0,
141            group_id: 0,
142            group: String::new(),
143            remark: String::new(),
144            hostname: String::new(),
145            port: 0,
146            username: None,
147            password: None,
148            encrypt_method: None,
149            plugin: None,
150            plugin_option: None,
151            protocol: None,
152            protocol_param: None,
153            obfs: None,
154            obfs_param: None,
155            user_id: None,
156            alter_id: 0,
157            transfer_protocol: None,
158            fake_type: None,
159            tls_secure: false,
160            host: None,
161            path: None,
162            edge: None,
163            quic_secure: None,
164            quic_secret: None,
165            udp: None,
166            tcp_fast_open: None,
167            allow_insecure: None,
168            tls13: None,
169            underlying_proxy: None,
170            snell_version: 0,
171            server_name: None,
172            self_ip: None,
173            self_ipv6: None,
174            public_key: None,
175            private_key: None,
176            pre_shared_key: None,
177            dns_servers: HashSet::new(),
178            mtu: 0,
179            allowed_ips: String::from("0.0.0.0/0, ::/0"),
180            keep_alive: 0,
181            test_url: None,
182            client_id: None,
183            ports: None,
184            up_speed: 0,
185            down_speed: 0,
186            auth: None,
187            auth_str: None,
188            sni: None,
189            fingerprint: None,
190            ca: None,
191            ca_str: None,
192            recv_window_conn: 0,
193            recv_window: 0,
194            disable_mtu_discovery: None,
195            hop_interval: 0,
196            alpn: HashSet::new(),
197            cwnd: 0,
198        }
199    }
200}
201#[cfg(feature = "js-runtime")]
202use rquickjs::{Ctx, IntoJs};
203#[cfg(feature = "js-runtime")]
204impl<'js> IntoJs<'js> for Proxy {
205    fn into_js(self, ctx: &Ctx<'js>) -> Result<rquickjs::Value<'js>, rquickjs::Error> {
206        let value =
207            ctx.json_parse(
208                serde_json::to_string(&self).map_err(|e| rquickjs::Error::IntoJs {
209                    from: "Proxy",
210                    to: "Json",
211                    message: Some(e.to_string()),
212                })?,
213            )?;
214        Ok(value)
215    }
216}
217
218impl Proxy {
219    pub fn is_combined_proxy(&self) -> bool {
220        matches!(
221            self.proxy_type,
222            ProxyType::Vless | ProxyType::Shadowsocks | ProxyType::AnyTls
223        )
224    }
225
226    /// 设置 UDP 支持,如果值已存在则不覆盖
227    pub fn with_udp(mut self, udp: Option<bool>) -> Self {
228        if self.udp.is_none() {
229            self.udp = udp;
230        }
231        self
232    }
233
234    /// 强制设置 UDP 支持,不论是否已存在值
235    pub fn set_udp(mut self, udp: bool) -> Self {
236        self.udp = Some(udp);
237        self
238    }
239
240    /// 设置 TCP Fast Open,如果值已存在则不覆盖
241    pub fn with_tfo(mut self, tfo: Option<bool>) -> Self {
242        if self.tcp_fast_open.is_none() {
243            self.tcp_fast_open = tfo;
244        }
245        self
246    }
247
248    /// 强制设置 TCP Fast Open,不论是否已存在值
249    pub fn set_tfo(mut self, tfo: bool) -> Self {
250        self.tcp_fast_open = Some(tfo);
251        self
252    }
253
254    /// 设置 Skip Cert Verify,如果值已存在则不覆盖
255    pub fn with_skip_cert_verify(mut self, scv: Option<bool>) -> Self {
256        if self.allow_insecure.is_none() {
257            self.allow_insecure = scv;
258        }
259        self
260    }
261
262    /// 强制设置 Skip Cert Verify,不论是否已存在值
263    pub fn set_skip_cert_verify(mut self, scv: bool) -> Self {
264        self.allow_insecure = Some(scv);
265        self
266    }
267
268    /// 设置代理备注
269    pub fn set_remark(mut self, remark: String) -> Self {
270        self.remark = remark;
271        self
272    }
273
274    /// 使用默认值应用 tribool 属性,如果属性值为 None 则设置为提供的默认值
275    pub fn apply_default_values(
276        mut self,
277        default_udp: Option<bool>,
278        default_tfo: Option<bool>,
279        default_scv: Option<bool>,
280    ) -> Self {
281        if self.udp.is_none() {
282            self.udp = default_udp;
283        }
284
285        if self.tcp_fast_open.is_none() {
286            self.tcp_fast_open = default_tfo;
287        }
288
289        if self.allow_insecure.is_none() {
290            self.allow_insecure = default_scv;
291        }
292
293        self
294    }
295}
296
297/// Default provider group names as constants.
298pub const SS_DEFAULT_GROUP: &str = "SSProvider";
299pub const SSR_DEFAULT_GROUP: &str = "SSRProvider";
300pub const V2RAY_DEFAULT_GROUP: &str = "V2RayProvider";
301pub const SOCKS_DEFAULT_GROUP: &str = "SocksProvider";
302pub const HTTP_DEFAULT_GROUP: &str = "HTTPProvider";
303pub const TROJAN_DEFAULT_GROUP: &str = "TrojanProvider";
304pub const SNELL_DEFAULT_GROUP: &str = "SnellProvider";
305pub const WG_DEFAULT_GROUP: &str = "WireGuardProvider";
306pub const HYSTERIA_DEFAULT_GROUP: &str = "HysteriaProvider";
307pub const HYSTERIA2_DEFAULT_GROUP: &str = "Hysteria2Provider";