feat: get profile file name from response

This commit is contained in:
GyDi 2021-12-14 02:32:42 +08:00
parent ef3b10fa8f
commit 1bff7d5b0b

View File

@ -2,55 +2,80 @@ extern crate reqwest;
use crate::config::{read_profiles, save_profiles, ProfileExtra, ProfileItem}; use crate::config::{read_profiles, save_profiles, ProfileExtra, ProfileItem};
use crate::init::app_home_dir; use crate::init::app_home_dir;
use std::default::Default;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
/// parse the string
fn parse_string<'a>(target: &'a str, key: &'a str) -> Option<&'a str> {
match target.find(key) {
Some(idx) => {
let idx = idx + key.len();
let value = &target[idx..];
match value.split(';').nth(0) {
Some(value) => Some(value.trim()),
None => Some(value.trim()),
}
}
None => None,
}
}
/// Todo: log /// Todo: log
/// Import the Profile from url /// Import the Profile from url
/// save to the `verge.yaml` file /// save to the `verge.yaml` file
pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> { pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
let resp = reqwest::get(profile_url).await?; let resp = reqwest::get(profile_url).await?;
let header = resp.headers().clone(); let header = resp.headers().clone();
let value = header
.get("Subscription-Userinfo")
.unwrap()
.to_str()
.unwrap();
let value: Vec<&str> = value.clone().split(';').collect();
// parse the Subscription Userinfo // parse the Subscription Userinfo
let mut extra = ProfileExtra::default(); let extra = {
for each in value.iter() { let sub_info = header
let each = each.clone().trim(); .get("Subscription-Userinfo")
if let Some(val) = each.strip_prefix("upload=") { .unwrap()
extra.upload = val.parse().unwrap_or(0u64); .to_str()
continue; .unwrap();
ProfileExtra {
upload: parse_string(sub_info, "upload=")
.unwrap_or("0")
.parse()
.unwrap_or(0u64),
download: parse_string(sub_info, "download=")
.unwrap_or("0")
.parse()
.unwrap_or(0u64),
total: parse_string(sub_info, "total=")
.unwrap_or("0")
.parse()
.unwrap_or(0u64),
expire: parse_string(sub_info, "expire=")
.unwrap_or("0")
.parse()
.unwrap_or(0u64),
} }
if let Some(val) = each.strip_prefix("download=") { };
extra.download = val.parse().unwrap_or(0u64);
continue; // parse the file name
let file_name = {
let file_name = header.get("Content-Disposition").unwrap().to_str().unwrap();
let file_name = parse_string(file_name, "filename=");
match file_name {
Some(f) => f.to_string(),
None => {
let cur_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
format!("{}.yaml", cur_time)
}
} }
if let Some(val) = each.strip_prefix("total=") { };
extra.total = val.parse().unwrap_or(0u64);
continue;
}
if let Some(val) = each.strip_prefix("expire=") {
extra.expire = val.parse().unwrap_or(0u64);
continue;
}
}
// save file // save file
let file_data = resp.text_with_charset("utf-8").await?; let file_data = resp.text_with_charset("utf-8").await?;
let cur_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let file_name = format!("{}.yaml", cur_time);
let file_path = app_home_dir().join("profiles").join(&file_name); let file_path = app_home_dir().join("profiles").join(&file_name);
File::create(file_path) File::create(file_path)
.unwrap() .unwrap()
.write(file_data.as_bytes()) .write(file_data.as_bytes())
@ -58,10 +83,9 @@ pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
// update profiles.yaml // update profiles.yaml
let mut profiles = read_profiles(); let mut profiles = read_profiles();
let mut items = if profiles.items.is_some() { let mut items = match profiles.items {
profiles.items.unwrap() Some(p) => p,
} else { None => vec![],
vec![]
}; };
let profile = ProfileItem { let profile = ProfileItem {
@ -77,14 +101,30 @@ pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
.iter() .iter()
.position(|x| x.name.is_some() && x.name.as_ref().unwrap().as_str() == file_name.as_str()); .position(|x| x.name.is_some() && x.name.as_ref().unwrap().as_str() == file_name.as_str());
if target_index.is_none() { match target_index {
items.push(profile) Some(idx) => items[idx] = profile,
} else { None => items.push(profile),
items[target_index.unwrap()] = profile; };
}
profiles.items = Some(items); profiles.items = Some(items);
save_profiles(&profiles); save_profiles(&profiles);
Ok(()) Ok(())
} }
#[test]
fn test_parse_value() {
let test_1 = "upload=111; download=2222; total=3333; expire=444";
let test_2 = "attachment; filename=Clash.yaml";
assert_eq!(parse_string(test_1, "upload="), Some("111"));
assert_eq!(parse_string(test_1, "download="), Some("2222"));
assert_eq!(parse_string(test_1, "total="), Some("3333"));
assert_eq!(parse_string(test_1, "expire="), Some("444"));
assert_eq!(parse_string(test_2, "filename="), Some("Clash.yaml"));
assert_eq!(parse_string(test_1, "aaa="), None);
assert_eq!(parse_string(test_1, "upload1="), None);
assert_eq!(parse_string(test_1, "expire1="), None);
assert_eq!(parse_string(test_2, "attachment="), None);
}