proxy_scraper/
vmess.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 VMess proxy.
7#[derive(Debug, Serialize, Deserialize)]
8pub struct VMess {
9    /// The address of the VMess server.
10    pub add: String,
11    /// The optional host address of the VMess server.
12    pub host: Option<String>,
13    /// The UUID of the VMess server.
14    pub id: String,
15    /// The port number of the VMess server.
16    pub port: serde_json::Value,
17    /// The network type of the VMess server.
18    pub net: String,
19    /// The optional SNI (Server Name Indication) of the VMess server.
20    pub sni: Option<String>,
21    /// The optional TLS (Transport Layer Security) of the VMess server.
22    pub tls: Option<String>,
23    /// Additional metadata associated with the VMess server.
24    #[serde(flatten)]
25    pub metadata: Option<HashMap<String, String>>,
26}
27
28impl VMess {
29    /// Converts the VMess proxy information into a VMess URL.
30    ///
31    /// # Example
32    ///
33    /// ```
34    /// use proxy_scraper::vmess::VMess;
35    /// let proxy = VMess {
36    ///     add: "example.com".to_string(),
37    ///     host: Some("www.example.com".to_string()),
38    ///     id: "uuid".to_string(),
39    ///     port: serde_json::json!(443),
40    ///     net: "tcp".to_string(),
41    ///     sni: Some("example.com".to_string()),
42    ///     tls: Some("tls".to_string()),
43    ///     metadata: None,
44    /// };
45    /// let url = proxy.to_url();
46    /// assert_eq!(url, "vmess://ewogICJhZGQiOiAiZXhhbXBsZS5jb20iLAogICJob3N0IjogInd3dy5leGFtcGxlLmNvbSIsCiAgImlkIjogInV1aWQiLAogICJwb3J0IjogNDQzLAogICJuZXQiOiAidGNwIiwKICAic25pIjogImV4YW1wbGUuY29tIiwKICAidGxzIjogInRscyIKfQ==");
47    /// ```
48    pub fn to_url(&self) -> String {
49        let base64_part = URL_SAFE.encode(serde_json::to_vec_pretty(&self).unwrap());
50        format!("vmess://{}", base64_part)
51    }
52
53    /// Scrapes VMess proxy information from the provided source string and returns a vector of VMess instances.
54    ///
55    /// # Arguments
56    ///
57    /// * `source` - A string containing the source code or text from which to extract VMess proxy information.
58    ///
59    /// # Returns
60    ///
61    /// A vector of `VMess` instances parsed from the source string.
62    pub fn scrape(source: &str) -> Vec<Self> {
63        let source = crate::utils::seperate_links(source);
64        let mut proxy_list: Vec<VMess> = Vec::new();
65        let regex = Regex::new(
66            r#"vmess://((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?)"#,
67        )
68        .unwrap();
69
70        for captures in regex.captures_iter(&source) {
71            let base64_part = captures.get(1).map(|b64| b64.as_str()).unwrap_or("");
72
73            if base64_part.is_empty() {
74                continue;
75            }
76
77            if let Ok(decoded_base64_part) = URL_SAFE.decode(&base64_part) {
78                let json_string = String::from_utf8(decoded_base64_part).unwrap();
79
80                let deserialized_vmess: VMess = serde_json::from_str(&json_string).unwrap();
81
82                proxy_list.push(deserialized_vmess);
83            }
84        }
85
86        proxy_list
87    }
88}