Add stdout/stderr printing support to UIThread

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2022-06-19 00:45:31 +10:00
parent c33f195d5f
commit ac492e6d8b
No known key found for this signature in database
GPG key ID: 591C0B03040416D6

View file

@ -1,14 +1,26 @@
use std::io::{self, BufRead, Write}; use std::io::{self, BufRead, Write};
use bytes::Bytes;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::task::spawn_blocking; use tokio::task::spawn_blocking;
use crate::BinstallError; use crate::BinstallError;
pub(super) enum UIRequest {
/// Request user confirmation
Confirm,
/// Print to stdout
PrintToStdout(Bytes),
/// Print to stderr
PrintToStderr(Bytes),
/// Flush stdout
FlushStdout,
}
#[derive(Debug)] #[derive(Debug)]
struct UIThreadInner { struct UIThreadInner {
/// Request for confirmation /// Request for confirmation
request_tx: mpsc::Sender<()>, request_tx: mpsc::Sender<UIRequest>,
/// Confirmation /// Confirmation
confirm_rx: mpsc::Receiver<Result<(), BinstallError>>, confirm_rx: mpsc::Receiver<Result<(), BinstallError>>,
@ -23,35 +35,39 @@ impl UIThreadInner {
// This task should be the only one able to // This task should be the only one able to
// access stdin // access stdin
let mut stdin = io::stdin().lock(); let mut stdin = io::stdin().lock();
let mut stdout = io::stdout().lock();
let mut stderr = io::stderr().lock();
let mut input = String::with_capacity(16); let mut input = String::with_capacity(16);
loop { loop {
if request_rx.blocking_recv().is_none() { match request_rx.blocking_recv() {
break; Some(UIRequest::Confirm) => {
} let res = loop {
writeln!(&mut stdout, "Do you wish to continue? yes/[no]").unwrap();
write!(&mut stdout, "? ").unwrap();
stdout.flush().unwrap();
// Lock stdout so that nobody can interfere input.clear();
// with confirmation. stdin.read_line(&mut input).unwrap();
let mut stdout = io::stdout().lock();
let res = loop { match input.as_str().trim() {
writeln!(&mut stdout, "Do you wish to continue? yes/[no]").unwrap(); "yes" | "y" | "YES" | "Y" => break Ok(()),
write!(&mut stdout, "? ").unwrap(); "no" | "n" | "NO" | "N" | "" => {
stdout.flush().unwrap(); break Err(BinstallError::UserAbort)
}
_ => continue,
}
};
input.clear(); confirm_tx
stdin.read_line(&mut input).unwrap(); .blocking_send(res)
.expect("entry exits when confirming request")
match input.as_str().trim() {
"yes" | "y" | "YES" | "Y" => break Ok(()),
"no" | "n" | "NO" | "N" | "" => break Err(BinstallError::UserAbort),
_ => continue,
} }
}; Some(UIRequest::PrintToStdout(output)) => stdout.write_all(&output).unwrap(),
Some(UIRequest::PrintToStderr(output)) => stderr.write_all(&output).unwrap(),
confirm_tx Some(UIRequest::FlushStdout) => stdout.flush().unwrap(),
.blocking_send(res) None => break,
.expect("entry exits when confirming request"); }
} }
}); });
@ -63,7 +79,7 @@ impl UIThreadInner {
async fn confirm(&mut self) -> Result<(), BinstallError> { async fn confirm(&mut self) -> Result<(), BinstallError> {
self.request_tx self.request_tx
.send(()) .send(UIRequest::Confirm)
.await .await
.map_err(|_| BinstallError::UserAbort)?; .map_err(|_| BinstallError::UserAbort)?;