proxy_scraper/
vless.rs

1use base64::{engine::general_purpose::URL_SAFE, Engine as _};
2use regex::Regex;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Represents a VLess proxy.
7#[derive(Debug, Serialize, Deserialize)]
8pub struct VLess {
9    /// The host address of the VLess proxy.
10    pub host: String,
11    /// The port number for the VLess proxy.
12    pub port: u32,
13    /// The UUID of the VLess proxy.
14    pub id: String,
15    /// Additional parameters associated with the VLess proxy.
16    #[serde(flatten)]
17    pub parameters: Option<HashMap<String, String>>,
18}
19
20impl VLess {
21    /// Converts the VLess proxy information into a VLess URL.
22    ///
23    /// # Example
24    ///
25    /// ```
26    /// use proxy_scraper::vless::VLess;
27    /// let proxy = VLess {
28    ///     host: "example.com".to_string(),
29    ///     port: 443,
30    ///     id: "00000000-0000-0000-0000-000000000000".to_string(),
31    ///     parameters: None,
32    /// };
33    /// let url = proxy.to_url();
34    /// assert_eq!(url, "vless://00000000-0000-0000-0000-000000000000@example.com:443?");
35    /// ```
36    pub fn to_url(&self) -> String {
37        let url_encoded_parameters = serde_urlencoded::to_string(&self.parameters).unwrap();
38        format!(
39            "vless://{}@{}:{}?{}",
40            self.id, self.host, self.port, url_encoded_parameters
41        )
42    }
43
44    /// Scrapes VLess proxy information from the provided source string and returns a vector of VLess instances.
45    ///
46    /// # Arguments
47    ///
48    /// * `source` - A string containing the source code or text from which to extract VLess proxy information.
49    ///
50    /// # Returns
51    ///
52    /// A vector of `VLess` instances parsed from the source string.
53    pub fn scrape(source: &str) -> Vec<Self> {
54        let source = crate::utils::seperate_links(source);
55        let mut proxy_list: Vec<VLess> = Vec::new();
56        let regex = Regex::new(r#"vless://([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})@((.+):(\d+))\?(.+)#"#).unwrap();
57
58        for captures in regex.captures_iter(&source) {
59            let uuid = captures.get(1).map(|id| id.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 uuid.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 vless_proxy = VLess {
72                host: host.to_string(),
73                port: port.parse::<u32>().unwrap_or(0),
74                id: uuid.to_string(),
75                parameters: Some(parameters),
76            };
77
78            proxy_list.push(vless_proxy);
79        }
80
81        proxy_list
82    }
83}