refactor: mode manage on tray

This commit is contained in:
GyDi 2022-07-13 02:26:54 +08:00
parent fcf570e96e
commit 6a51e93ded
No known key found for this signature in database
GPG Key ID: 58B15242BA8277A6
4 changed files with 79 additions and 120 deletions

View File

@ -16,9 +16,6 @@ pub struct ClashInfo {
/// clash secret
pub secret: Option<String>,
/// mode
pub mode: Option<String>,
}
impl ClashInfo {
@ -29,7 +26,6 @@ impl ClashInfo {
let key_port_2 = Value::from("mixed-port");
let key_server = Value::from("external-controller");
let key_secret = Value::from("secret");
let key_mode = Value::from("mode");
let port = match config.get(&key_port_1) {
Some(value) => match value {
@ -76,20 +72,11 @@ impl ClashInfo {
_ => None,
};
let mode = match config.get(&key_mode) {
Some(value) => match value {
Value::String(val_str) => Some(val_str.clone()),
_ => None,
},
_ => None,
};
ClashInfo {
status: "init".into(),
port,
server,
secret,
mode,
}
}
}

View File

@ -3,7 +3,7 @@ use self::sysopt::Sysopt;
use self::timer::Timer;
use crate::core::enhance::PrfEnhancedResult;
use crate::log_if_err;
use crate::utils::{dirs, help};
use crate::utils::help;
use anyhow::{bail, Result};
use parking_lot::Mutex;
use serde_yaml::Mapping;
@ -112,6 +112,7 @@ impl Core {
log_if_err!(sysopt.init_launch(auto_launch));
log_if_err!(self.update_systray(&app_handle));
log_if_err!(self.update_systray_clash(&app_handle));
// wait the window setup during resolve app
let core = self.clone();
@ -191,7 +192,7 @@ impl Core {
}
if changed_mode {
self.update_systray(app_handle)?;
self.update_systray_clash(app_handle)?;
}
Ok(())
@ -240,7 +241,7 @@ impl Core {
#[cfg(target_os = "windows")]
if tun_mode.is_some() && *tun_mode.as_ref().unwrap_or(&false) {
let wintun_dll = dirs::app_home_dir().join("wintun.dll");
let wintun_dll = crate::utils::dirs::app_home_dir().join("wintun.dll");
if !wintun_dll.exists() {
bail!("failed to enable TUN for missing `wintun.dll`");
}
@ -262,31 +263,39 @@ impl Core {
Ok(())
}
/// update the system tray state
pub fn update_systray(&self, app_handle: &AppHandle) -> Result<()> {
// update system tray state (clash config)
pub fn update_systray_clash(&self, app_handle: &AppHandle) -> Result<()> {
let clash = self.clash.lock();
let info = clash.info.clone();
let mode = info.mode.as_ref();
let mode = clash
.config
.get(&Value::from("mode"))
.map(|val| val.as_str().unwrap_or("rule"))
.unwrap_or("rule");
let tray = app_handle.tray_handle();
tray.get_item("rule_mode").set_selected(mode == "rule")?;
tray
.get_item("global_mode")
.set_selected(mode == "global")?;
tray
.get_item("direct_mode")
.set_selected(mode == "direct")?;
tray
.get_item("script_mode")
.set_selected(mode == "script")?;
Ok(())
}
/// update the system tray state (verge config)
pub fn update_systray(&self, app_handle: &AppHandle) -> Result<()> {
let verge = self.verge.lock();
let tray = app_handle.tray_handle();
let system_proxy = verge.enable_system_proxy.as_ref();
let tun_mode = verge.enable_tun_mode.as_ref();
tray
.get_item("rule_mode")
.set_selected((*mode.unwrap()).eq("rule"))?;
tray
.get_item("global_mode")
.set_selected((*mode.unwrap()).eq("global"))?;
tray
.get_item("direct_mode")
.set_selected((*mode.unwrap()).eq("direct"))?;
tray
.get_item("script_mode")
.set_selected((*mode.unwrap()).eq("script"))?;
tray
.get_item("system_proxy")
.set_selected(*system_proxy.unwrap_or(&false))?;
@ -302,6 +311,33 @@ impl Core {
Ok(())
}
// update rule/global/direct/script mode
pub fn update_mode(&self, app_handle: &AppHandle, mode: &str) -> Result<()> {
// save config to file
let mut clash = self.clash.lock();
clash.config.insert(Value::from("mode"), Value::from(mode));
clash.save_config()?;
let info = clash.info.clone();
drop(clash);
let notice = {
let window = self.window.lock();
Notice::from(window.clone())
};
let mut mapping = Mapping::new();
mapping.insert(Value::from("mode"), Value::from(mode));
let service = self.service.lock();
service.patch_config(info, mapping, notice)?;
// update tray
self.update_systray_clash(app_handle)?;
Ok(())
}
/// activate the profile
/// auto activate enhanced profile
pub fn activate(&self) -> Result<()> {
@ -425,31 +461,6 @@ impl Core {
Ok(())
}
// update rule/global/direct/script mode
pub fn update_mode(&self, app_handle: &AppHandle, mode: &str) -> Result<()> {
let mut mapping = Mapping::new();
mapping.insert(Value::from("mode"), Value::from(mode));
self.patch_clash(mapping, app_handle);
let (config, info) = {
let clash = self.clash.lock();
let config = clash.config.clone();
let info = clash.info.clone();
(config, info)
};
let notice = {
let window = self.window.lock();
Notice::from(window.clone())
};
let service = self.service.lock();
service.patch_config(info, config, notice);
Ok(())
}
}
impl Core {

View File

@ -1,10 +1,8 @@
use super::Clash;
use super::{notice::Notice, ClashInfo};
use crate::log_if_err;
use crate::utils::{config, dirs};
use anyhow::{bail, Result};
use reqwest::header::HeaderMap;
use serde::{Deserialize, Serialize};
use serde_yaml::Mapping;
use std::{collections::HashMap, time::Duration};
use tauri::api::process::{Command, CommandChild, CommandEvent};
@ -139,24 +137,7 @@ impl Service {
let temp_path = dirs::profiles_temp_path();
config::save_yaml(temp_path.clone(), &config, Some("# Clash Verge Temp File"))?;
if info.server.is_none() {
if info.port.is_none() {
bail!("failed to parse config.yaml file");
} else {
bail!("failed to parse the server");
}
}
let server = info.server.unwrap();
let server = format!("http://{server}/configs");
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/json".parse().unwrap());
if let Some(secret) = info.secret.as_ref() {
let secret = format!("Bearer {}", secret.clone()).parse().unwrap();
headers.insert("Authorization", secret);
}
let (server, headers) = Self::clash_client_info(info)?;
tauri::async_runtime::spawn(async move {
let mut data = HashMap::new();
@ -197,6 +178,24 @@ impl Service {
bail!("did not start sidecar");
}
let (server, headers) = Self::clash_client_info(info)?;
tauri::async_runtime::spawn(async move {
if let Ok(client) = reqwest::ClientBuilder::new().no_proxy().build() {
let builder = client.patch(&server).headers(headers.clone()).json(&config);
match builder.send().await {
Ok(_) => notice.refresh_clash(),
Err(err) => log::error!("{err}"),
}
}
});
Ok(())
}
/// get clash client url and headers from clash info
fn clash_client_info(info: ClashInfo) -> Result<(String, HeaderMap)> {
if info.server.is_none() {
if info.port.is_none() {
bail!("failed to parse config.yaml file");
@ -216,34 +215,7 @@ impl Service {
headers.insert("Authorization", secret);
}
tauri::async_runtime::spawn(async move {
// retry 5 times
for _ in 0..5 {
match reqwest::ClientBuilder::new().no_proxy().build() {
Ok(client) => {
let builder = client.patch(&server).headers(headers.clone()).json(&config);
match builder.send().await {
Ok(resp) => {
if resp.status() != 204 {
log::error!("failed to activate clash with status \"{}\"", resp.status());
}
notice.refresh_clash();
// do not retry
break;
}
Err(err) => log::error!("failed to activate for `{err}`"),
}
}
Err(err) => log::error!("failed to activate for `{err}`"),
}
sleep(Duration::from_millis(500)).await;
}
});
Ok(())
Ok((server, headers))
}
}

View File

@ -51,21 +51,10 @@ fn main() -> std::io::Result<()> {
"open_window" => {
resolve::create_window(app_handle);
}
"rule_mode" => {
mode @ ("rule_mode" | "global_mode" | "direct_mode" | "script_mode") => {
let mode = &mode[0..mode.len() - 5];
let core = app_handle.state::<core::Core>();
crate::log_if_err!(core.update_mode(app_handle, "rule"));
}
"global_mode" => {
let core = app_handle.state::<core::Core>();
crate::log_if_err!(core.update_mode(app_handle, "global"));
}
"direct_mode" => {
let core = app_handle.state::<core::Core>();
crate::log_if_err!(core.update_mode(app_handle, "direct"));
}
"script_mode" => {
let core = app_handle.state::<core::Core>();
crate::log_if_err!(core.update_mode(app_handle, "script"));
crate::log_if_err!(core.update_mode(app_handle, mode));
}
"system_proxy" => {
let core = app_handle.state::<core::Core>();