html terminal
Diffstat (limited to 'src/process.rs')
-rw-r--r--src/process.rs101
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")
+}