Files
clash-proxy/src-tauri/src/utils/fetch.rs

103 lines
2.9 KiB
Rust
Raw Normal View History

2022-01-08 01:27:25 +08:00
use crate::core::{ProfileExtra, ProfileResponse};
2021-12-18 02:29:54 +08:00
use std::{
str::FromStr,
time::{SystemTime, UNIX_EPOCH},
};
2021-12-13 02:29:48 +08:00
/// parse the string
2021-12-18 02:29:54 +08:00
fn parse_string<T: FromStr>(target: &str, key: &str) -> Option<T> {
match target.find(key) {
Some(idx) => {
let idx = idx + key.len();
let value = &target[idx..];
2021-12-18 02:29:54 +08:00
match match value.split(';').nth(0) {
Some(value) => value.trim().parse(),
None => value.trim().parse(),
} {
Ok(r) => Some(r),
Err(_) => None,
}
}
None => None,
}
}
2022-02-19 00:09:36 +08:00
/// fetch and parse the profile url
/// maybe it contains some Subscription infomations, maybe not
pub async fn fetch_profile(url: &str, with_proxy: bool) -> Result<ProfileResponse, String> {
2022-01-16 22:57:42 +08:00
let builder = reqwest::ClientBuilder::new();
let client = match with_proxy {
true => builder.build(),
false => builder.no_proxy().build(),
};
2022-02-19 00:09:36 +08:00
let resp = match client.unwrap().get(url).send().await {
Ok(res) => res,
Err(_) => return Err("failed to create https client".into()),
2021-12-14 22:33:42 +08:00
};
2022-01-16 22:57:42 +08:00
2021-12-14 22:33:42 +08:00
let header = resp.headers();
2021-12-13 02:29:48 +08:00
2021-12-14 00:40:41 +08:00
// parse the Subscription Userinfo
2022-02-19 00:09:36 +08:00
let extra = match header.get("Subscription-Userinfo") {
Some(value) => {
let sub_info = value.to_str().unwrap_or("");
2022-02-19 00:09:36 +08:00
Some(ProfileExtra {
upload: parse_string(sub_info, "upload=").unwrap_or(0),
download: parse_string(sub_info, "download=").unwrap_or(0),
total: parse_string(sub_info, "total=").unwrap_or(0),
expire: parse_string(sub_info, "expire=").unwrap_or(0),
})
2021-12-13 02:29:48 +08:00
}
2022-02-19 00:09:36 +08:00
None => None,
};
2022-02-17 13:44:26 +08:00
let file = {
2021-12-14 22:33:42 +08:00
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
2022-02-17 13:44:26 +08:00
format!("{}.yaml", now)
};
2021-12-14 22:33:42 +08:00
2022-02-17 13:44:26 +08:00
let name = match header.get("Content-Disposition") {
Some(name) => {
let name = name.to_str().unwrap();
parse_string::<String>(name, "filename=").unwrap_or(file.clone())
2021-12-13 02:29:48 +08:00
}
2022-02-17 13:44:26 +08:00
None => file.clone(),
};
2021-12-13 02:29:48 +08:00
2021-12-14 22:33:42 +08:00
// get the data
2022-02-19 00:09:36 +08:00
match resp.text_with_charset("utf-8").await {
Ok(data) => Ok(ProfileResponse {
file,
name,
data,
extra,
}),
Err(_) => Err("failed to parse the response data".into()),
}
2021-12-13 02:29:48 +08:00
}
#[test]
fn test_parse_value() {
let test_1 = "upload=111; download=2222; total=3333; expire=444";
let test_2 = "attachment; filename=Clash.yaml";
2021-12-18 02:29:54 +08:00
assert_eq!(parse_string::<usize>(test_1, "upload=").unwrap(), 111);
assert_eq!(parse_string::<usize>(test_1, "download=").unwrap(), 2222);
assert_eq!(parse_string::<usize>(test_1, "total=").unwrap(), 3333);
assert_eq!(parse_string::<usize>(test_1, "expire=").unwrap(), 444);
assert_eq!(
parse_string::<String>(test_2, "filename=").unwrap(),
format!("Clash.yaml")
);
2021-12-18 02:29:54 +08:00
assert_eq!(parse_string::<usize>(test_1, "aaa="), None);
assert_eq!(parse_string::<usize>(test_1, "upload1="), None);
assert_eq!(parse_string::<usize>(test_1, "expire1="), None);
assert_eq!(parse_string::<usize>(test_2, "attachment="), None);
}