1use regex::Regex;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5#[derive(Debug, Serialize, Deserialize)]
7pub struct TUIC {
8 pub host: String,
10 pub port: u32,
12 pub auth: String,
14 #[serde(flatten)]
16 pub parameters: Option<HashMap<String, String>>,
17}
18
19impl TUIC {
20 pub fn to_url(&self) -> String {
37 let url_encoded_parameters = serde_urlencoded::to_string(&self.parameters).unwrap();
38 format!(
39 "tuic://{}@{}:{}?{}",
40 self.auth, self.host, self.port, url_encoded_parameters
41 )
42 }
43
44 pub fn scrape(source: &str) -> Vec<Self> {
54 let source = crate::utils::seperate_links(source);
55 let mut proxy_list: Vec<TUIC> = Vec::new();
56 let regex = Regex::new(r#"tuic://([A-Za-z0-9\-._~]+)@((.+):(\d+))\?(.+)#"#).unwrap();
57
58 for captures in regex.captures_iter(&source) {
59 let auth = captures.get(1).map(|auth| auth.as_str()).unwrap_or("");
60 let host = captures.get(3).map(|host| host.as_str()).unwrap_or("");
61 let port = captures.get(4).map(|port| port.as_str()).unwrap_or("");
62 let url_parameters = captures.get(5).map(|params| params.as_str()).unwrap_or("");
63
64 if auth.is_empty() || host.is_empty() || port.is_empty() || url_parameters.is_empty() {
65 continue;
66 }
67
68 let parameters: HashMap<String, String> =
69 serde_urlencoded::from_str(&url_parameters).unwrap();
70
71 let tuic_proxy = TUIC {
72 host: host.to_string(),
73 port: port.parse::<u32>().unwrap_or(0),
74 auth: auth.to_string(),
75 parameters: Some(parameters),
76 };
77
78 proxy_list.push(tuic_proxy);
79 }
80
81 proxy_list
82 }
83}