swan_common/types/
proxy.rs1use syn::{LitStr, LitBool};
2
3#[derive(Debug, Clone, PartialEq)]
5pub enum ProxyType {
6 Http,
8 Socks5,
10}
11
12impl ProxyType {
13 pub fn from_str(s: &str) -> Option<Self> {
15 match s.to_lowercase().as_str() {
16 "http" => Some(ProxyType::Http),
17 "socks5" => Some(ProxyType::Socks5),
18 _ => None,
19 }
20 }
21
22 pub fn as_str(&self) -> &'static str {
24 match self {
25 ProxyType::Http => "http",
26 ProxyType::Socks5 => "socks5",
27 }
28 }
29}
30
31#[derive(Clone)]
39pub enum ProxyConfig {
40 Simple(LitStr),
42 Full {
44 proxy_type: Option<ProxyType>,
45 url: LitStr,
46 username: Option<LitStr>,
47 password: Option<LitStr>,
48 no_proxy: Option<LitStr>,
49 },
50 Disabled(LitBool),
52}
53
54impl ProxyConfig {
55 pub fn url(&self) -> Option<&LitStr> {
57 match self {
58 ProxyConfig::Simple(url) => Some(url),
59 ProxyConfig::Full { url, .. } => Some(url),
60 ProxyConfig::Disabled(_) => None,
61 }
62 }
63
64 pub fn proxy_type(&self) -> Option<&ProxyType> {
66 match self {
67 ProxyConfig::Full { proxy_type, .. } => proxy_type.as_ref(),
68 _ => None,
69 }
70 }
71
72 pub fn username(&self) -> Option<&LitStr> {
74 match self {
75 ProxyConfig::Full { username, .. } => username.as_ref(),
76 _ => None,
77 }
78 }
79
80 pub fn password(&self) -> Option<&LitStr> {
82 match self {
83 ProxyConfig::Full { password, .. } => password.as_ref(),
84 _ => None,
85 }
86 }
87
88 pub fn no_proxy(&self) -> Option<&LitStr> {
90 match self {
91 ProxyConfig::Full { no_proxy, .. } => no_proxy.as_ref(),
92 _ => None,
93 }
94 }
95
96 pub fn is_disabled(&self) -> bool {
98 matches!(self, ProxyConfig::Disabled(_))
99 }
100
101 pub fn infer_proxy_type(&self) -> Option<ProxyType> {
103 match self {
104 ProxyConfig::Simple(url) => {
105 let url_value = url.value();
106 if url_value.starts_with("http://") || url_value.starts_with("https://") {
107 Some(ProxyType::Http)
108 } else if url_value.starts_with("socks5://") {
109 Some(ProxyType::Socks5)
110 } else {
111 None
112 }
113 }
114 ProxyConfig::Full { proxy_type, url, .. } => {
115 if let Some(ptype) = proxy_type {
116 Some(ptype.clone())
117 } else {
118 let url_value = url.value();
120 if url_value.starts_with("http://") || url_value.starts_with("https://") {
121 Some(ProxyType::Http)
122 } else if url_value.starts_with("socks5://") {
123 Some(ProxyType::Socks5)
124 } else {
125 Some(ProxyType::Http)
127 }
128 }
129 }
130 ProxyConfig::Disabled(_) => None,
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use syn::LitStr;
139 use proc_macro2::Span;
140
141 #[test]
142 fn test_simple_proxy_config() {
143 let url = LitStr::new("http://proxy.example.com:8080", Span::call_site());
144 let config = ProxyConfig::Simple(url);
145
146 assert!(config.url().is_some());
147 assert_eq!(config.url().unwrap().value(), "http://proxy.example.com:8080");
148 assert!(config.username().is_none());
149 assert!(config.password().is_none());
150 assert!(!config.is_disabled());
151 }
152
153 #[test]
154 fn test_full_proxy_config() {
155 let url = LitStr::new("http://proxy.example.com:8080", Span::call_site());
156 let username = Some(LitStr::new("user", Span::call_site()));
157 let password = Some(LitStr::new("pass", Span::call_site()));
158
159 let config = ProxyConfig::Full {
160 proxy_type: Some(ProxyType::Http),
161 url,
162 username,
163 password,
164 no_proxy: None,
165 };
166
167 assert!(config.url().is_some());
168 assert_eq!(config.url().unwrap().value(), "http://proxy.example.com:8080");
169 assert!(config.username().is_some());
170 assert_eq!(config.username().unwrap().value(), "user");
171 assert!(config.password().is_some());
172 assert_eq!(config.password().unwrap().value(), "pass");
173 assert!(!config.is_disabled());
174 }
175
176 #[test]
177 fn test_disabled_proxy_config() {
178 let disabled = LitBool::new(false, Span::call_site());
179 let config = ProxyConfig::Disabled(disabled);
180
181 assert!(config.url().is_none());
182 assert!(config.username().is_none());
183 assert!(config.password().is_none());
184 assert!(config.is_disabled());
185 }
186}