@@ -4,6 +4,7 @@ mod pmhq_client;
44mod qrcode_display;
55mod updater;
66
7+ use command_group:: { CommandGroup , GroupChild } ;
78use pmhq_client:: PMHQClient ;
89use qrcode_display:: { print_qrcode_terminal, save_qrcode_image} ;
910use std:: env;
@@ -13,7 +14,7 @@ use std::net::TcpListener;
1314use std:: path:: { Path , PathBuf } ;
1415use std:: process:: { Command , Stdio } ;
1516use std:: sync:: atomic:: { AtomicBool , Ordering } ;
16- use std:: sync:: Arc ;
17+ use std:: sync:: { Arc , Mutex } ;
1718use std:: thread;
1819use 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