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}