diff --git a/src-tauri/src/clash.rs b/src-tauri/src/clash.rs index 3e11d47..ef25ff1 100644 --- a/src-tauri/src/clash.rs +++ b/src-tauri/src/clash.rs @@ -1,56 +1,30 @@ +extern crate log; extern crate reqwest; extern crate serde_yaml; -use std::fs; -use std::io::Write; -use std::path::{Path, PathBuf}; -use tauri::api::path::home_dir; +use crate::init::app_home_dir; use tauri::api::process::{Command, CommandEvent}; -/// Get the clash config dir -pub fn get_config_dir() -> PathBuf { - home_dir() - .unwrap() - .join(Path::new(".config")) - .join(Path::new("clash-verge")) -} - -/// Initialize the default config dir for clash -pub fn init_clash_config() { - let config_dir = get_config_dir(); - let conifg_yaml = config_dir.join("config.yaml"); - - let default_yaml = - "mixed-port: 7890\nallow-lan: false\nexternal-controller: 127.0.0.1:9090\nsecret: ''\n"; - let mut yaml_obj = serde_yaml::from_str::(&default_yaml).unwrap(); - - if !config_dir.exists() { - let config_dir = config_dir.clone(); - fs::create_dir(config_dir).unwrap(); - let mut file = fs::File::create(conifg_yaml).unwrap(); - file.write(default_yaml.as_bytes()).unwrap(); - } - - let yaml_path = &config_dir.join("config.yaml"); - let yaml_str = fs::read_to_string(yaml_path).unwrap(); - yaml_obj = serde_yaml::from_str::(&yaml_str).unwrap(); - - println!("{:?}", yaml_obj); -} - /// Run the clash bin -pub fn run_clash_bin(config_dirs: &str) { - let (mut rx, mut _child) = Command::new_sidecar("clash") +pub fn run_clash_bin() { + let app_dir = app_home_dir(); + + let (mut rx, _sidecar) = Command::new_sidecar("clash") .expect("failed to create clash binary") - .args(["-d", config_dirs]) + .args(["-d", &app_dir.as_os_str().to_str().unwrap()]) .spawn() .expect("failed to spawn sidecar"); tauri::async_runtime::spawn(async move { - // read events such as stdout while let Some(event) = rx.recv().await { - if let CommandEvent::Stdout(line) = event { - println!("{:?}", line); + match event { + CommandEvent::Stdout(line) => { + log::info!("{}", line); + } + CommandEvent::Stderr(err) => { + log::error!("{}", err); + } + _ => {} } } }); diff --git a/src-tauri/src/cmd.rs b/src-tauri/src/cmd.rs index c6b224a..9b02ca1 100644 --- a/src-tauri/src/cmd.rs +++ b/src-tauri/src/cmd.rs @@ -1,4 +1,16 @@ -use tauri::api::process::CommandChild; +use crate::clash; +use tauri::api::process::kill_children; #[tauri::command] -fn set_clash_port(process: Option, port: i32) {} +pub fn restart_sidebar() { + kill_children(); + clash::run_clash_bin(); +} + +#[tauri::command] +pub async fn get_config_data(url: String) -> Result { + match clash::fetch_url(&url).await { + Ok(_) => Ok(String::from("success")), + Err(_) => Err(String::from("error")), + } +} diff --git a/src-tauri/src/init.rs b/src-tauri/src/init.rs new file mode 100644 index 0000000..7333e47 --- /dev/null +++ b/src-tauri/src/init.rs @@ -0,0 +1,143 @@ +extern crate serde_yaml; + +use log::LevelFilter; +use log4rs::append::console::ConsoleAppender; +use log4rs::append::file::FileAppender; +use log4rs::config::{Appender, Config, Root}; +use log4rs::encode::pattern::PatternEncoder; +use serde_yaml::Mapping; +use std::fs; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::time::{SystemTime, UNIX_EPOCH}; +use tauri::api::path::home_dir; + +const CLASH_CONFIG: &str = r#" +mixed-port: 7890 +allow-lan: false +external-controller: 127.0.0.1:9090 +secret: '' +"#; + +const VERGE_CONFIG: &str = r#" +nothing: ohh! +"#; + +/// get the verge app home dir +pub fn app_home_dir() -> PathBuf { + home_dir() + .unwrap() + .join(Path::new(".config")) + .join(Path::new("clash-verge")) +} + +/// initialize the app home dir +fn init_app_dir() -> PathBuf { + let app_dir = app_home_dir(); + if !app_dir.exists() { + fs::create_dir(&app_dir).unwrap(); + } + app_dir +} + +/// initialize the logs dir +fn init_log_dir() -> PathBuf { + let log_dir = app_home_dir().join("logs"); + if !log_dir.exists() { + fs::create_dir(&log_dir).unwrap(); + } + log_dir +} + +/// initialize this instance's log file +fn init_log() { + let log_dir = init_log_dir(); + let log_time = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + let log_file = format!("log-{:?}", log_time); + let log_file = log_dir.join(log_file); + + let stdout = ConsoleAppender::builder().build(); + let tofile = FileAppender::builder() + .encoder(Box::new(PatternEncoder::new( + "{d(%Y-%m-%d %H:%M:%S)} - {m}{n}", + ))) + .build(log_file) + .unwrap(); + + let config = Config::builder() + .appender(Appender::builder().build("stdout", Box::new(stdout))) + .appender(Appender::builder().build("file", Box::new(tofile))) + .build( + Root::builder() + .appenders(["stdout", "file"]) + .build(LevelFilter::Debug), + ) + .unwrap(); + + log4rs::init_config(config).unwrap(); +} + +/// Initialize & Get the clash config +fn init_clash_config() -> Mapping { + let app_dir = app_home_dir(); + let yaml_path = app_dir.join("config.yaml"); + let mut yaml_obj = serde_yaml::from_str::(CLASH_CONFIG).unwrap(); + + if !yaml_path.exists() { + fs::File::create(yaml_path) + .unwrap() + .write(CLASH_CONFIG.as_bytes()) + .unwrap(); + } else { + let yaml_str = fs::read_to_string(yaml_path).unwrap(); + let user_obj = serde_yaml::from_str::(&yaml_str).unwrap(); + for (key, value) in user_obj.iter() { + yaml_obj.insert(key.clone(), value.clone()); + } + } + yaml_obj +} + +/// Initialize & Get the app config +fn init_verge_config() -> Mapping { + let app_dir = app_home_dir(); + let yaml_path = app_dir.join("verge.yaml"); + let mut yaml_obj = serde_yaml::from_str::(VERGE_CONFIG).unwrap(); + + if !yaml_path.exists() { + fs::File::create(yaml_path) + .unwrap() + .write(VERGE_CONFIG.as_bytes()) + .unwrap(); + } else { + let yaml_str = fs::read_to_string(yaml_path).unwrap(); + let user_obj = serde_yaml::from_str::(&yaml_str).unwrap(); + for (key, value) in user_obj.iter() { + yaml_obj.insert(key.clone(), value.clone()); + } + } + yaml_obj +} + +#[derive(Debug)] +pub struct InitApp { + pub clash_config: Mapping, + pub verge_config: Mapping, +} + +/// initialize app +pub fn init_app() -> InitApp { + init_app_dir(); + init_log(); + + let clash_config = init_clash_config(); + let verge_config = init_verge_config(); + + InitApp { + clash_config, + verge_config, + } +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index b65f833..5485c09 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -6,50 +6,63 @@ extern crate tauri; mod clash; +mod cmd; +mod init; mod sysopt; -use tauri::{CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu}; - -#[tauri::command] -async fn get_config_data(url: String) -> Result { - match clash::fetch_url(&url).await { - Ok(_) => Ok(String::from("success")), - Err(_) => Err(String::from("error")), - } -} +use tauri::{ + CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, + SystemTraySubmenu, +}; fn main() -> std::io::Result<()> { - clash::run_clash_bin(&clash::get_config_dir().to_str().unwrap()); + init::init_app(); + // clash::run_clash_bin(); + + // 通过clash config初始化menu和tray + // 通过verge config干点别的 + + let sub_menu = SystemTraySubmenu::new( + "出站规则", + SystemTrayMenu::new() + .add_item(CustomMenuItem::new("rway_global", "全局连接")) + .add_item(CustomMenuItem::new("rway_rule", "规则连接").selected()) + .add_item(CustomMenuItem::new("rway_direct", "直接连接")), + ); + let menu = SystemTrayMenu::new() + .add_submenu(sub_menu) + .add_native_item(SystemTrayMenuItem::Separator) + .add_item(CustomMenuItem::new("syste_proxy", "设置为系统代理")) + .add_item(CustomMenuItem::new("self_startup", "开机启动").selected()) + .add_item(CustomMenuItem::new("open_window", "显示应用")) + .add_native_item(SystemTrayMenuItem::Separator) + .add_item(CustomMenuItem::new("quit", "退出").accelerator("CmdOrControl+Q")); let app = tauri::Builder::default() - .system_tray( - SystemTray::new().with_menu( - SystemTrayMenu::new() - .add_item(CustomMenuItem::new("event_show", "Show")) - .add_item(CustomMenuItem::new("event_quit", "Quit")), - ), - ) + .system_tray(SystemTray::new().with_menu(menu)) .on_system_tray_event(move |app, event| match event { + SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { + "open_window" => { + let window = app.get_window("main").unwrap(); + window.show().unwrap(); + window.set_focus().unwrap(); + } + "quit" => { + app.exit(0); + } + _ => {} + }, SystemTrayEvent::LeftClick { .. } => { let window = app.get_window("main").unwrap(); window.show().unwrap(); window.set_focus().unwrap(); } - - SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { - "event_show" => { - let window = app.get_window("main").unwrap(); - window.show().unwrap(); - window.set_focus().unwrap(); - } - "event_quit" => { - app.exit(0); - } - _ => {} - }, _ => {} }) - .invoke_handler(tauri::generate_handler![get_config_data]) + .invoke_handler(tauri::generate_handler![ + cmd::get_config_data, + cmd::restart_sidebar, + ]) .build(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/sysopt.rs b/src-tauri/src/sysopt.rs index b21e769..e6a609b 100644 --- a/src-tauri/src/sysopt.rs +++ b/src-tauri/src/sysopt.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use std::io; #[cfg(target_os = "windows")] use winreg::enums::*; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 4f74bb1..e61d95e 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -5,7 +5,7 @@ }, "build": { "distDir": "../dist", - "devPath": "http://localhost:3000", + "devPath": "http://localhost:3000/proxy", "beforeDevCommand": "npm run web:dev", "beforeBuildCommand": "npm run web:build" }, @@ -61,7 +61,9 @@ "width": 800, "height": 600, "resizable": true, - "fullscreen": false + "fullscreen": false, + "decorations": true, + "transparent": false } ], "security": {