use crate::{
models::{Proxy, SNELL_DEFAULT_GROUP},
utils::url_decode,
};
use std::collections::HashMap;
use url::Url;
pub fn explode_snell(snell: &str, node: &mut Proxy) -> bool {
if !snell.starts_with("snell://") {
return false;
}
let url = match Url::parse(snell) {
Ok(url) => url,
Err(_) => return false,
};
let host = match url.host_str() {
Some(host) => host,
None => return false,
};
let port = url.port().unwrap_or(8388);
if port == 0 {
return false; }
let password = url.username();
if password.is_empty() {
return false;
}
let mut params = HashMap::new();
for (key, value) in url.query_pairs() {
params.insert(key.to_string(), url_decode(&value));
}
let obfs = params.get("obfs").map(|s| s.as_str()).unwrap_or("none");
let host_param = params.get("host").map(|s| s.as_str()).unwrap_or("");
let version = params
.get("version")
.map(|s| s.parse::<u16>().unwrap_or(1))
.unwrap_or(1);
let udp = params.get("udp").map(|s| s == "true" || s == "1");
let tfo = params.get("tfo").map(|s| s == "true" || s == "1");
let allow_insecure = params
.get("skip-cert-verify")
.map(|s| s == "true" || s == "1");
let remark = url_decode(url.fragment().unwrap_or(""));
let formatted_remark = if remark.is_empty() {
format!("{} ({})", host, port)
} else {
remark.to_string()
};
*node = Proxy::snell_construct(
SNELL_DEFAULT_GROUP.to_string(),
formatted_remark,
host.to_string(),
port,
password.to_string(),
obfs.to_string(),
host_param.to_string(),
version,
udp,
tfo,
allow_insecure,
None,
);
true
}
pub fn explode_snell_surge(surge: &str, node: &mut Proxy) -> bool {
if !surge.starts_with("snell") {
return false;
}
let parts: Vec<&str> = surge.split(',').map(|s| s.trim()).collect();
if parts.len() < 3 {
return false;
}
let server_part = parts[0];
let server = if server_part.contains('=') {
server_part
.split('=')
.nth(1)
.unwrap_or("")
.trim()
.to_string()
} else {
server_part.replace("snell", "").trim().to_string()
};
if server.is_empty() {
return false;
}
let port_str = parts[1];
let port = match port_str.parse::<u16>() {
Ok(p) => p,
Err(_) => return false,
};
if port == 0 {
return false;
}
let mut password = String::new();
let mut obfs = String::new();
let mut obfs_host = String::new();
let mut version = 1u16;
let mut udp = None;
let mut tfo = None;
let mut allow_insecure = None;
for i in 2..parts.len() {
let param_parts: Vec<&str> = parts[i].split('=').collect();
if param_parts.len() != 2 {
continue;
}
let key = param_parts[0].trim();
let value = param_parts[1].trim();
match key {
"psk" => password = value.to_string(),
"obfs" => obfs = value.to_string(),
"obfs-host" => obfs_host = value.to_string(),
"version" => version = value.parse::<u16>().unwrap_or(1),
"udp" | "udp-relay" => udp = Some(value == "true" || value == "1"),
"tfo" => tfo = Some(value == "true" || value == "1"),
"skip-cert-verify" => allow_insecure = Some(value == "true" || value == "1"),
_ => {}
}
}
if password.is_empty() {
return false;
}
let remark = format!("{} ({})", server, port);
*node = Proxy::snell_construct(
SNELL_DEFAULT_GROUP.to_string(),
remark,
server,
port,
password,
obfs,
obfs_host,
version,
udp,
tfo,
allow_insecure,
None,
);
true
}