html terminal
Diffstat (limited to 'src/process.rs')
| -rw-r--r-- | src/process.rs | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/process.rs b/src/process.rs new file mode 100644 index 0000000..de30047 --- /dev/null +++ b/src/process.rs @@ -0,0 +1,101 @@ +use ansi_to_html::convert_escaped; +use std::process::Stdio; +use std::{ffi::OsString, time::Duration}; +use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader}; +use tokio::process::{Child, ChildStdin, ChildStdout, Command}; +use tokio::sync::broadcast; +use tokio::sync::broadcast::error::TryRecvError; +use tokio::task::JoinHandle; +pub struct Process { + _inner: Child, + input: Option<broadcast::Receiver<String>>, + output: Option<broadcast::Sender<String>>, + stdout: BufReader<ChildStdout>, + stdin: ChildStdin, +} + +impl Process { + /// spawns the server + #[must_use] + pub fn spawn(server_dir: OsString) -> Self { + let mut p = Command::new("bash") + .arg("run.sh") + .current_dir(server_dir) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("failed to spawn"); + + Self { + // mindus doesnt output stderr + stdout: BufReader::new(p.stdout.take().unwrap()), + stdin: p.stdin.take().unwrap(), + _inner: p, + input: None, + output: None, + } + } + + pub fn input(mut self, input: broadcast::Receiver<String>) -> Self { + self.input = Some(input); + return self; + } + + pub fn output(mut self, output: broadcast::Sender<String>) -> Self { + self.output = Some(output); + return self; + } + + pub fn link(mut self) -> JoinHandle<()> { + define_print!("process"); + let mut input = self.input.unwrap(); + let output = self.output.unwrap(); + tokio::spawn(async move { + let mut stdout = [0; 4096]; + loop { + nextiter!(); + if output.receiver_count() == 0 { + async_std::task::sleep(Duration::from_millis(500)).await; + cont!(); + } + match input.try_recv() { + Err(e) => match e { + TryRecvError::Empty => noinput!(), + TryRecvError::Closed => fail!("closed"), + TryRecvError::Lagged(_) => noinput!("lagged"), + }, + Ok(mut s) => { + input!("{s}"); + s += "\n"; + self.stdin.write_all(s.as_bytes()).await.unwrap(); + self.stdin.flush().await.unwrap(); + } + } + + let string = { + let n = tokio::select! { + n = {self.stdout.read(&mut stdout)} => n.unwrap(), + _ = async_std::task::sleep(Duration::from_millis(500)) => cont!() + }; + String::from_utf8_lossy(&stdout[..n]).into_owned() + }; + for line in string.lines() { + output!("{line}"); + output.send(ansi2html(&line)).unwrap(); + } + nooutput!(); + async_std::task::sleep(Duration::from_millis(500)).await; + } + }) + } +} + +/// for dark theme +fn ansi2html(ansi: &str) -> String { + convert_escaped(ansi) + .unwrap() + .replace("#555", "#a4a4a0") + .replace("#55f", "#7486fd") + .replace("#fff", "wheat") + .replace("#a00", "#d05047") +} |