@@ -6,13 +6,17 @@ use process_wrap::tokio::ProcessGroup;
66use process_wrap:: tokio:: { JobObject , KillOnDrop } ;
77#[ cfg( unix) ]
88use std:: os:: unix:: process:: ExitStatusExt ;
9+ use std:: sync:: Arc ;
910use std:: { process:: Stdio , time:: Duration } ;
1011use tauri:: { AppHandle , Manager , path:: BaseDirectory } ;
1112use tauri_plugin_store:: StoreExt ;
1213use tauri_specta:: Event ;
13- use tokio:: io:: { AsyncBufReadExt , BufReader } ;
14- use tokio:: process:: Command ;
15- use tokio:: sync:: { mpsc, oneshot} ;
14+ use tokio:: {
15+ io:: { AsyncBufRead , AsyncBufReadExt , BufReader } ,
16+ process:: Command ,
17+ sync:: { mpsc, oneshot} ,
18+ task:: JoinHandle ,
19+ } ;
1620use tokio_stream:: wrappers:: ReceiverStream ;
1721use tracing:: Instrument ;
1822
@@ -34,8 +38,8 @@ pub struct Config {
3438
3539#[ derive( Clone , Debug ) ]
3640pub enum CommandEvent {
37- Stdout ( Vec < u8 > ) ,
38- Stderr ( Vec < u8 > ) ,
41+ Stdout ( String ) ,
42+ Stderr ( String ) ,
3943 Error ( String ) ,
4044 Terminated ( TerminatedPayload ) ,
4145}
@@ -64,10 +68,11 @@ pub async fn get_config(app: &AppHandle) -> Option<Config> {
6468
6569 events
6670 . fold ( String :: new ( ) , async |mut config_str, event| {
67- if let CommandEvent :: Stdout ( stdout) = event
68- && let Ok ( s) = str:: from_utf8 ( & stdout)
69- {
70- config_str += s
71+ if let CommandEvent :: Stdout ( s) = & event {
72+ config_str += s. as_str ( )
73+ }
74+ if let CommandEvent :: Stderr ( s) = & event {
75+ config_str += s. as_str ( )
7176 }
7277
7378 config_str
@@ -317,9 +322,9 @@ pub fn spawn_command(
317322 cmd
318323 } ;
319324
320- cmd. stdin ( Stdio :: null ( ) ) ;
321325 cmd. stdout ( Stdio :: piped ( ) ) ;
322326 cmd. stderr ( Stdio :: piped ( ) ) ;
327+ cmd. stdin ( Stdio :: null ( ) ) ;
323328
324329 #[ cfg( windows) ]
325330 cmd. creation_flags ( 0x0800_0000 ) ;
@@ -337,32 +342,24 @@ pub fn spawn_command(
337342 }
338343
339344 let mut child = wrap. spawn ( ) ?;
340- let stdout = child. stdout ( ) . take ( ) ;
341- let stderr = child. stderr ( ) . take ( ) ;
345+ let guard = Arc :: new ( tokio:: sync:: RwLock :: new ( ( ) ) ) ;
342346 let ( tx, rx) = mpsc:: channel ( 256 ) ;
343347 let ( kill_tx, mut kill_rx) = mpsc:: channel ( 1 ) ;
344348
345- if let Some ( stdout) = stdout {
346- let tx = tx. clone ( ) ;
347- tokio:: spawn ( async move {
348- let mut lines = BufReader :: new ( stdout) . lines ( ) ;
349- while let Ok ( Some ( line) ) = lines. next_line ( ) . await {
350- let _ = tx. send ( CommandEvent :: Stdout ( line. into_bytes ( ) ) ) . await ;
351- }
352- } ) ;
353- }
354-
355- if let Some ( stderr) = stderr {
356- let tx = tx. clone ( ) ;
357- tokio:: spawn ( async move {
358- let mut lines = BufReader :: new ( stderr) . lines ( ) ;
359- while let Ok ( Some ( line) ) = lines. next_line ( ) . await {
360- let _ = tx. send ( CommandEvent :: Stderr ( line. into_bytes ( ) ) ) . await ;
361- }
362- } ) ;
363- }
349+ let stdout = spawn_pipe_reader (
350+ tx. clone ( ) ,
351+ guard. clone ( ) ,
352+ BufReader :: new ( child. stdout ( ) . take ( ) . unwrap ( ) ) ,
353+ CommandEvent :: Stdout ,
354+ ) ;
355+ let stderr = spawn_pipe_reader (
356+ tx. clone ( ) ,
357+ guard. clone ( ) ,
358+ BufReader :: new ( child. stderr ( ) . take ( ) . unwrap ( ) ) ,
359+ CommandEvent :: Stderr ,
360+ ) ;
364361
365- tokio:: spawn ( async move {
362+ tokio:: task :: spawn ( async move {
366363 let mut kill_open = true ;
367364 let status = loop {
368365 match child. try_wait ( ) {
@@ -394,6 +391,9 @@ pub fn spawn_command(
394391 let _ = tx. send ( CommandEvent :: Error ( err. to_string ( ) ) ) . await ;
395392 }
396393 }
394+
395+ stdout. abort ( ) ;
396+ stderr. abort ( ) ;
397397 } ) ;
398398
399399 let event_stream = ReceiverStream :: new ( rx) ;
@@ -404,9 +404,7 @@ pub fn spawn_command(
404404
405405fn signal_from_status ( status : std:: process:: ExitStatus ) -> Option < i32 > {
406406 #[ cfg( unix) ]
407- {
408- return status. signal ( ) ;
409- }
407+ return status. signal ( ) ;
410408
411409 #[ cfg( not( unix) ) ]
412410 {
@@ -442,12 +440,10 @@ pub fn serve(
442440 events
443441 . for_each ( move |event| {
444442 match event {
445- CommandEvent :: Stdout ( line_bytes) => {
446- let line = String :: from_utf8_lossy ( & line_bytes) ;
443+ CommandEvent :: Stdout ( line) => {
447444 tracing:: info!( "{line}" ) ;
448445 }
449- CommandEvent :: Stderr ( line_bytes) => {
450- let line = String :: from_utf8_lossy ( & line_bytes) ;
446+ CommandEvent :: Stderr ( line) => {
451447 tracing:: info!( "{line}" ) ;
452448 }
453449 CommandEvent :: Error ( err) => {
@@ -499,11 +495,7 @@ pub mod sqlite_migration {
499495 }
500496
501497 future:: ready ( match & event {
502- CommandEvent :: Stdout ( stdout) => {
503- let Ok ( s) = str:: from_utf8 ( stdout) else {
504- return future:: ready ( None ) ;
505- } ;
506-
498+ CommandEvent :: Stdout ( s) | CommandEvent :: Stderr ( s) => {
507499 if let Some ( s) = s. strip_prefix ( "sqlite-migration:" ) . map ( |s| s. trim ( ) ) {
508500 if let Ok ( progress) = s. parse :: < u8 > ( ) {
509501 let _ = SqliteMigrationProgress :: InProgress ( progress) . emit ( & app) ;
@@ -522,3 +514,41 @@ pub mod sqlite_migration {
522514 } )
523515 }
524516}
517+
518+ fn spawn_pipe_reader < F : Fn ( String ) -> CommandEvent + Send + Copy + ' static > (
519+ tx : mpsc:: Sender < CommandEvent > ,
520+ guard : Arc < tokio:: sync:: RwLock < ( ) > > ,
521+ pipe_reader : impl AsyncBufRead + Send + Unpin + ' static ,
522+ wrapper : F ,
523+ ) -> JoinHandle < ( ) > {
524+ tokio:: spawn ( async move {
525+ let _lock = guard. read ( ) . await ;
526+ let reader = BufReader :: new ( pipe_reader) ;
527+
528+ read_line ( reader, tx, wrapper) . await ;
529+ } )
530+ }
531+
532+ async fn read_line < F : Fn ( String ) -> CommandEvent + Send + Copy + ' static > (
533+ reader : BufReader < impl AsyncBufRead + Unpin > ,
534+ tx : mpsc:: Sender < CommandEvent > ,
535+ wrapper : F ,
536+ ) {
537+ let mut lines = reader. lines ( ) ;
538+ loop {
539+ let line = lines. next_line ( ) . await ;
540+
541+ match line {
542+ Ok ( s) => {
543+ if let Some ( s) = s {
544+ let _ = tx. clone ( ) . send ( wrapper ( s) ) . await ;
545+ }
546+ }
547+ Err ( e) => {
548+ let tx_ = tx. clone ( ) ;
549+ let _ = tx_. send ( CommandEvent :: Error ( e. to_string ( ) ) ) . await ;
550+ break ;
551+ }
552+ }
553+ }
554+ }
0 commit comments