From 881a95520a83fb7e692b5080e1b4205cf506e4cd Mon Sep 17 00:00:00 2001 From: GyDi Date: Tue, 14 Dec 2021 18:37:03 +0800 Subject: [PATCH] feat: enhance clash caller & support more commands --- src-tauri/src/cmd.rs | 26 ++++++++++--- src-tauri/src/events/emit.rs | 26 +++++++++++++ src-tauri/src/events/mod.rs | 2 + src-tauri/src/events/state.rs | 6 +++ src-tauri/src/main.rs | 21 ++++++---- src-tauri/src/utils/clash.rs | 72 ++++++++++++++++++++++++++--------- 6 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 src-tauri/src/events/emit.rs create mode 100644 src-tauri/src/events/mod.rs create mode 100644 src-tauri/src/events/state.rs diff --git a/src-tauri/src/cmd.rs b/src-tauri/src/cmd.rs index 12aee41..5c2cb38 100644 --- a/src-tauri/src/cmd.rs +++ b/src-tauri/src/cmd.rs @@ -1,17 +1,31 @@ -use tauri::api::process::kill_children; - -use crate::utils::{clash, import}; +use crate::{ + events::{emit::ClashInfoPayload, state::ClashInfoState}, + utils::{clash, import}, +}; +use tauri::{api::process::kill_children, AppHandle, State}; #[tauri::command] -pub fn cmd_restart_sidebar() { +pub fn restart_sidebar(app_handle: AppHandle, clash_info: State<'_, ClashInfoState>) { kill_children(); - clash::run_clash_bin(); + let payload = clash::run_clash_bin(&app_handle); + + if let Ok(mut arc) = clash_info.0.lock() { + *arc = payload; + } } #[tauri::command] -pub async fn cmd_import_profile(url: String) -> Result { +pub async fn import_profile(url: String) -> Result { match import::import_profile(&url).await { Ok(_) => Ok(String::from("success")), Err(_) => Err(String::from("error")), } } + +#[tauri::command] +pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option { + match clash_info.0.lock() { + Ok(arc) => Some(arc.clone()), + _ => None, + } +} diff --git a/src-tauri/src/events/emit.rs b/src-tauri/src/events/emit.rs new file mode 100644 index 0000000..029cc35 --- /dev/null +++ b/src-tauri/src/events/emit.rs @@ -0,0 +1,26 @@ +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 new file mode 100644 index 0000000..c382b2f --- /dev/null +++ b/src-tauri/src/events/mod.rs @@ -0,0 +1,2 @@ +pub mod emit; +pub mod state; diff --git a/src-tauri/src/events/state.rs b/src-tauri/src/events/state.rs new file mode 100644 index 0000000..22aa77f --- /dev/null +++ b/src-tauri/src/events/state.rs @@ -0,0 +1,6 @@ +use std::sync::{Arc, Mutex}; + +use super::emit::ClashInfoPayload; + +#[derive(Default)] +pub struct ClashInfoState(pub Arc>); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 742cf33..98765ec 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,10 +7,13 @@ extern crate tauri; mod cmd; mod config; +mod events; mod utils; +use crate::events::state::ClashInfoState; +use std::sync::{Arc, Mutex}; use tauri::{ - CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, + api, CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu, }; @@ -41,6 +44,7 @@ fn main() -> std::io::Result<()> { window.set_focus().unwrap(); } "quit" => { + api::process::kill_children(); app.exit(0); } _ => {} @@ -53,18 +57,18 @@ fn main() -> std::io::Result<()> { _ => {} }) .invoke_handler(tauri::generate_handler![ - cmd::cmd_import_profile, - cmd::cmd_restart_sidebar, + cmd::import_profile, + cmd::restart_sidebar, + cmd::get_clash_info, ]) .build(tauri::generate_context!()) .expect("error while running tauri application"); // init app config utils::init::init_app(app.package_info()); - // clash::run_clash_bin(); - - // 通过clash config初始化menu和tray - // 通过verge config干点别的 + // run clash sidecar + let info = utils::clash::run_clash_bin(&app.handle()); + app.manage(ClashInfoState(Arc::new(Mutex::new(info)))); app.run(|app_handle, e| match e { tauri::Event::CloseRequested { label, api, .. } => { @@ -75,6 +79,9 @@ fn main() -> std::io::Result<()> { tauri::Event::ExitRequested { api, .. } => { api.prevent_exit(); } + tauri::Event::Exit => { + api::process::kill_children(); + } _ => {} }); diff --git a/src-tauri/src/utils/clash.rs b/src-tauri/src/utils/clash.rs index d028b79..9d2c46d 100644 --- a/src-tauri/src/utils/clash.rs +++ b/src-tauri/src/utils/clash.rs @@ -1,29 +1,63 @@ extern crate log; -use crate::utils::app_home_dir; -use tauri::api::process::{Command, CommandEvent}; +use crate::{ + config::read_clash_controller, + events::emit::{clash_start, ClashInfoPayload}, + utils::app_home_dir, +}; +use tauri::{ + api::process::{Command, CommandEvent}, + AppHandle, +}; /// Run the clash bin -pub fn run_clash_bin() { +pub fn run_clash_bin(app_handle: &AppHandle) -> ClashInfoPayload { let app_dir = app_home_dir(); + let mut payload = ClashInfoPayload { + status: "success".to_string(), + controller: None, + message: None, + }; - let (mut rx, _sidecar) = Command::new_sidecar("clash") - .expect("failed to create clash binary") - .args(["-d", &app_dir.as_os_str().to_str().unwrap()]) - .spawn() - .expect("failed to spawn sidecar"); + match Command::new_sidecar("clash") { + Ok(cmd) => match cmd + .args(["-d", &app_dir.as_os_str().to_str().unwrap()]) + .spawn() + { + Ok((mut rx, _)) => { + log::info!("Successfully execute clash sidecar"); + payload.controller = Some(read_clash_controller()); - tauri::async_runtime::spawn(async move { - while let Some(event) = rx.recv().await { - match event { - CommandEvent::Stdout(line) => { - log::info!("{}", line); - } - CommandEvent::Stderr(err) => { - log::error!("{}", err); - } - _ => {} + tauri::async_runtime::spawn(async move { + while let Some(event) = rx.recv().await { + match event { + CommandEvent::Stdout(line) => log::info!("{}", line), + CommandEvent::Stderr(err) => log::error!("{}", err), + _ => {} + } + } + }); } + Err(err) => { + log::error!( + "Failed to execute clash sidecar for \"{:?}\"", + err.to_string() + ); + payload.status = "error".to_string(); + payload.message = Some(err.to_string()); + } + }, + Err(err) => { + log::error!( + "Failed to execute clash sidecar for \"{:?}\"", + err.to_string() + ); + payload.status = "error".to_string(); + payload.message = Some(err.to_string()); } - }); + }; + + clash_start(app_handle, &payload); + + payload }