feat: enhance clash caller & support more commands

This commit is contained in:
GyDi 2021-12-14 18:37:03 +08:00
parent 4719649bf4
commit 881a95520a
6 changed files with 121 additions and 32 deletions

View File

@ -1,17 +1,31 @@
use tauri::api::process::kill_children; use crate::{
events::{emit::ClashInfoPayload, state::ClashInfoState},
use crate::utils::{clash, import}; utils::{clash, import},
};
use tauri::{api::process::kill_children, AppHandle, State};
#[tauri::command] #[tauri::command]
pub fn cmd_restart_sidebar() { pub fn restart_sidebar(app_handle: AppHandle, clash_info: State<'_, ClashInfoState>) {
kill_children(); 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] #[tauri::command]
pub async fn cmd_import_profile(url: String) -> Result<String, String> { pub async fn import_profile(url: String) -> Result<String, String> {
match import::import_profile(&url).await { match import::import_profile(&url).await {
Ok(_) => Ok(String::from("success")), Ok(_) => Ok(String::from("success")),
Err(_) => Err(String::from("error")), Err(_) => Err(String::from("error")),
} }
} }
#[tauri::command]
pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfoPayload> {
match clash_info.0.lock() {
Ok(arc) => Some(arc.clone()),
_ => None,
}
}

View File

@ -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<ClashController>,
/// some message
pub message: Option<String>,
}
/// 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();
}
_ => {}
};
}

View File

@ -0,0 +1,2 @@
pub mod emit;
pub mod state;

View File

@ -0,0 +1,6 @@
use std::sync::{Arc, Mutex};
use super::emit::ClashInfoPayload;
#[derive(Default)]
pub struct ClashInfoState(pub Arc<Mutex<ClashInfoPayload>>);

View File

@ -7,10 +7,13 @@ extern crate tauri;
mod cmd; mod cmd;
mod config; mod config;
mod events;
mod utils; mod utils;
use crate::events::state::ClashInfoState;
use std::sync::{Arc, Mutex};
use tauri::{ use tauri::{
CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, api, CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
SystemTraySubmenu, SystemTraySubmenu,
}; };
@ -41,6 +44,7 @@ fn main() -> std::io::Result<()> {
window.set_focus().unwrap(); window.set_focus().unwrap();
} }
"quit" => { "quit" => {
api::process::kill_children();
app.exit(0); app.exit(0);
} }
_ => {} _ => {}
@ -53,18 +57,18 @@ fn main() -> std::io::Result<()> {
_ => {} _ => {}
}) })
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
cmd::cmd_import_profile, cmd::import_profile,
cmd::cmd_restart_sidebar, cmd::restart_sidebar,
cmd::get_clash_info,
]) ])
.build(tauri::generate_context!()) .build(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
// init app config // init app config
utils::init::init_app(app.package_info()); utils::init::init_app(app.package_info());
// clash::run_clash_bin(); // run clash sidecar
let info = utils::clash::run_clash_bin(&app.handle());
// 通过clash config初始化menu和tray app.manage(ClashInfoState(Arc::new(Mutex::new(info))));
// 通过verge config干点别的
app.run(|app_handle, e| match e { app.run(|app_handle, e| match e {
tauri::Event::CloseRequested { label, api, .. } => { tauri::Event::CloseRequested { label, api, .. } => {
@ -75,6 +79,9 @@ fn main() -> std::io::Result<()> {
tauri::Event::ExitRequested { api, .. } => { tauri::Event::ExitRequested { api, .. } => {
api.prevent_exit(); api.prevent_exit();
} }
tauri::Event::Exit => {
api::process::kill_children();
}
_ => {} _ => {}
}); });

View File

@ -1,29 +1,63 @@
extern crate log; extern crate log;
use crate::utils::app_home_dir; use crate::{
use tauri::api::process::{Command, CommandEvent}; config::read_clash_controller,
events::emit::{clash_start, ClashInfoPayload},
utils::app_home_dir,
};
use tauri::{
api::process::{Command, CommandEvent},
AppHandle,
};
/// Run the clash bin /// 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 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") match Command::new_sidecar("clash") {
.expect("failed to create clash binary") Ok(cmd) => match cmd
.args(["-d", &app_dir.as_os_str().to_str().unwrap()]) .args(["-d", &app_dir.as_os_str().to_str().unwrap()])
.spawn() .spawn()
.expect("failed to spawn sidecar"); {
Ok((mut rx, _)) => {
log::info!("Successfully execute clash sidecar");
payload.controller = Some(read_clash_controller());
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
while let Some(event) = rx.recv().await { while let Some(event) = rx.recv().await {
match event { match event {
CommandEvent::Stdout(line) => { CommandEvent::Stdout(line) => log::info!("{}", line),
log::info!("{}", line); CommandEvent::Stderr(err) => log::error!("{}", err),
} _ => {}
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
} }