Skip to content

Commit 4025b65

Browse files
authored
desktop: replicate tauri-plugin-shell logic (anomalyco#13986)
1 parent 7379903 commit 4025b65

1 file changed

Lines changed: 74 additions & 44 deletions

File tree

  • packages/desktop/src-tauri/src

packages/desktop/src-tauri/src/cli.rs

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ use process_wrap::tokio::ProcessGroup;
66
use process_wrap::tokio::{JobObject, KillOnDrop};
77
#[cfg(unix)]
88
use std::os::unix::process::ExitStatusExt;
9+
use std::sync::Arc;
910
use std::{process::Stdio, time::Duration};
1011
use tauri::{AppHandle, Manager, path::BaseDirectory};
1112
use tauri_plugin_store::StoreExt;
1213
use 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+
};
1620
use tokio_stream::wrappers::ReceiverStream;
1721
use tracing::Instrument;
1822

@@ -34,8 +38,8 @@ pub struct Config {
3438

3539
#[derive(Clone, Debug)]
3640
pub 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

405405
fn 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

Comments
 (0)