diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs new file mode 100644 index 0000000..602b9f1 --- /dev/null +++ b/src-tauri/src/cmds.rs @@ -0,0 +1,238 @@ +use crate::{ + config::{ClashInfo, ProfileItem, ProfilesConfig, VergeConfig}, + states::{ClashState, ProfilesState, VergeState}, + utils::{ + config::{read_clash, save_clash}, + fetch::fetch_profile, + sysopt::SysProxyConfig, + }, +}; +use serde_yaml::Mapping; +use tauri::State; + +/// get all profiles from `profiles.yaml` +/// do not acquire the lock of ProfileLock +#[tauri::command] +pub fn get_profiles(profiles: State<'_, ProfilesState>) -> Result { + match profiles.0.lock() { + Ok(profiles) => Ok(profiles.clone()), + Err(_) => Err("failed to get profiles lock".into()), + } +} + +/// synchronize data irregularly +#[tauri::command] +pub fn sync_profiles(profiles: State<'_, ProfilesState>) -> Result<(), String> { + match profiles.0.lock() { + Ok(mut profiles) => profiles.sync_file(), + Err(_) => Err("failed to get profiles lock".into()), + } +} + +/// Import the profile from url +/// and save to `profiles.yaml` +#[tauri::command] +pub async fn import_profile(url: String, profiles: State<'_, ProfilesState>) -> Result<(), String> { + match fetch_profile(&url).await { + Some(result) => { + let mut profiles = profiles.0.lock().unwrap(); + profiles.import_from_url(url, result) + } + None => Err(format!("failed to fetch profile from `{}`", url)), + } +} + +/// Update the profile +/// and save to `profiles.yaml` +/// http request firstly +/// then acquire the lock of `profiles.yaml` +#[tauri::command] +pub async fn update_profile( + index: usize, + clash: State<'_, ClashState>, + profiles: State<'_, ProfilesState>, +) -> Result<(), String> { + // maybe we can get the url from the web app directly + let url = match profiles.0.lock() { + Ok(mut profile) => { + let items = profile.items.take().unwrap_or(vec![]); + if index >= items.len() { + return Err("the index out of bound".into()); + } + let url = match &items[index].url { + Some(u) => u.clone(), + None => return Err("failed to update profile for `invalid url`".into()), + }; + profile.items = Some(items); + url + } + Err(_) => return Err("failed to get profiles lock".into()), + }; + + match fetch_profile(&url).await { + Some(result) => match profiles.0.lock() { + Ok(mut profiles) => { + profiles.update_item(index, result)?; + + // reactivate the profile + let current = profiles.current.clone().unwrap_or(0); + if current == index { + let clash = clash.0.lock().unwrap(); + profiles.activate(clash.info.clone()) + } else { + Ok(()) + } + } + Err(_) => Err("failed to get profiles lock".into()), + }, + None => Err(format!("failed to fetch profile from `{}`", url)), + } +} + +/// change the current profile +#[tauri::command] +pub fn select_profile( + index: usize, + clash: State<'_, ClashState>, + profiles: State<'_, ProfilesState>, +) -> Result<(), String> { + let mut profiles = profiles.0.lock().unwrap(); + + match profiles.put_current(index) { + Ok(()) => { + let clash = clash.0.lock().unwrap(); + profiles.activate(clash.info.clone()) + } + Err(err) => Err(err), + } +} + +/// todo: need to check +/// delete profile item +#[tauri::command] +pub fn delete_profile(index: usize, profiles: State<'_, ProfilesState>) -> Result<(), String> { + match profiles.0.lock() { + Ok(mut profiles) => profiles.delete_item(index), + Err(_) => Err("can not get profiles lock".into()), + } +} + +/// patch the profile config +#[tauri::command] +pub fn patch_profile( + index: usize, + profile: ProfileItem, + profiles: State<'_, ProfilesState>, +) -> Result<(), String> { + match profiles.0.lock() { + Ok(mut profiles) => profiles.patch_item(index, profile), + Err(_) => Err("can not get profiles lock".into()), + } +} + +/// restart the sidecar +#[tauri::command] +pub fn restart_sidecar(clash_state: State<'_, ClashState>) { + let mut clash_arc = clash_state.0.lock().unwrap(); + if let Err(err) = clash_arc.restart_sidecar() { + log::error!("{}", err); + } +} + +/// get the clash core info from the state +/// the caller can also get the infomation by clash's api +#[tauri::command] +pub fn get_clash_info(clash_state: State<'_, ClashState>) -> Result { + match clash_state.0.lock() { + Ok(arc) => Ok(arc.info.clone()), + Err(_) => Err("failed to get clash lock".into()), + } +} + +/// todo: need refactor +/// update the clash core config +/// after putting the change to the clash core +/// then we should save the latest config +#[tauri::command] +pub fn patch_clash_config(payload: Mapping) -> Result<(), String> { + let mut config = read_clash(); + for (key, value) in payload.iter() { + if config.contains_key(key) { + config[key] = value.clone(); + } else { + config.insert(key.clone(), value.clone()); + } + } + save_clash(&config) +} + +/// set the system proxy +/// Tips: only support windows now +#[tauri::command] +pub fn set_sys_proxy(enable: bool, verge_state: State<'_, VergeState>) -> Result<(), String> { + let mut verge = verge_state.0.lock().unwrap(); + + if let Some(mut sysproxy) = verge.cur_sysproxy.take() { + sysproxy.enable = enable; + if sysproxy.set_sys().is_err() { + log::error!("failed to set system proxy"); + } + verge.cur_sysproxy = Some(sysproxy); + } + Ok(()) +} + +/// get the system proxy +/// Tips: only support windows now +#[tauri::command] +pub fn get_sys_proxy() -> Result { + match SysProxyConfig::get_sys() { + Ok(value) => Ok(value), + Err(err) => Err(err.to_string()), + } +} + +#[tauri::command] +pub fn get_cur_proxy(verge_state: State<'_, VergeState>) -> Result, String> { + match verge_state.0.lock() { + Ok(verge) => Ok(verge.cur_sysproxy.clone()), + Err(_) => Err("failed to get verge lock".into()), + } +} + +/// get the verge config +#[tauri::command] +pub fn get_verge_config(verge_state: State<'_, VergeState>) -> Result { + match verge_state.0.lock() { + Ok(arc) => Ok(arc.config.clone()), + Err(_) => Err("failed to get verge lock".into()), + } +} + +/// patch the verge config +/// this command only save the config and not responsible for other things +#[tauri::command] +pub async fn patch_verge_config( + payload: VergeConfig, + verge_state: State<'_, VergeState>, +) -> Result<(), String> { + let mut verge = verge_state.0.lock().unwrap(); + + if payload.theme_mode.is_some() { + verge.config.theme_mode = payload.theme_mode; + } + + if payload.enable_self_startup.is_some() { + verge.config.enable_self_startup = payload.enable_self_startup; + } + + if payload.enable_system_proxy.is_some() { + verge.config.enable_system_proxy = payload.enable_system_proxy; + } + + if payload.system_proxy_bypass.is_some() { + verge.config.system_proxy_bypass = payload.system_proxy_bypass; + } + + verge.config.save_file() +} diff --git a/src-tauri/src/cmds/mod.rs b/src-tauri/src/cmds/mod.rs deleted file mode 100644 index c5be45b..0000000 --- a/src-tauri/src/cmds/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod profile; -pub mod some; diff --git a/src-tauri/src/cmds/profile.rs b/src-tauri/src/cmds/profile.rs deleted file mode 100644 index 576805c..0000000 --- a/src-tauri/src/cmds/profile.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::{ - config::{ProfileItem, ProfilesConfig}, - events::state::{ClashInfoState, ProfilesState}, - utils::{clash, fetch}, -}; -use tauri::State; - -/// get all profiles from `profiles.yaml` -/// do not acquire the lock of ProfileLock -#[tauri::command] -pub fn get_profiles(profiles: State<'_, ProfilesState>) -> Result { - match profiles.0.lock() { - Ok(profiles) => Ok(profiles.clone()), - Err(_) => Err("can not get profiles lock".into()), - } -} - -/// synchronize data irregularly -#[tauri::command] -pub fn sync_profiles(profiles: State<'_, ProfilesState>) -> Result<(), String> { - match profiles.0.lock() { - Ok(mut profiles) => profiles.sync_file(), - Err(_) => Err("can not get profiles lock".into()), - } -} - -/// Import the profile from url -/// and save to `profiles.yaml` -#[tauri::command] -pub async fn import_profile(url: String, profiles: State<'_, ProfilesState>) -> Result<(), String> { - let result = match fetch::fetch_profile(&url).await { - Some(r) => r, - None => return Err(format!("failed to fetch profile from `{}`", url)), - }; - - match profiles.0.lock() { - Ok(mut profiles) => profiles.import_from_url(url, result), - Err(_) => Err("can not get profiles lock".into()), - } -} - -/// Update the profile -/// and save to `profiles.yaml` -/// http request firstly -/// then acquire the lock of `profiles.yaml` -#[tauri::command] -pub async fn update_profile( - index: usize, - profiles: State<'_, ProfilesState>, -) -> Result<(), String> { - // maybe we can get the url from the web app directly - let url = { - match profiles.0.lock() { - Ok(mut profile) => { - let items = profile.items.take().unwrap_or(vec![]); - if index >= items.len() { - return Err("the index out of bound".into()); - } - let url = match &items[index].url { - Some(u) => u.clone(), - None => return Err("failed to update profile for `invalid url`".into()), - }; - profile.items = Some(items); - url - } - Err(_) => return Err("can not get profiles lock".into()), - } - }; - - let result = match fetch::fetch_profile(&url).await { - Some(r) => r, - None => return Err(format!("failed to fetch profile from `{}`", url)), - }; - - match profiles.0.lock() { - Ok(mut profiles) => profiles.update_item(index, result), - Err(_) => Err("can not get profiles lock".into()), - } -} - -/// change the current profile -#[tauri::command] -pub async fn select_profile( - index: usize, - profiles: State<'_, ProfilesState>, - clash_info: State<'_, ClashInfoState>, -) -> Result<(), String> { - match profiles.0.lock() { - Ok(mut profiles) => profiles.put_current(index)?, - Err(_) => return Err("can not get profiles lock".into()), - }; - - let arc = match clash_info.0.lock() { - Ok(arc) => arc.clone(), - _ => return Err("can not get clash info lock".into()), - }; - - clash::put_clash_profile(&arc).await -} - -/// delete profile item -#[tauri::command] -pub fn delete_profile(index: usize, profiles: State<'_, ProfilesState>) -> Result<(), String> { - match profiles.0.lock() { - Ok(mut profiles) => profiles.delete_item(index), - Err(_) => Err("can not get profiles lock".into()), - } -} - -/// patch the profile config -#[tauri::command] -pub fn patch_profile( - index: usize, - profile: ProfileItem, - profiles: State<'_, ProfilesState>, -) -> Result<(), String> { - match profiles.0.lock() { - Ok(mut profiles) => profiles.patch_item(index, profile), - Err(_) => Err("can not get profiles lock".into()), - } -} diff --git a/src-tauri/src/cmds/some.rs b/src-tauri/src/cmds/some.rs deleted file mode 100644 index 44a89dc..0000000 --- a/src-tauri/src/cmds/some.rs +++ /dev/null @@ -1,166 +0,0 @@ -use crate::{ - config::VergeConfig, - events::{ - emit::ClashInfoPayload, - state::{ClashInfoState, ClashSidecarState, VergeConfLock}, - }, - utils::{ - clash::run_clash_bin, - config::{read_clash, save_clash, save_verge}, - sysopt::{get_proxy_config, set_proxy_config, SysProxyConfig, DEFAULT_BYPASS}, - }, -}; -use serde_yaml::Mapping; -use tauri::{AppHandle, State}; - -/// restart the sidecar -#[tauri::command] -pub fn restart_sidecar( - app_handle: AppHandle, - clash_info: State<'_, ClashInfoState>, - clash_sidecar: State<'_, ClashSidecarState>, -) { - { - let mut guard = clash_sidecar.0.lock().unwrap(); - let sidecar = guard.take(); - if sidecar.is_some() { - if let Err(err) = sidecar.unwrap().kill() { - log::error!("failed to restart clash for \"{}\"", err); - } - } - } - let payload = run_clash_bin(&app_handle); - - if let Ok(mut arc) = clash_info.0.lock() { - *arc = payload; - } -} - -/// get the clash core info from the state -/// the caller can also get the infomation by clash's api -#[tauri::command] -pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Result { - match clash_info.0.lock() { - Ok(arc) => Ok(arc.clone()), - Err(_) => Err(format!("can not get clash info")), - } -} - -/// update the clash core config -/// after putting the change to the clash core -/// then we should save the latest config -#[tauri::command] -pub fn patch_clash_config(payload: Mapping) -> Result<(), String> { - let mut config = read_clash(); - for (key, value) in payload.iter() { - if config.contains_key(key) { - config[key] = value.clone(); - } else { - config.insert(key.clone(), value.clone()); - } - } - save_clash(&config) -} - -/// set the system proxy -/// Tips: only support windows now -#[tauri::command] -pub fn set_sys_proxy( - enable: bool, - clash_info: State<'_, ClashInfoState>, - verge_lock: State<'_, VergeConfLock>, -) -> Result<(), String> { - let clash_info = match clash_info.0.lock() { - Ok(arc) => arc.clone(), - _ => return Err(format!("can not get clash info")), - }; - - let verge_info = match verge_lock.0.lock() { - Ok(arc) => arc.clone(), - _ => return Err(format!("can not get verge info")), - }; - - let port = match clash_info.controller { - Some(ctrl) => ctrl.port, - None => None, - }; - - if port.is_none() { - return Err(format!("can not get clash core's port")); - } - - let config = if enable { - let server = format!("127.0.0.1:{}", port.unwrap()); - let bypass = verge_info - .system_proxy_bypass - .unwrap_or(String::from(DEFAULT_BYPASS)); - SysProxyConfig { - enable, - server, - bypass, - } - } else { - SysProxyConfig { - enable, - server: String::from(""), - bypass: String::from(""), - } - }; - - match set_proxy_config(&config) { - Ok(_) => Ok(()), - Err(_) => Err(format!("can not set proxy")), - } -} - -/// get the system proxy -/// Tips: only support windows now -#[tauri::command] -pub fn get_sys_proxy() -> Result { - match get_proxy_config() { - Ok(value) => Ok(value), - Err(err) => Err(err.to_string()), - } -} - -/// get the verge config -#[tauri::command] -pub fn get_verge_config(verge_lock: State<'_, VergeConfLock>) -> Result { - match verge_lock.0.lock() { - Ok(arc) => Ok(arc.clone()), - Err(_) => Err(format!("can not get the lock")), - } -} - -/// patch the verge config -/// this command only save the config and not responsible for other things -#[tauri::command] -pub async fn patch_verge_config( - payload: VergeConfig, - verge_lock: State<'_, VergeConfLock>, -) -> Result<(), String> { - let mut verge = match verge_lock.0.lock() { - Ok(v) => v, - Err(_) => return Err(format!("can not get the lock")), - }; - - if payload.theme_mode.is_some() { - verge.theme_mode = payload.theme_mode; - } - - // todo - if payload.enable_self_startup.is_some() { - verge.enable_self_startup = payload.enable_self_startup; - } - - // todo - if payload.enable_system_proxy.is_some() { - verge.enable_system_proxy = payload.enable_system_proxy; - } - - if payload.system_proxy_bypass.is_some() { - verge.system_proxy_bypass = payload.system_proxy_bypass; - } - - save_verge(&verge) -} diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index 245b846..3ecf76a 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -1,30 +1,147 @@ +use crate::utils::{config, dirs}; use serde::{Deserialize, Serialize}; - -/// ### `config.yaml` schema -/// here should contain all configuration options. -/// See: https://github.com/Dreamacro/clash/wiki/configuration for details -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -pub struct ClashConfig { - pub port: Option, - - /// alias to `mixed-port` - pub mixed_port: Option, - - /// alias to `allow-lan` - pub allow_lan: Option, - - /// alias to `external-controller` - pub external_ctrl: Option, - - pub secret: Option, -} +use serde_yaml::{Mapping, Value}; +use tauri::api::process::{Command, CommandChild, CommandEvent}; #[derive(Default, Debug, Clone, Deserialize, Serialize)] -pub struct ClashController { +pub struct ClashInfo { + /// clash sidecar status + pub status: String, + /// clash core port pub port: Option, /// same as `external-controller` pub server: Option, + + /// clash secret pub secret: Option, } + +#[derive(Debug)] +pub struct Clash { + /// some info + pub info: ClashInfo, + + /// clash sidecar + pub sidecar: Option, +} + +static CLASH_CONFIG: &str = "config.yaml"; + +// todo: be able to change config field +impl Clash { + pub fn new() -> Clash { + let clash_config = config::read_yaml::(dirs::app_home_dir().join(CLASH_CONFIG)); + + let key_port_1 = Value::String("port".to_string()); + let key_port_2 = Value::String("mixed-port".to_string()); + let key_server = Value::String("external-controller".to_string()); + let key_secret = Value::String("secret".to_string()); + + let port = match clash_config.get(&key_port_1) { + Some(value) => match value { + Value::String(val_str) => Some(val_str.clone()), + Value::Number(val_num) => Some(val_num.to_string()), + _ => None, + }, + _ => None, + }; + let port = match port { + Some(_) => port, + None => match clash_config.get(&key_port_2) { + Some(value) => match value { + Value::String(val_str) => Some(val_str.clone()), + Value::Number(val_num) => Some(val_num.to_string()), + _ => None, + }, + _ => None, + }, + }; + + let server = match clash_config.get(&key_server) { + Some(value) => match value { + Value::String(val_str) => Some(val_str.clone()), + _ => None, + }, + _ => None, + }; + let secret = match clash_config.get(&key_secret) { + Some(value) => match value { + Value::String(val_str) => Some(val_str.clone()), + Value::Bool(val_bool) => Some(val_bool.to_string()), + Value::Number(val_num) => Some(val_num.to_string()), + _ => None, + }, + _ => None, + }; + + Clash { + info: ClashInfo { + status: "init".into(), + port, + server, + secret, + }, + sidecar: None, + } + } + + /// run clash sidecar + pub fn run_sidecar(&mut self) -> Result<(), String> { + let app_dir = dirs::app_home_dir(); + let app_dir = app_dir.as_os_str().to_str().unwrap(); + + match Command::new_sidecar("clash") { + Ok(cmd) => match cmd.args(["-d", app_dir]).spawn() { + Ok((mut rx, cmd_child)) => { + self.sidecar = Some(cmd_child); + + // clash log + tauri::async_runtime::spawn(async move { + while let Some(event) = rx.recv().await { + match event { + CommandEvent::Stdout(line) => log::info!("[stdout]: {}", line), + CommandEvent::Stderr(err) => log::error!("[stderr]: {}", err), + _ => {} + } + } + }); + Ok(()) + } + Err(err) => Err(err.to_string()), + }, + Err(err) => Err(err.to_string()), + } + } + + /// drop clash sidecar + pub fn drop_sidecar(&mut self) -> Result<(), String> { + if let Some(sidecar) = self.sidecar.take() { + if let Err(err) = sidecar.kill() { + return Err(format!("failed to drop clash for \"{}\"", err)); + } + } + Ok(()) + } + + /// restart clash sidecar + pub fn restart_sidecar(&mut self) -> Result<(), String> { + self.drop_sidecar()?; + self.run_sidecar() + } +} + +impl Default for Clash { + fn default() -> Self { + Clash::new() + } +} + +impl Drop for Clash { + fn drop(&mut self) { + if let Err(err) = self.drop_sidecar() { + log::error!("{}", err); + } + } +} diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index 878590b..a493d2f 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -1,9 +1,15 @@ -use crate::utils::{app_home_dir, config}; +use crate::utils::{config, dirs}; +use reqwest::header::HeaderMap; use serde::{Deserialize, Serialize}; +use serde_yaml::{Mapping, Value}; +use std::collections::HashMap; +use std::env::temp_dir; use std::fs::File; use std::io::Write; use std::time::{SystemTime, UNIX_EPOCH}; +use super::ClashInfo; + /// Define the `profiles.yaml` schema #[derive(Default, Debug, Clone, Deserialize, Serialize)] pub struct ProfilesConfig { @@ -56,17 +62,18 @@ pub struct ProfileResponse { } static PROFILE_YAML: &str = "profiles.yaml"; +static PROFILE_TEMP: &str = "clash-verge-runtime.yaml"; impl ProfilesConfig { /// read the config from the file pub fn read_file() -> Self { - config::read_yaml::(app_home_dir().join(PROFILE_YAML)) + config::read_yaml::(dirs::app_home_dir().join(PROFILE_YAML)) } /// save the config to the file pub fn save_file(&self) -> Result<(), String> { config::save_yaml( - app_home_dir().join(PROFILE_YAML), + dirs::app_home_dir().join(PROFILE_YAML), self, Some("# Profiles Config for Clash Verge\n\n"), ) @@ -74,7 +81,7 @@ impl ProfilesConfig { /// sync the config between file and memory pub fn sync_file(&mut self) -> Result<(), String> { - let data = config::read_yaml::(app_home_dir().join(PROFILE_YAML)); + let data = config::read_yaml::(dirs::app_home_dir().join(PROFILE_YAML)); if data.current.is_none() { Err("failed to read profiles.yaml".into()) } else { @@ -88,7 +95,7 @@ impl ProfilesConfig { /// and update the config file pub fn import_from_url(&mut self, url: String, result: ProfileResponse) -> Result<(), String> { // save the profile file - let path = app_home_dir().join("profiles").join(&result.file); + let path = dirs::app_home_dir().join("profiles").join(&result.file); let file_data = result.data.as_bytes(); File::create(path).unwrap().write(file_data).unwrap(); @@ -145,7 +152,7 @@ impl ProfilesConfig { // update file let file_path = &items[index].file.as_ref().unwrap(); - let file_path = app_home_dir().join("profiles").join(file_path); + let file_path = dirs::app_home_dir().join("profiles").join(file_path); let file_data = result.data.as_bytes(); File::create(file_path).unwrap().write(file_data).unwrap(); @@ -206,4 +213,99 @@ impl ProfilesConfig { self.current = Some(current); self.save_file() } + + /// activate current profile + pub fn activate(&self, clash_config: ClashInfo) -> Result<(), String> { + let current = self.current.unwrap_or(0); + match self.items.clone() { + Some(items) => { + if current >= items.len() { + return Err("the index out of bound".into()); + } + + let profile = items[current].clone(); + tauri::async_runtime::spawn(async move { + let mut count = 5; // retry times + let mut err = String::from(""); + while count > 0 { + match activate_profile(&profile, &clash_config).await { + Ok(_) => return, + Err(e) => err = e, + } + count -= 1; + } + log::error!("failed to activate for `{}`", err); + }); + + Ok(()) + } + None => Err("empty profiles".into()), + } + } +} + +/// put the profile to clash +pub async fn activate_profile(profile_item: &ProfileItem, info: &ClashInfo) -> Result<(), String> { + // temp profile's path + let temp_path = temp_dir().join(PROFILE_TEMP); + + // generate temp profile + { + let file_name = match profile_item.file.clone() { + Some(file_name) => file_name, + None => return Err("profile item should have `file` field".into()), + }; + + let file_path = dirs::app_home_dir().join("profiles").join(file_name); + if !file_path.exists() { + return Err(format!("profile `{:?}` not exists", file_path)); + } + + // Only the following fields are allowed: + // proxies/proxy-providers/proxy-groups/rule-providers/rules + let config = config::read_yaml::(file_path.clone()); + let mut new_config = Mapping::new(); + vec![ + "proxies", + "proxy-providers", + "proxy-groups", + "rule-providers", + "rules", + ] + .iter() + .map(|item| Value::String(item.to_string())) + .for_each(|key| { + if config.contains_key(&key) { + let value = config[&key].clone(); + new_config.insert(key, value); + } + }); + + config::save_yaml( + temp_path.clone(), + &new_config, + Some("# Clash Verge Temp File"), + )? + }; + + let server = format!("http://{}/configs", info.server.clone().unwrap()); + + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", "application/json".parse().unwrap()); + + if let Some(secret) = info.secret.clone() { + headers.insert( + "Authorization", + format!("Bearer {}", secret).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 `{}`", err.to_string())), + } } diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index e322185..751d05b 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -1,3 +1,4 @@ +use crate::utils::{config, dirs, sysopt::SysProxyConfig}; use serde::{Deserialize, Serialize}; /// ### `verge.yaml` schema @@ -15,3 +16,78 @@ pub struct VergeConfig { /// set system proxy bypass pub system_proxy_bypass: Option, } + +static VERGE_CONFIG: &str = "verge.yaml"; + +impl VergeConfig { + pub fn new() -> Self { + config::read_yaml::(dirs::app_home_dir().join(VERGE_CONFIG)) + } + + /// Save Verge App Config + pub fn save_file(&self) -> Result<(), String> { + config::save_yaml( + dirs::app_home_dir().join(VERGE_CONFIG), + self, + Some("# The Config for Clash Verge App\n\n"), + ) + } +} + +#[derive(Debug)] +pub struct Verge { + pub config: VergeConfig, + + pub old_sysproxy: Option, + + pub cur_sysproxy: Option, +} + +impl Default for Verge { + fn default() -> Self { + Verge::new() + } +} + +impl Verge { + pub fn new() -> Self { + Verge { + config: VergeConfig::new(), + old_sysproxy: None, + cur_sysproxy: None, + } + } + + /// init the sysproxy + pub fn init_sysproxy(&mut self, port: Option) { + if let Some(port) = port { + let enable = self.config.enable_system_proxy.clone().unwrap_or(false); + + self.old_sysproxy = match SysProxyConfig::get_sys() { + Ok(proxy) => Some(proxy), + Err(_) => None, + }; + + let bypass = self.config.system_proxy_bypass.clone(); + let sysproxy = SysProxyConfig::new(enable, port, bypass); + + if enable { + if sysproxy.set_sys().is_err() { + log::error!("failed to set system proxy"); + } + } + + self.cur_sysproxy = Some(sysproxy); + } + } + + /// reset the sysproxy + pub fn reset_sysproxy(&mut self) { + if let Some(sysproxy) = self.old_sysproxy.take() { + match sysproxy.set_sys() { + Ok(_) => self.cur_sysproxy = None, + Err(_) => log::error!("failed to reset proxy for"), + } + } + } +} diff --git a/src-tauri/src/events/emit.rs b/src-tauri/src/events/emit.rs deleted file mode 100644 index 029cc35..0000000 --- a/src-tauri/src/events/emit.rs +++ /dev/null @@ -1,26 +0,0 @@ -use serde::{Deserialize, Serialize}; -use tauri::{AppHandle, Manager}; - -use crate::config::ClashController; - -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -pub struct ClashInfoPayload { - /// value between `success` and `error` - pub status: String, - - /// the clash core's external controller infomation - pub controller: Option, - - /// some message - pub message: Option, -} - -/// emit `clash_runtime` to the main windows -pub fn clash_start(app_handle: &AppHandle, payload: &ClashInfoPayload) { - match app_handle.get_window("main") { - Some(main_win) => { - main_win.emit("clash_start", payload).unwrap(); - } - _ => {} - }; -} diff --git a/src-tauri/src/events/mod.rs b/src-tauri/src/events/mod.rs deleted file mode 100644 index c382b2f..0000000 --- a/src-tauri/src/events/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod emit; -pub mod state; diff --git a/src-tauri/src/events/state.rs b/src-tauri/src/events/state.rs deleted file mode 100644 index cfda63b..0000000 --- a/src-tauri/src/events/state.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::emit::ClashInfoPayload; -use crate::{ - config::{ProfilesConfig, VergeConfig}, - utils::sysopt::SysProxyConfig, -}; -use std::sync::{Arc, Mutex}; -use tauri::api::process::CommandChild; - -#[derive(Default)] -pub struct ClashInfoState(pub Arc>); - -#[derive(Default)] -pub struct ProfilesState(pub Arc>); - -#[derive(Default)] -pub struct VergeConfLock(pub Arc>); - -#[derive(Default)] -pub struct SomthingState(pub Arc>>); - -#[derive(Default)] -pub struct ClashSidecarState(pub Arc>>); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index debbe79..6338971 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,13 +7,10 @@ extern crate tauri; mod cmds; mod config; -mod events; +mod states; mod utils; -use crate::{ - events::state, - utils::{clash, resolve, server}, -}; +use crate::utils::{resolve, server}; use tauri::{ api, CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, }; @@ -31,11 +28,9 @@ fn main() -> std::io::Result<()> { .add_item(CustomMenuItem::new("quit", "退出").accelerator("CmdOrControl+Q")); tauri::Builder::default() - .manage(state::ClashSidecarState::default()) - .manage(state::VergeConfLock::default()) - .manage(state::ClashInfoState::default()) - .manage(state::SomthingState::default()) - .manage(state::ProfilesState::default()) + .manage(states::VergeState::default()) + .manage(states::ClashState::default()) + .manage(states::ProfilesState::default()) .setup(|app| Ok(resolve::resolve_setup(app))) .system_tray(SystemTray::new().with_menu(menu)) .on_system_tray_event(move |app_handle, event| match event { @@ -46,22 +41,11 @@ fn main() -> std::io::Result<()> { window.set_focus().unwrap(); } "restart_clash" => { - { - let state = app_handle.state::(); - let mut guard = state.0.lock().unwrap(); - let sidecar = guard.take(); - if sidecar.is_some() { - if let Err(err) = sidecar.unwrap().kill() { - log::error!("failed to restart clash for \"{}\"", err); - } - } + let clash_state = app_handle.state::(); + let mut clash_arc = clash_state.0.lock().unwrap(); + if let Err(err) = clash_arc.restart_sidecar() { + log::error!("{}", err); } - - let payload = clash::run_clash_bin(&app_handle); - let state = app_handle.state::(); - if let Ok(mut arc) = state.0.lock() { - *arc = payload; - }; } "quit" => { api::process::kill_children(); @@ -78,20 +62,21 @@ fn main() -> std::io::Result<()> { _ => {} }) .invoke_handler(tauri::generate_handler![ - cmds::some::restart_sidecar, - cmds::some::set_sys_proxy, - cmds::some::get_sys_proxy, - cmds::some::get_clash_info, - cmds::some::patch_clash_config, - cmds::some::get_verge_config, - cmds::some::patch_verge_config, - cmds::profile::import_profile, - cmds::profile::update_profile, - cmds::profile::delete_profile, - cmds::profile::select_profile, - cmds::profile::patch_profile, - cmds::profile::sync_profiles, - cmds::profile::get_profiles, + cmds::restart_sidecar, + cmds::set_sys_proxy, + cmds::get_sys_proxy, + cmds::get_cur_proxy, + cmds::get_clash_info, + cmds::patch_clash_config, + cmds::get_verge_config, + cmds::patch_verge_config, + cmds::import_profile, + cmds::update_profile, + cmds::delete_profile, + cmds::select_profile, + cmds::patch_profile, + cmds::sync_profiles, + cmds::get_profiles, ]) .build(tauri::generate_context!()) .expect("error while running tauri application") diff --git a/src-tauri/src/states.rs b/src-tauri/src/states.rs new file mode 100644 index 0000000..3f9941b --- /dev/null +++ b/src-tauri/src/states.rs @@ -0,0 +1,11 @@ +use crate::config::{Clash, ProfilesConfig, Verge}; +use std::sync::{Arc, Mutex}; + +#[derive(Default)] +pub struct ProfilesState(pub Arc>); + +#[derive(Default)] +pub struct ClashState(pub Arc>); + +#[derive(Default)] +pub struct VergeState(pub Arc>); diff --git a/src-tauri/src/utils/clash.rs b/src-tauri/src/utils/clash.rs deleted file mode 100644 index 33e5cb4..0000000 --- a/src-tauri/src/utils/clash.rs +++ /dev/null @@ -1,168 +0,0 @@ -extern crate log; - -use crate::{ - config::ProfilesConfig, - events::{ - emit::{clash_start, ClashInfoPayload}, - state, - }, - utils::{app_home_dir, clash, config}, -}; -use reqwest::header::HeaderMap; -use serde_yaml::{Mapping, Value}; -use std::{collections::HashMap, env::temp_dir}; -use tauri::{ - api::process::{Command, CommandEvent}, - AppHandle, Manager, -}; - -/// Run the clash bin -pub fn run_clash_bin(app_handle: &AppHandle) -> ClashInfoPayload { - let app_dir = app_home_dir(); - let app_dir = app_dir.as_os_str().to_str().unwrap(); - - let mut payload = ClashInfoPayload { - status: "success".to_string(), - controller: None, - message: None, - }; - - let result = match Command::new_sidecar("clash") { - Ok(cmd) => match cmd.args(["-d", app_dir]).spawn() { - Ok(res) => Ok(res), - Err(err) => Err(err.to_string()), - }, - Err(err) => Err(err.to_string()), - }; - - match result { - Ok((mut rx, cmd_child)) => { - log::info!("Successfully execute clash sidecar"); - payload.controller = Some(config::read_clash_controller()); - - if let Ok(mut state) = app_handle.state::().0.lock() { - *state = Some(cmd_child); - }; - - tauri::async_runtime::spawn(async move { - while let Some(event) = rx.recv().await { - match event { - CommandEvent::Stdout(line) => log::info!("[stdout]: {}", line), - CommandEvent::Stderr(err) => log::error!("[stderr]: {}", err), - _ => {} - } - } - }); - - // update the profile - let payload_ = payload.clone(); - tauri::async_runtime::spawn(async move { - let mut count = 5; // retry times - let mut err = String::from(""); - while count > 0 { - match clash::put_clash_profile(&payload_).await { - Ok(_) => return, - Err(e) => err = e, - } - count -= 1; - } - log::error!("failed to put config for `{}`", err); - }); - } - Err(err) => { - log::error!("Failed to execute clash sidecar for \"{}\"", err); - payload.status = "error".to_string(); - payload.message = Some(err.to_string()); - } - }; - - 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 = ProfilesConfig::read_file(); - let current = profiles.current.unwrap_or(0) 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()); - } - } - }; - - // temp profile's path - let temp_path = temp_dir().join("clash-verge-runtime.yaml"); - - // generate temp profile - { - let file_name = match profile.file { - Some(file_name) => file_name.clone(), - None => return Err(format!("profile item should have `file` field")), - }; - - let file_path = app_home_dir().join("profiles").join(file_name); - if !file_path.exists() { - return Err(format!("profile `{:?}` not exists", file_path)); - } - - // Only the following fields are allowed: - // proxies/proxy-providers/proxy-groups/rule-providers/rules - let config = config::read_yaml::(file_path.clone()); - let mut new_config = Mapping::new(); - vec![ - "proxies", - "proxy-providers", - "proxy-groups", - "rule-providers", - "rules", - ] - .iter() - .map(|item| Value::String(item.to_string())) - .for_each(|key| { - if config.contains_key(&key) { - let value = config[&key].clone(); - new_config.insert(key, value); - } - }); - - match config::save_yaml( - temp_path.clone(), - &new_config, - Some("# Clash Verge Temp File"), - ) { - Err(err) => return Err(err), - _ => {} - }; - } - - let ctrl = payload.controller.clone().unwrap(); - let server = format!("http://{}/configs", ctrl.server.unwrap()); - - let mut headers = HeaderMap::new(); - headers.insert("Content-Type", "application/json".parse().unwrap()); - - if let Some(secret) = ctrl.secret { - headers.insert( - "Authorization", - format!("Bearer {}", secret).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 `{}`", err.to_string())), - } -} diff --git a/src-tauri/src/utils/config.rs b/src-tauri/src/utils/config.rs index 78b8030..4d8e13e 100644 --- a/src-tauri/src/utils/config.rs +++ b/src-tauri/src/utils/config.rs @@ -1,9 +1,6 @@ -use crate::{ - config::{ClashController, VergeConfig}, - utils::app_home_dir, -}; +use crate::utils::dirs; use serde::{de::DeserializeOwned, Serialize}; -use serde_yaml::{Mapping, Value}; +use serde_yaml::Mapping; use std::{fs, path::PathBuf}; /// read data from yaml as struct T @@ -19,100 +16,33 @@ pub fn save_yaml( data: &T, prefix: Option<&str>, ) -> Result<(), String> { - if let Ok(data_str) = serde_yaml::to_string(data) { - let yaml_str = if prefix.is_some() { - prefix.unwrap().to_string() + &data_str - } else { - data_str - }; + match serde_yaml::to_string(data) { + Ok(data_str) => { + let yaml_str = match prefix { + Some(prefix) => format!("{}{}", prefix, data_str), + None => data_str, + }; - if fs::write(path.clone(), yaml_str.as_bytes()).is_err() { - Err(format!("can not save file `{:?}`", path)) - } else { - Ok(()) + let path_str = path.as_os_str().to_string_lossy().to_string(); + match fs::write(path, yaml_str.as_bytes()) { + Ok(_) => Ok(()), + Err(_) => Err(format!("can not save file `{}`", path_str)), + } } - } else { - Err(String::from("can not convert the data to yaml")) + Err(_) => Err("can not convert the data to yaml".into()), } } /// Get Clash Core Config `config.yaml` pub fn read_clash() -> Mapping { - read_yaml::(app_home_dir().join("config.yaml")) + read_yaml::(dirs::app_home_dir().join("config.yaml")) } /// Save the clash core Config `config.yaml` pub fn save_clash(config: &Mapping) -> Result<(), String> { save_yaml( - app_home_dir().join("config.yaml"), + dirs::app_home_dir().join("config.yaml"), config, Some("# Default Config For Clash Core\n\n"), ) } - -/// Get infomation of the clash's `external-controller` and `secret` -pub fn read_clash_controller() -> ClashController { - let config = read_clash(); - - let key_port_1 = Value::String("port".to_string()); - let key_port_2 = Value::String("mixed-port".to_string()); - let key_server = Value::String("external-controller".to_string()); - let key_secret = Value::String("secret".to_string()); - - let port = match config.get(&key_port_1) { - Some(value) => match value { - Value::String(val_str) => Some(val_str.clone()), - Value::Number(val_num) => Some(val_num.to_string()), - _ => None, - }, - _ => None, - }; - let port = match port { - Some(_) => port, - None => match config.get(&key_port_2) { - Some(value) => match value { - Value::String(val_str) => Some(val_str.clone()), - Value::Number(val_num) => Some(val_num.to_string()), - _ => None, - }, - _ => None, - }, - }; - - let server = match config.get(&key_server) { - Some(value) => match value { - Value::String(val_str) => Some(val_str.clone()), - _ => None, - }, - _ => None, - }; - let secret = match config.get(&key_secret) { - Some(value) => match value { - Value::String(val_str) => Some(val_str.clone()), - Value::Bool(val_bool) => Some(val_bool.to_string()), - Value::Number(val_num) => Some(val_num.to_string()), - _ => None, - }, - _ => None, - }; - - ClashController { - port, - server, - secret, - } -} - -/// Get the `verge.yaml` -pub fn read_verge() -> VergeConfig { - read_yaml::(app_home_dir().join("verge.yaml")) -} - -/// Save Verge App Config -pub fn save_verge(verge: &VergeConfig) -> Result<(), String> { - save_yaml( - app_home_dir().join("verge.yaml"), - verge, - Some("# The Config for Clash Verge App\n\n"), - ) -} diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index e0cf06b..7171b1f 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -1,5 +1,6 @@ extern crate serde_yaml; +use crate::utils::dirs; use chrono::Local; use log::LevelFilter; use log4rs::append::console::ConsoleAppender; @@ -11,8 +12,6 @@ use std::io::Write; use std::path::PathBuf; use tauri::PackageInfo; -use crate::utils::{app_home_dir, app_resources_dir}; - /// initialize this instance's log file fn init_log(log_dir: &PathBuf) { let local_time = Local::now().format("%Y-%m-%d-%H%M%S").to_string(); @@ -85,11 +84,11 @@ fn init_config_file(app_dir: &PathBuf, res_dir: &PathBuf) { /// initialize app pub fn init_app(package_info: &PackageInfo) { // create app dir - let app_dir = app_home_dir(); + let app_dir = dirs::app_home_dir(); let log_dir = app_dir.join("logs"); let profiles_dir = app_dir.join("profiles"); - let res_dir = app_resources_dir(package_info); + let res_dir = dirs::app_resources_dir(package_info); if !app_dir.exists() { fs::create_dir(&app_dir).unwrap(); diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs index 3a09fe4..a5fe22b 100644 --- a/src-tauri/src/utils/mod.rs +++ b/src-tauri/src/utils/mod.rs @@ -1,8 +1,5 @@ -mod dirs; -pub use self::dirs::*; - -pub mod clash; pub mod config; +pub mod dirs; pub mod fetch; pub mod init; pub mod resolve; diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index 8d5727b..416b80e 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -1,5 +1,5 @@ -use super::{clash, config, init, server, sysopt}; -use crate::{config::ProfilesConfig, events::state}; +use super::{init, server}; +use crate::{config::ProfilesConfig, states}; use tauri::{App, AppHandle, Manager}; /// handle something when start app @@ -10,68 +10,31 @@ pub fn resolve_setup(app: &App) { // init app config init::init_app(app.package_info()); - // run clash sidecar - let info = clash::run_clash_bin(&app.handle()); + // init states + let clash_state = app.state::(); + let verge_state = app.state::(); + let profiles_state = app.state::(); - // resolve the verge config - enable system proxy - let mut original: Option = None; - let verge = config::read_verge(); - let enable = verge.enable_system_proxy.unwrap_or(false); + let mut clash = clash_state.0.lock().unwrap(); + let mut verge = verge_state.0.lock().unwrap(); + let mut profiles = profiles_state.0.lock().unwrap(); - if enable && info.controller.is_some() { - if let Ok(original_conf) = sysopt::get_proxy_config() { - original = Some(original_conf) - }; - let ctl = info.controller.clone().unwrap(); - if ctl.port.is_some() { - let server = format!("127.0.0.1:{}", ctl.port.unwrap()); - let bypass = verge - .system_proxy_bypass - .clone() - .unwrap_or(String::from(sysopt::DEFAULT_BYPASS)); - let config = sysopt::SysProxyConfig { - enable, - server, - bypass, - }; - if let Err(err) = sysopt::set_proxy_config(&config) { - log::error!("can not set system proxy for `{}`", err); - } - } + if let Err(err) = clash.run_sidecar() { + log::error!("{}", err); } - // update state - let profiles_state = app.state::(); - let mut profiles = profiles_state.0.lock().unwrap(); *profiles = ProfilesConfig::read_file(); + if let Err(err) = profiles.activate(clash.info.clone()) { + log::error!("{}", err); + } - let verge_state = app.state::(); - let mut verge_arc = verge_state.0.lock().unwrap(); - *verge_arc = verge; - - let clash_state = app.state::(); - let mut clash_arc = clash_state.0.lock().unwrap(); - *clash_arc = info; - - let some_state = app.state::(); - let mut some_arc = some_state.0.lock().unwrap(); - *some_arc = original; + verge.init_sysproxy(clash.info.port.clone()); } /// reset system proxy pub fn resolve_reset(app_handle: &AppHandle) { - let state = app_handle.try_state::(); - if state.is_none() { - return; - } - match state.unwrap().0.lock() { - Ok(arc) => { - if arc.is_some() { - if let Err(err) = sysopt::set_proxy_config(arc.as_ref().unwrap()) { - log::error!("failed to reset proxy for `{}`", err); - } - } - } - _ => {} - }; + let verge_state = app_handle.state::(); + let mut verge_arc = verge_state.0.lock().unwrap(); + + verge_arc.reset_sysproxy(); } diff --git a/src-tauri/src/utils/sysopt.rs b/src-tauri/src/utils/sysopt.rs index 46250e3..c47ab13 100644 --- a/src-tauri/src/utils/sysopt.rs +++ b/src-tauri/src/utils/sysopt.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; use std::io; +static DEFAULT_BYPASS: &str = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*;"; + #[derive(Debug, Deserialize, Serialize, Clone)] pub struct SysProxyConfig { pub enable: bool, @@ -18,16 +20,21 @@ impl Default for SysProxyConfig { } } -pub static DEFAULT_BYPASS: &str = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*;"; - -#[cfg(target_os = "windows")] -mod win { - use super::*; - use winreg::enums::*; - use winreg::RegKey; +impl SysProxyConfig { + pub fn new(enable: bool, port: String, bypass: Option) -> Self { + SysProxyConfig { + enable, + server: format!("127.0.0.1:{}", port), + bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()), + } + } /// Get the windows system proxy config - pub fn get_proxy_config() -> io::Result { + #[cfg(target_os = "windows")] + pub fn get_sys() -> io::Result { + use winreg::enums::*; + use winreg::RegKey; + let hkcu = RegKey::predef(HKEY_CURRENT_USER); let cur_var = hkcu.open_subkey_with_flags( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", @@ -41,43 +48,38 @@ mod win { }) } + #[cfg(target_os = "windows")] /// Set the windows system proxy config - pub fn set_proxy_config(config: &SysProxyConfig) -> io::Result<()> { + pub fn set_sys(&self) -> io::Result<()> { + use winreg::enums::*; + use winreg::RegKey; let hkcu = RegKey::predef(HKEY_CURRENT_USER); let cur_var = hkcu.open_subkey_with_flags( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", KEY_SET_VALUE, )?; - let enable: u32 = if config.enable { 1u32 } else { 0u32 }; + let enable: u32 = if self.enable { 1u32 } else { 0u32 }; cur_var.set_value("ProxyEnable", &enable)?; - cur_var.set_value("ProxyServer", &config.server)?; - cur_var.set_value("ProxyOverride", &config.bypass)?; - - Ok(()) + cur_var.set_value("ProxyServer", &self.server)?; + cur_var.set_value("ProxyOverride", &self.bypass) } } -#[cfg(target_os = "macos")] -mod macos { - use super::*; +// #[cfg(target_os = "macos")] +// mod macos { +// use super::*; - pub fn get_proxy_config() -> io::Result { - Ok(SysProxyConfig { - enable: false, - server: "server".into(), - bypass: "bypass".into(), - }) - } +// pub fn get_proxy_config() -> io::Result { +// Ok(SysProxyConfig { +// enable: false, +// server: "server".into(), +// bypass: "bypass".into(), +// }) +// } - pub fn set_proxy_config(config: &SysProxyConfig) -> io::Result<()> { - Ok(()) - } -} - -#[cfg(target_os = "windows")] -pub use win::*; - -#[cfg(target_os = "macos")] -pub use macos::*; +// pub fn set_proxy_config(config: &SysProxyConfig) -> io::Result<()> { +// Ok(()) +// } +// } diff --git a/src/services/api.ts b/src/services/api.ts index 52d4cb1..8e0273f 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -13,8 +13,8 @@ export async function getAxios() { try { const info = await getClashInfo(); - if (info?.controller?.server) server = info?.controller?.server; - if (info?.controller?.secret) secret = info?.controller?.secret; + if (info?.server) server = info?.server; + if (info?.secret) secret = info?.secret; } catch {} axiosIns = axios.create({ @@ -29,7 +29,7 @@ export async function getAxios() { export async function getInfomation() { if (server) return { server, secret }; const info = await getClashInfo(); - return info?.controller!; + return info!; } /// Get Version diff --git a/src/services/cmds.ts b/src/services/cmds.ts index 132cfb2..308ff63 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -2,7 +2,7 @@ import { invoke } from "@tauri-apps/api/tauri"; import { ApiType, CmdType } from "./types"; export async function getProfiles() { - return (await invoke("get_profiles")) ?? {}; + return invoke("get_profiles"); } export async function syncProfiles() { diff --git a/src/services/types.ts b/src/services/types.ts index 3544c42..e7c91f5 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -80,8 +80,9 @@ export namespace ApiType { export namespace CmdType { export interface ClashInfo { status: string; - controller?: { server?: string; secret?: string }; - message?: string; + port?: string; + server?: string; + secret?: string; } export interface ProfileItem {