refactor: import profile
This commit is contained in:
parent
b5bb39ef3d
commit
eb3daf7b3e
@ -1,7 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
config::{read_profiles, save_profiles, ProfileItem},
|
||||||
events::{emit::ClashInfoPayload, state::ClashInfoState},
|
events::{emit::ClashInfoPayload, state::ClashInfoState},
|
||||||
utils::{clash, import},
|
utils::{app_home_dir, clash, fetch::fetch_profile},
|
||||||
};
|
};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
use tauri::{api::process::kill_children, AppHandle, State};
|
use tauri::{api::process::kill_children, AppHandle, State};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@ -14,14 +17,6 @@ pub fn restart_sidebar(app_handle: AppHandle, clash_info: State<'_, ClashInfoSta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn import_profile(url: String) -> Result<String, String> {
|
|
||||||
match import::import_profile(&url).await {
|
|
||||||
Ok(_) => Ok(String::from("success")),
|
|
||||||
Err(_) => Err(String::from("error")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfoPayload> {
|
pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfoPayload> {
|
||||||
match clash_info.0.lock() {
|
match clash_info.0.lock() {
|
||||||
@ -29,3 +24,44 @@ pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfo
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Import the Profile from url and
|
||||||
|
/// save to the `profiles.yaml` file
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn import_profile(url: String) -> Result<String, String> {
|
||||||
|
let result = match fetch_profile(&url).await {
|
||||||
|
Some(r) => r,
|
||||||
|
None => {
|
||||||
|
log::error!("failed to fetch profile from `{}`", url);
|
||||||
|
return Err(format!("failed"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = app_home_dir().join("profiles").join(&result.file);
|
||||||
|
File::create(path)
|
||||||
|
.unwrap()
|
||||||
|
.write(result.data.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// update profiles.yaml
|
||||||
|
let mut profiles = read_profiles();
|
||||||
|
let mut items = match profiles.items {
|
||||||
|
Some(p) => p,
|
||||||
|
None => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let profile = ProfileItem {
|
||||||
|
name: Some(result.name),
|
||||||
|
file: Some(result.file),
|
||||||
|
mode: Some(format!("rule")),
|
||||||
|
url: Some(url),
|
||||||
|
selected: Some(vec![]), // Todo: parse the selected list
|
||||||
|
extra: Some(result.extra),
|
||||||
|
};
|
||||||
|
|
||||||
|
items.push(profile);
|
||||||
|
profiles.items = Some(items);
|
||||||
|
save_profiles(&profiles);
|
||||||
|
|
||||||
|
Ok(format!("success"))
|
||||||
|
}
|
||||||
|
@ -39,3 +39,12 @@ pub struct ProfileExtra {
|
|||||||
pub total: u64,
|
pub total: u64,
|
||||||
pub expire: u64,
|
pub expire: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||||
|
/// the result from url
|
||||||
|
pub struct ProfileResponse {
|
||||||
|
pub name: String,
|
||||||
|
pub file: String,
|
||||||
|
pub data: String,
|
||||||
|
pub extra: ProfileExtra,
|
||||||
|
}
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
extern crate reqwest;
|
use crate::config::{ProfileExtra, ProfileResponse};
|
||||||
|
|
||||||
use crate::config::{read_profiles, save_profiles, ProfileExtra, ProfileItem};
|
|
||||||
use crate::utils::app_home_dir;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
/// parse the string
|
/// parse the string
|
||||||
@ -21,12 +16,13 @@ fn parse_string<'a>(target: &'a str, key: &'a str) -> Option<&'a str> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Todo: log
|
/// fetch and parse the profile
|
||||||
/// Import the Profile from url
|
pub async fn fetch_profile(url: &str) -> Option<ProfileResponse> {
|
||||||
/// save to the `verge.yaml` file
|
let resp = match reqwest::get(url).await {
|
||||||
pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
|
Ok(res) => res,
|
||||||
let resp = reqwest::get(profile_url).await?;
|
Err(_) => return None,
|
||||||
let header = resp.headers().clone();
|
};
|
||||||
|
let header = resp.headers();
|
||||||
|
|
||||||
// parse the Subscription Userinfo
|
// parse the Subscription Userinfo
|
||||||
let extra = {
|
let extra = {
|
||||||
@ -56,60 +52,34 @@ pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// parse the file name
|
// parse the `name` and `file`
|
||||||
let file_name = {
|
let (name, file) = {
|
||||||
let file_name = header.get("Content-Disposition").unwrap().to_str().unwrap();
|
let now = SystemTime::now()
|
||||||
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)
|
.duration_since(UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs();
|
.as_secs();
|
||||||
format!("{}.yaml", cur_time)
|
let file = format!("{}.yaml", now);
|
||||||
}
|
let name = header.get("Content-Disposition").unwrap().to_str().unwrap();
|
||||||
|
let name = parse_string(name, "filename=");
|
||||||
|
|
||||||
|
match name {
|
||||||
|
Some(f) => (f.to_string(), file),
|
||||||
|
None => (file.clone(), file),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// save file
|
// get the data
|
||||||
let file_data = resp.text_with_charset("utf-8").await?;
|
let data = match resp.text_with_charset("utf-8").await {
|
||||||
let file_path = app_home_dir().join("profiles").join(&file_name);
|
Ok(d) => d,
|
||||||
File::create(file_path)
|
Err(_) => return None,
|
||||||
.unwrap()
|
|
||||||
.write(file_data.as_bytes())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// update profiles.yaml
|
|
||||||
let mut profiles = read_profiles();
|
|
||||||
let mut items = match profiles.items {
|
|
||||||
Some(p) => p,
|
|
||||||
None => vec![],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let profile = ProfileItem {
|
Some(ProfileResponse {
|
||||||
name: Some(file_name.clone()),
|
file,
|
||||||
file: Some(file_name.clone()),
|
name,
|
||||||
mode: Some(String::from("rule")),
|
data,
|
||||||
url: Some(String::from(profile_url)),
|
extra,
|
||||||
selected: Some(vec![]),
|
})
|
||||||
extra: Some(extra),
|
|
||||||
};
|
|
||||||
|
|
||||||
let target_index = items
|
|
||||||
.iter()
|
|
||||||
.position(|x| x.name.is_some() && x.name.as_ref().unwrap().as_str() == file_name.as_str());
|
|
||||||
|
|
||||||
match target_index {
|
|
||||||
Some(idx) => items[idx] = profile,
|
|
||||||
None => items.push(profile),
|
|
||||||
};
|
|
||||||
|
|
||||||
profiles.items = Some(items);
|
|
||||||
save_profiles(&profiles);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
@ -2,6 +2,6 @@ mod dirs;
|
|||||||
pub use self::dirs::*;
|
pub use self::dirs::*;
|
||||||
|
|
||||||
pub mod clash;
|
pub mod clash;
|
||||||
pub mod import;
|
pub mod fetch;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod sysopt;
|
pub mod sysopt;
|
||||||
|
Loading…
Reference in New Issue
Block a user