diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 98765ec..41d9719 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -10,7 +10,7 @@ mod config; mod events; mod utils; -use crate::events::state::ClashInfoState; +use crate::{events::state::ClashInfoState, utils::clash::put_clash_profile}; use std::sync::{Arc, Mutex}; use tauri::{ api, CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, @@ -68,6 +68,15 @@ fn main() -> std::io::Result<()> { utils::init::init_app(app.package_info()); // run clash sidecar let info = utils::clash::run_clash_bin(&app.handle()); + // update the profile + let info_copy = info.clone(); + tauri::async_runtime::spawn(async move { + match put_clash_profile(&info_copy).await { + Ok(_) => {} + Err(err) => log::error!("failed to put config for `{}`", err), + }; + }); + app.manage(ClashInfoState(Arc::new(Mutex::new(info)))); app.run(|app_handle, e| match e { diff --git a/src-tauri/src/utils/clash.rs b/src-tauri/src/utils/clash.rs index 9d2c46d..d562e34 100644 --- a/src-tauri/src/utils/clash.rs +++ b/src-tauri/src/utils/clash.rs @@ -1,10 +1,12 @@ extern crate log; use crate::{ - config::read_clash_controller, + config::{read_clash_controller, read_profiles}, events::emit::{clash_start, ClashInfoPayload}, utils::app_home_dir, }; +use reqwest::header::HeaderMap; +use std::{collections::HashMap, env::temp_dir, fs}; use tauri::{ api::process::{Command, CommandEvent}, AppHandle, @@ -58,6 +60,59 @@ pub fn run_clash_bin(app_handle: &AppHandle) -> ClashInfoPayload { }; clash_start(app_handle, &payload); - payload } + +/// Update the clash profile firstly +pub async fn put_clash_profile(payload: &ClashInfoPayload) -> Result<(), String> { + let profile = { + let profiles = read_profiles(); + let current = profiles.current.unwrap_or(0u32) as usize; + match profiles.items { + Some(items) => { + if items.len() == 0 { + return Err("can not read profiles".to_string()); + } + let idx = if current < items.len() { current } else { 0 }; + items[idx].clone() + } + None => { + return Err("can not read profiles".to_string()); + } + } + }; + + // generate temp profile + let file_name = match profile.file { + Some(file_name) => file_name.clone(), + None => { + return Err("the profile item should have `file` field".to_string()); + } + }; + + let file_path = app_home_dir().join("profiles").join(file_name); + let temp_path = temp_dir().join("clash-verge-runtime.yaml"); + + if !file_path.exists() { + return Err(format!("the profile `{:?}` not exists", file_path)); + } + fs::copy(file_path, temp_path.clone()).unwrap(); + + let server = payload.controller.clone().unwrap().server.unwrap(); + let server = format!("http://{}/configs", server); + + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", "application/json".parse().unwrap()); + + let mut data = HashMap::new(); + data.insert("path", temp_path.as_os_str().to_str().unwrap()); + + let client = reqwest::Client::new(); + match client.put(server).headers(headers).json(&data).send().await { + Ok(_) => Ok(()), + Err(err) => Err(format!( + "request failed with status `{}`", + err.status().unwrap() + )), + } +}