feat(core): Added core startup and debugging features

- Introduced the tauri-plugin-os, tauri-plugin-shell, and tauri-plugin-process plugins
- Added the coreStart function to execute shell commands to start the core
- Added the coreLog page and MainConsole component for debugging output
- Introduced vue-web-terminal to implement a terminal interface
- Removed the old Exe and Group modules and related code
This commit is contained in:
2025-10-24 09:36:10 +08:00
parent 462f70f35d
commit e4f67f0f76
20 changed files with 179 additions and 163 deletions

View File

@@ -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"

View File

@@ -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
}
]
}
]
}

View File

@@ -1,3 +0,0 @@
enum Core{
XRAY(String),
}

View File

@@ -1 +0,0 @@

View File

@@ -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<String>,
child: Arc<Mutex<Option<Child>>>,
pub pid: Arc<Mutex<Option<u32>>>,
}
impl Exe {
pub fn new<P: Into<PathBuf>, S: Into<String>>(path: P, args: Vec<S>) -> 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<F, E, X>(
&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<u32> {
*self.pid.lock().unwrap()
}
}

View File

@@ -1,14 +0,0 @@
#[tauri::command]
pub fn add_group(
group_name: String,
group_subscribe_url: Option<String>,
group_arguments: Option<String>,
) {
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);
}

View File

@@ -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");
}

View File

@@ -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()
}