Skip to content

Commit 7d6d59c

Browse files
committed
chore(cli): bump version to 1.3.1 and improve process management
1 parent 5b3999c commit 7d6d59c

2 files changed

Lines changed: 43 additions & 76 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "llbot-cli"
3-
version = "1.3.0"
3+
version = "1.3.1"
44
edition = "2021"
55
description = "LLBot CLI launcher"
66

@@ -15,6 +15,7 @@ serde_json = "1"
1515
qrcode = "0.14"
1616
base64 = "0.22"
1717
ctrlc = "3"
18+
command-group = "5"
1819
flate2 = "1"
1920
tar = "0.4"
2021

src/main.rs

Lines changed: 41 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod pmhq_client;
44
mod qrcode_display;
55
mod updater;
66

7+
use command_group::{CommandGroup, GroupChild};
78
use pmhq_client::PMHQClient;
89
use qrcode_display::{print_qrcode_terminal, save_qrcode_image};
910
use std::env;
@@ -13,7 +14,7 @@ use std::net::TcpListener;
1314
use std::path::{Path, PathBuf};
1415
use std::process::{Command, Stdio};
1516
use std::sync::atomic::{AtomicBool, Ordering};
16-
use std::sync::Arc;
17+
use std::sync::{Arc, Mutex};
1718
use std::thread;
1819
use std::time::Duration;
1920

@@ -170,11 +171,11 @@ fn main() {
170171
.arg("--")
171172
.arg(format!("--pmhq-port={}", port));
172173

173-
let mut child = match cmd
174+
let mut child: GroupChild = match cmd
174175
.stdin(Stdio::null())
175176
.stdout(Stdio::piped())
176177
.stderr(Stdio::piped())
177-
.spawn()
178+
.group_spawn()
178179
{
179180
Ok(child) => child,
180181
Err(e) => {
@@ -183,45 +184,39 @@ fn main() {
183184
}
184185
};
185186

186-
let child_id = child.id();
187-
let qq_pid_cache = Arc::new(std::sync::atomic::AtomicU32::new(0));
188-
let qq_pid_for_cleanup = qq_pid_cache.clone();
187+
let child_arc: Arc<Mutex<Option<GroupChild>>> = Arc::new(Mutex::new(None));
188+
let child_for_handler = child_arc.clone();
189189

190190
ctrlc::set_handler(move || {
191-
let cached_pid = qq_pid_for_cleanup.load(Ordering::Relaxed);
192-
cleanup_and_exit(child_id, if cached_pid > 0 { Some(cached_pid) } else { None });
191+
if let Ok(mut guard) = child_for_handler.lock() {
192+
if let Some(ref mut c) = *guard {
193+
let _ = c.kill();
194+
}
195+
}
196+
std::process::exit(0);
193197
})
194198
.ok();
195199

196-
// 读取 pmhq stdout,解析 QQ PID
197-
let qq_pid_from_stdout = qq_pid_cache.clone();
198-
if let Some(stdout) = child.stdout.take() {
200+
let stdout = child.inner().stdout.take();
201+
let stderr = child.inner().stderr.take();
202+
203+
// 把 child 移入 Arc,供 ctrlc handler 使用
204+
*child_arc.lock().unwrap() = Some(child);
205+
let child_for_wait = child_arc.clone();
206+
207+
if let Some(stdout) = stdout {
199208
thread::spawn(move || {
200209
use std::io::{BufRead, BufReader};
201210
let reader = BufReader::new(stdout);
202211
for line in reader.lines() {
203212
if let Ok(line) = line {
204213
println!("{}", line);
205-
// 解析 "QQ 进程 PID: 12345" 或 "QQ进程PID: 12345"
206-
if line.contains("PID:") && line.contains("QQ") {
207-
if let Some(pos) = line.rfind("PID:") {
208-
let after_pid = &line[pos + 4..];
209-
let pid_str: String = after_pid.chars()
210-
.skip_while(|c| c.is_whitespace())
211-
.take_while(|c| c.is_ascii_digit())
212-
.collect();
213-
if let Ok(pid) = pid_str.parse::<u32>() {
214-
qq_pid_from_stdout.store(pid, Ordering::Relaxed);
215-
}
216-
}
217-
}
218214
}
219215
}
220216
});
221217
}
222218

223-
// 读取 pmhq stderr
224-
if let Some(stderr) = child.stderr.take() {
219+
if let Some(stderr) = stderr {
225220
thread::spawn(move || {
226221
use std::io::{BufRead, BufReader};
227222
let reader = BufReader::new(stderr);
@@ -239,15 +234,28 @@ fn main() {
239234

240235
start_login_listener(port, logged_in.clone(), qrcode_path, show_terminal_qr);
241236

242-
match child.wait() {
243-
Ok(status) => {
244-
if !status.success() {
245-
eprintln!("pmhq 退出,状态码: {:?}", status.code());
237+
// 等待子进程结束
238+
loop {
239+
thread::sleep(Duration::from_millis(100));
240+
if let Ok(mut guard) = child_for_wait.lock() {
241+
if let Some(ref mut c) = *guard {
242+
match c.try_wait() {
243+
Ok(Some(status)) => {
244+
if !status.success() {
245+
eprintln!("pmhq 退出,状态码: {:?}", status.code());
246+
}
247+
break;
248+
}
249+
Ok(None) => {}
250+
Err(e) => {
251+
eprintln!("等待 pmhq 失败: {}", e);
252+
break;
253+
}
254+
}
255+
} else {
256+
break;
246257
}
247258
}
248-
Err(e) => {
249-
eprintln!("等待 pmhq 失败: {}", e);
250-
}
251259
}
252260
}
253261

@@ -502,45 +510,3 @@ fn copy_dir_recursive(src: &Path, dst: &Path) -> std::io::Result<()> {
502510
}
503511
Ok(())
504512
}
505-
506-
#[cfg(target_os = "windows")]
507-
fn kill_process_tree(pid: u32) {
508-
let _ = Command::new("taskkill")
509-
.args(["/F", "/T", "/PID", &pid.to_string()])
510-
.stdout(Stdio::null())
511-
.stderr(Stdio::null())
512-
.status();
513-
}
514-
515-
#[cfg(not(target_os = "windows"))]
516-
fn kill_process_tree(pid: u32) {
517-
let _ = Command::new("kill")
518-
.args(["-TERM", &format!("-{}", pid)])
519-
.status();
520-
}
521-
522-
fn cleanup_and_exit(pmhq_pid: u32, qq_pid: Option<u32>) {
523-
// 先杀 QQ,再杀 pmhq(因为 taskkill /T 会终止整个进程树)
524-
if let Some(pid) = qq_pid {
525-
kill_process(pid);
526-
}
527-
528-
kill_process_tree(pmhq_pid);
529-
std::process::exit(0);
530-
}
531-
532-
#[cfg(target_os = "windows")]
533-
fn kill_process(pid: u32) {
534-
let _ = Command::new("taskkill")
535-
.args(["/F", "/PID", &pid.to_string()])
536-
.stdout(Stdio::null())
537-
.stderr(Stdio::null())
538-
.status();
539-
}
540-
541-
#[cfg(not(target_os = "windows"))]
542-
fn kill_process(pid: u32) {
543-
let _ = Command::new("kill")
544-
.args(["-9", &pid.to_string()])
545-
.status();
546-
}

0 commit comments

Comments
 (0)