diff --git a/package.json b/package.json index 4082e99..054fd85 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,14 @@ "@tauri-apps/api": "^2", "@tauri-apps/plugin-fs": "~2", "@tauri-apps/plugin-opener": "^2", + "@tauri-apps/plugin-os": "~2", + "@tauri-apps/plugin-process": "~2", + "@tauri-apps/plugin-shell": "~2", "@tauri-apps/plugin-sql": "~2", "vue": "^3.5.21", "vue-i18n": "^11.1.12", "vue-router": "^4.5.1", + "vue-web-terminal": "^3.4.1", "vuetify": "^3.10.1", "zod": "^4.1.12" }, diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d1888c1..2b2da85 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -24,3 +24,6 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tauri-plugin-sql = { version = "2", features = ["sqlite"] } tauri-plugin-fs = "2" +tauri-plugin-os = "2" +tauri-plugin-shell = "2" +tauri-plugin-process = "2" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 7e75c02..e624831 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -11,6 +11,9 @@ "sql:default", "sql:allow-execute", "fs:default", + "os:default", + "shell:default", + "process:default", { "identifier": "fs:allow-write-text-file", "allow": [ @@ -26,6 +29,28 @@ "path": "$APPCONFIG/*" } ] + }, + { + "identifier": "fs:allow-exists", + "allow": [ + { + "path": "$APPCONFIG/*" + } + ] + }, + { + "identifier": "shell:allow-execute", + "allow": [ + { + "name": "exec-sh", + "cmd": "sh", + "args": [ + "-c", + "echo 'Hello World!'" + ], + "sidecar": false + } + ] } ] } \ No newline at end of file diff --git a/src-tauri/src/cores.rs b/src-tauri/src/cores.rs deleted file mode 100644 index d0b7509..0000000 --- a/src-tauri/src/cores.rs +++ /dev/null @@ -1,3 +0,0 @@ -enum Core{ - XRAY(String), -} \ No newline at end of file diff --git a/src-tauri/src/entity.rs b/src-tauri/src/entity.rs deleted file mode 100644 index 8b13789..0000000 --- a/src-tauri/src/entity.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src-tauri/src/exe.rs b/src-tauri/src/exe.rs deleted file mode 100644 index 3ac0d79..0000000 --- a/src-tauri/src/exe.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::io::{BufRead, BufReader}; -use std::path::PathBuf; -use std::process::{Child, Command, Stdio}; -use std::sync::{Arc, Mutex}; -use std::thread; - -pub struct Exe { - path: PathBuf, - args: Vec, - child: Arc>>, - pub pid: Arc>>, -} - -impl Exe { - pub fn new, S: Into>(path: P, args: Vec) -> Self { - Self { - path: path.into(), - args: args.into_iter().map(|s| s.into()).collect(), - child: Arc::new(Mutex::new(None)), - pid: Arc::new(Mutex::new(None)), - } - } - - pub fn start( - &mut self, - mut on_stdout: F, - mut on_stderr: E, - mut on_exit: X, - ) -> std::io::Result<()> - where - F: FnMut(String) + Send + 'static, - E: FnMut(String) + Send + 'static, - X: FnMut(i32) + Send + 'static, - { - let mut cmd = Command::new(&self.path); - cmd.args(&self.args) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - let mut child = cmd.spawn()?; - - // ✅ 保存 PID - let pid = child.id(); - { - *self.pid.lock().unwrap() = Some(pid); - } - - // ✅ 异步读取 stdout - if let Some(out) = child.stdout.take() { - let mut reader = BufReader::new(out); - let mut line = String::new(); - thread::spawn(move || { - while let Ok(n) = reader.read_line(&mut line) { - if n == 0 { - break; - } - on_stdout(line.clone()); - line.clear(); - } - }); - } - - if let Some(err) = child.stderr.take() { - let mut reader = BufReader::new(err); - let mut line = String::new(); - thread::spawn(move || { - while let Ok(n) = reader.read_line(&mut line) { - if n == 0 { - break; - } - on_stderr(line.clone()); - line.clear(); - } - }); - } - - let child_arc = self.child.clone(); - *child_arc.lock().unwrap() = Some(child); - - let pid_clone = self.pid.clone(); - thread::spawn(move || { - if let Some(mut c) = child_arc.lock().unwrap().take() { - match c.wait() { - Ok(status) => { - let code = status.code().unwrap_or(-1); - *pid_clone.lock().unwrap() = None; - on_exit(code); - } - Err(e) => { - eprintln!("Error waiting for process: {e}"); - *pid_clone.lock().unwrap() = None; - on_exit(-1); - } - } - } - }); - - Ok(()) - } - - pub fn kill(&self) -> std::io::Result<()> { - let mut guard = self.child.lock().unwrap(); - if let Some(child) = guard.as_mut() { - child.kill()?; - Ok(()) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "No running process", - )) - } - } - - pub fn is_alive(&self) -> bool { - let mut guard = self.child.lock().unwrap(); - if let Some(child) = guard.as_mut() { - match child.try_wait() { - Ok(Some(_)) => false, // 已退出 - Ok(None) => true, // 仍在运行 - Err(_) => false, - } - } else { - false - } - } - - pub fn get_pid(&self) -> Option { - *self.pid.lock().unwrap() - } -} diff --git a/src-tauri/src/group.rs b/src-tauri/src/group.rs deleted file mode 100644 index b8efdab..0000000 --- a/src-tauri/src/group.rs +++ /dev/null @@ -1,14 +0,0 @@ -#[tauri::command] -pub fn add_group( - group_name: String, - group_subscribe_url: Option, - group_arguments: Option, -) { - let message = match (&group_subscribe_url, &group_arguments) { - (Some(url), Some(args)) => format!("add_group: {} {} {}", group_name, url, args), - (Some(url), None) => format!("add_group: {} {}", group_name, url), - (None, Some(args)) => format!("add_group: {} {}", group_name, args), - (None, None) => format!("add_group: {}", group_name), - }; - println!("{}", message); -} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 706aa3f..7d96862 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,12 +1,8 @@ // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ -use crate::group::add_group; use crate::spary::spary_switch; use tauri_plugin_sql::{Migration, MigrationKind}; -mod exe; -mod group; mod spary; -mod cores; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { @@ -31,6 +27,9 @@ pub fn run() { } ]; tauri::Builder::default() + .plugin(tauri_plugin_process::init()) + .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_fs::init()) .plugin( tauri_plugin_sql::Builder::default() @@ -38,7 +37,7 @@ pub fn run() { .build(), ) .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![spary_switch, add_group]) + .invoke_handler(tauri::generate_handler![spary_switch]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 3357118..8ca9644 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,7 +1,5 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -mod entity; - fn main() { spary_lib::run() } diff --git a/src/components.d.ts b/src/components.d.ts index f187ea9..02102df 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -11,6 +11,7 @@ declare module 'vue' { AddGroup: typeof import('./components/nodeEdit/addGroup.vue')['default'] AddNode: typeof import('./components/nodeEdit/addNode.vue')['default'] LanguageSwitcher: typeof import('./components/LanguageSwitcher.vue')['default'] + MainConsole: typeof import('./components/index/mainConsole.vue')['default'] MainDrawer: typeof import('./components/index/mainDrawer.vue')['default'] NodeList: typeof import('./components/nodeEdit/nodeList.vue')['default'] NodesFloatButton: typeof import('./components/nodeEdit/nodesFloatButton.vue')['default'] diff --git a/src/components/index/mainConsole.vue b/src/components/index/mainConsole.vue new file mode 100644 index 0000000..6eeff0a --- /dev/null +++ b/src/components/index/mainConsole.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/components/index/mainDrawer.vue b/src/components/index/mainDrawer.vue index 9ebae0a..0c283ff 100644 --- a/src/components/index/mainDrawer.vue +++ b/src/components/index/mainDrawer.vue @@ -51,6 +51,12 @@ useI18n() + diff --git a/src/components/index/spary.vue b/src/components/index/spary.vue index 11a46be..40acbd8 100644 --- a/src/components/index/spary.vue +++ b/src/components/index/spary.vue @@ -13,18 +13,20 @@ + + + + \ No newline at end of file diff --git a/src/typed-router.d.ts b/src/typed-router.d.ts index 031a4a1..fcd75cd 100644 --- a/src/typed-router.d.ts +++ b/src/typed-router.d.ts @@ -21,6 +21,7 @@ declare module 'vue-router/auto-routes' { '/': RouteRecordInfo<'/', '/', Record, Record>, '/addGroup': RouteRecordInfo<'/addGroup', '/addGroup', Record, Record>, '/addNode/[groupId]': RouteRecordInfo<'/addNode/[groupId]', '/addNode/:groupId', { groupId: ParamValue }, { groupId: ParamValue }>, + '/coreLog': RouteRecordInfo<'/coreLog', '/coreLog', Record, Record>, '/nodes': RouteRecordInfo<'/nodes', '/nodes', Record, Record>, '/settings': RouteRecordInfo<'/settings', '/settings', Record, Record>, } @@ -48,6 +49,10 @@ declare module 'vue-router/auto-routes' { routes: '/addNode/[groupId]' views: never } + 'src/pages/coreLog.vue': { + routes: '/coreLog' + views: never + } 'src/pages/nodes.vue': { routes: '/nodes' views: never diff --git a/src/utils/coreBoot.ts b/src/utils/coreBoot.ts new file mode 100644 index 0000000..489b594 --- /dev/null +++ b/src/utils/coreBoot.ts @@ -0,0 +1,9 @@ +import {Command} from '@tauri-apps/plugin-shell'; + +export async function coreStart() { + let result = await Command.create('exec-sh', [ + '-c', + "echo 'Hello World!'", + ]).execute(); + console.log(result); +} \ No newline at end of file diff --git a/src/utils/bootArgs.ts b/src/utils/coreBootArgs.ts similarity index 97% rename from src/utils/bootArgs.ts rename to src/utils/coreBootArgs.ts index a33c2d7..d5d7f18 100644 --- a/src/utils/bootArgs.ts +++ b/src/utils/coreBootArgs.ts @@ -1,6 +1,10 @@ -import {writeTextFile, BaseDirectory, remove} from '@tauri-apps/plugin-fs'; +import {writeTextFile, BaseDirectory, remove, exists} from '@tauri-apps/plugin-fs'; export async function removeConfigFile(){ try { + const tokenExists = await exists('config.json', { baseDir: BaseDirectory.AppConfig }); + if (!tokenExists) { + return; + } await remove('config.json', { baseDir: BaseDirectory.AppConfig }); } catch (error) { // ignore diff --git a/yarn.lock b/yarn.lock index e373a25..882d7f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -697,6 +697,27 @@ dependencies: "@tauri-apps/api" "^2.8.0" +"@tauri-apps/plugin-os@~2": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-os/-/plugin-os-2.3.1.tgz#2b773d03916fcc272dc23b502f945251bebe64f8" + integrity sha512-ty5V8XDUIFbSnrk3zsFoP3kzN+vAufYzalJSlmrVhQTImIZa1aL1a03bOaP2vuBvfR+WDRC6NgV2xBl8G07d+w== + dependencies: + "@tauri-apps/api" "^2.8.0" + +"@tauri-apps/plugin-process@~2": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-process/-/plugin-process-2.3.0.tgz#43cb71f655ab774314c17344b2948e84d5331f8f" + integrity sha512-0DNj6u+9csODiV4seSxxRbnLpeGYdojlcctCuLOCgpH9X3+ckVZIEj6H7tRQ7zqWr7kSTEWnrxtAdBb0FbtrmQ== + dependencies: + "@tauri-apps/api" "^2.6.0" + +"@tauri-apps/plugin-shell@~2": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-shell/-/plugin-shell-2.3.1.tgz#e92fb07e7bcf48ba647e5c8ef78e2ea8b469db15" + integrity sha512-jjs2WGDO/9z2pjNlydY/F5yYhNsscv99K5lCmU5uKjsVvQ3dRlDhhtVYoa4OLDmktLtQvgvbQjCFibMl6tgGfw== + dependencies: + "@tauri-apps/api" "^2.8.0" + "@tauri-apps/plugin-sql@~2": version "2.3.0" resolved "https://registry.npmjs.org/@tauri-apps/plugin-sql/-/plugin-sql-2.3.0.tgz" @@ -1166,6 +1187,15 @@ clean-regexp@^1.0.0: dependencies: escape-string-regexp "^1.0.5" +clipboard@^2.0.4: + version "2.0.11" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.11.tgz#62180360b97dd668b6b3a84ec226975762a70be5" + integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw== + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" @@ -1246,6 +1276,11 @@ deep-is@^0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== + detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" @@ -1703,6 +1738,13 @@ globals@^16.3.0, globals@^16.4.0: resolved "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz" integrity sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw== +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + integrity sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw== + dependencies: + delegate "^3.1.2" + graphemer@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" @@ -2430,6 +2472,11 @@ scule@^1.3.0: resolved "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz" integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g== +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + integrity sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA== + semver@^7.3.5, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3, semver@^7.7.2: version "7.7.3" resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" @@ -2505,6 +2552,11 @@ sync-message-port@^1.0.0: dependencies: "@pkgr/core" "^0.2.9" +tiny-emitter@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + tinyexec@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz" @@ -2725,6 +2777,13 @@ vue-i18n@^11.1.12: "@intlify/shared" "11.1.12" "@vue/devtools-api" "^6.5.0" +vue-json-viewer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/vue-json-viewer/-/vue-json-viewer-3.0.4.tgz#c1d65515e57d4036defbbc18fa942d7fd5fb9a8b" + integrity sha512-pnC080rTub6YjccthVSNQod2z9Sl5IUUq46srXtn6rxwhW8QM4rlYn+CTSLFKXWfw+N3xv77Cioxw7B4XUKIbQ== + dependencies: + clipboard "^2.0.4" + vue-router@^4.5.1: version "4.5.1" resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz" @@ -2740,7 +2799,15 @@ vue-tsc@^3.0.7: "@volar/typescript" "2.4.23" "@vue/language-core" "3.1.1" -vue@^3.5.21: +vue-web-terminal@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/vue-web-terminal/-/vue-web-terminal-3.4.1.tgz#f62b33f5df5dc789e86509340286d94d2632d757" + integrity sha512-+gU28qClqvIZQlzokcvDS2tbFpGfIJKIPc6dvLm2VYX110c6NOh7mV1YrcUESnaE5VQ9DgxqtIbr1YraEA/GRQ== + dependencies: + vue "^3.3.4" + vue-json-viewer "^3.0.4" + +vue@^3.3.4, vue@^3.5.21: version "3.5.22" resolved "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz" integrity sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==