html terminal
remove panel
| -rw-r--r-- | Cargo.lock | 122 | ||||
| -rw-r--r-- | Cargo.toml | 5 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | build.rs | 28 | ||||
| -rw-r--r-- | html-src/panel.html | 180 | ||||
| -rw-r--r-- | src/bot/js.rs | 11 | ||||
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/process.rs | 51 | ||||
| -rw-r--r-- | src/server.rs | 47 | ||||
| -rw-r--r-- | src/websocket.rs | 73 |
10 files changed, 80 insertions, 440 deletions
@@ -9,19 +9,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aho-corasick" -version = "0.7.20" +name = "ahash" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ - "memchr", + "cfg-if", + "once_cell", + "version_check", ] [[package]] name = "aho-corasick" -version = "1.0.2" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -42,17 +44,6 @@ dependencies = [ ] [[package]] -name = "ansi-to-html" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7bd918cc0ff933f0e6cf48a8f74584818ea43e07d1fba1f9251bb3df2a37ca2" -dependencies = [ - "once_cell", - "regex", - "thiserror", -] - -[[package]] name = "anyhow" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -188,7 +179,7 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-rustls 0.23.4", - "tungstenite 0.17.3", + "tungstenite", "webpki-roots", ] @@ -212,7 +203,6 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", - "base64 0.21.2", "bitflags", "bytes", "futures-util", @@ -227,10 +217,8 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite", "tower", "tower-layer", "tower-service", @@ -458,7 +446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.12.3", "lock_api", "once_cell", "parking_lot_core", @@ -738,6 +726,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", + "bumpalo", +] + +[[package]] name = "hermit-abi" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -869,7 +867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1002,11 +1000,11 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4d9147754a49e80557df835eb59e743eab1bf75410a134f55dc4b9dbb692ad" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick", "css-minify", "lazy_static", "memchr", - "minify-js", + "minify-js 0.4.3", "rustc-hash", ] @@ -1017,7 +1015,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c300f90ba1138b5c5daf5d9441dc9bdc67b808aac22cf638362a2647bc213be4" dependencies = [ "lazy_static", - "parse-js", + "parse-js 0.10.3", +] + +[[package]] +name = "minify-js" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d6c512a82abddbbc13b70609cb2beff01be2c7afff534d6e5e1c85e438fc8b" +dependencies = [ + "lazy_static", + "parse-js 0.17.0", ] [[package]] @@ -1094,7 +1102,6 @@ dependencies = [ name = "panel" version = "0.1.0" dependencies = [ - "ansi-to-html", "anyhow", "async-std", "axum", @@ -1103,7 +1110,7 @@ dependencies = [ "futures-util", "itertools", "minify-html", - "minify-js", + "minify-js 0.5.6", "paste", "poise", "regex", @@ -1148,7 +1155,20 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30534759e6ad87aa144c396544747e1c25b1020bd133356fd758c8facec764e5" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick", + "lazy_static", + "memchr", +] + +[[package]] +name = "parse-js" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ec3b11d443640ec35165ee8f6f0559f1c6f41878d70330fe9187012b5935f02" +dependencies = [ + "aho-corasick", + "bumpalo", + "hashbrown 0.13.2", "lazy_static", "memchr", ] @@ -1313,8 +1333,6 @@ version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick 1.0.2", - "memchr", "regex-syntax", ] @@ -1584,17 +1602,6 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] name = "signal-hook-registry" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1802,18 +1809,6 @@ dependencies = [ ] [[package]] -name = "tokio-tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.18.0", -] - -[[package]] name = "tokio-util" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1915,25 +1910,6 @@ dependencies = [ ] [[package]] -name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] name = "typemap_rev" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6,13 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ansi-to-html = { version = "0.1.3", features = ["lazy-init"] } async-std = "1.12.0" axum = { version = "0.6.18", features = [ - "ws", "tokio", "http1", - "matched-path", ], default-features = false } futures = "0.3.28" paste = "1.0.12" @@ -37,7 +34,7 @@ serenity = { version = "0.11.5", features = [ poise = "0.5.5" anyhow = "1.0.71" regex = { version = "1.8.4", features = ["std"], default-features = false } -minify-js = "0.4.3" +minify-js = "0.5.6" itertools = "0.10.5" convert_case = "0.6.0" @@ -1,3 +1,3 @@ # panel -html terminal for connecting to game servers without ssh +links a mindustry server to discord @@ -1,25 +1,9 @@ -#![feature(utf8_chunks)] use std::fs; use std::io::prelude::*; use std::path::Path; use minify_html::{minify, Cfg}; -/// like [String::from_utf8_lossy] but instead of being lossy it panics -pub fn from_utf8(v: &[u8]) -> &str { - let mut iter = std::str::Utf8Chunks::new(v); - if let Some(chunk) = iter.next() { - let valid = chunk.valid(); - if chunk.invalid().is_empty() { - debug_assert_eq!(valid.len(), v.len()); - return valid; - } - } else { - return ""; - }; - unreachable!("invalid utf8") -} - pub fn process(input: impl AsRef<Path>) -> std::io::Result<()> { let mut f = fs::File::create(dbg!(Path::new("html").join(input.as_ref()))).unwrap(); let mut buf = vec![]; @@ -32,20 +16,12 @@ pub fn process(input: impl AsRef<Path>) -> std::io::Result<()> { ..Default::default() }, ); - let minified = from_utf8(&minified); - let minified = minified.replace( - "ws://localhost:4001/connect/", - &format!( - "{}", - std::env::var("URL").unwrap_or("ws://localhost:4001/connect/".to_string()) - ), - ); - f.write_all(minified.as_bytes()) + f.write_all(&minified) } fn main() -> std::io::Result<()> { if !Path::new("html").exists() { - std::fs::create_dir("html")?; + fs::create_dir("html")?; } for path in fs::read_dir("html-src")? { diff --git a/html-src/panel.html b/html-src/panel.html deleted file mode 100644 index 982b465..0000000 --- a/html-src/panel.html +++ /dev/null @@ -1,180 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta charset="UTF-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="icon" href="favicon.ico"> - <style> - body { - background-color: grey; - background-attachment: fixed; - background-position: center; - background-repeat: no-repeat; - height: 100%; - background-color: rgb(36, 42, 49); - margin: 0; - } - - h1 { - text-align: center; - color: wheat; - font-family: 'Ubuntu', sans-serif; - font-weight: bolder; - font-size: 1em; - vertical-align: middle; - } - - #id, - #command { - border: 2px solid rgb(196, 196, 194); - border-radius: 5px; - padding: 2px; - font-family: 'Ubuntu', sans-serif; - background-color: rgb(47, 55, 64); - color: wheat; - } - - #logs:focus { - outline: none !important; - } - - #id:focus, - #command:focus { - font-size: 1rem; - border: 2px solid rgb(237, 237, 233); - outline: none !important; - } - - #id { - font-size: 0.5rem; - } - - #command { - font-size: 1rem; - margin: 5px 0px 5px 0px; - } - - #command, - #logs { - display: block; - width: 900px; - box-sizing: border-box; - } - - #logs { - border-radius: 5px; - background-repeat: no-repeat; - height: 400px; - background-color: rgb(47, 55, 64); - border: 2px solid rgb(196, 196, 194); - overflow: scroll; - font-family: Ubuntu, sans-serif; - color: wheat; - font-size: 0.7rem; - padding: 2px; - letter-spacing: 1px; - line-height: 7px; - } - - .center { - display: flex; - justify-content: center; - } - - .vert { - align-items: center; - } - </style> - <title>panel</title> -</head> - -<body> - <div class="center"> - <div class="vert"> - <div id="logs" cols="30" rows="10" readonly></div> - <input id="command" type="text" placeholder="js killall" disabled="true"> - <input id="id" type="password" placeholder="password"> - </div> - </div> - <script> - const input = document.querySelector("#command") - const textarea = document.querySelector("#logs") - const id = document.querySelector("#id") - let text = "" - - function tex(t) { - text = t - render() - } - let w, h = 0 - textarea.onmousedown = function (e) { - w = e.offsetWidth; - h = e.offsetHeight; - } - textarea.onmouseup = function (e) { - if (e.offsetWidth === w && e.offsetHeight === h) { - return - } - render() - } - - id.onkeydown = function (e) { - if (e.key == "Enter") { - if (text != "") { - tex("connecting") - } - id.disabled = true - input.disabled = false - const websocket = new WebSocket("ws://localhost:4001/connect/" + id.value) - - websocket.onopen = function () { - console.log("connection opened") - tex("") - } - - websocket.onclose = function () { - console.log("connection closed"); - id.disabled = false - input.disabled = true - tex("disconnected") - } - - websocket.onmessage = function (e) { - console.log("< " + e.data) - tex(text + e.data + "<br></br>") - } - - input.onkeydown = function (e) { - if (e.key == "Enter") { - console.log("> " + input.value) - websocket.send(input.value) - input.value = "" - } - } - } - } - - function render() { - // let data = ` - // <svg xmlns="http://www.w3.org/2000/svg" width="${textarea.offsetWidth}" height="${textarea.offsetHeight}"> - // <foreignObject width="100%" height="100%"> - // <div xmlns="http://www.w3.org/1999/xhtml" - // style="font-family:Ubuntu, sans-serif;color:wheat;font-size:1rem;padding:2px;letter-spacing:1px"> - // ${text} - // </div> - // </foreignObject> - // </svg>` - // textarea.style.backgroundImage = "url(" + - // URL.createObjectURL(new Blob([data], { type: 'image/svg+xml' })) - // + ")" - textarea.innerHTML = text - textarea.scrollTop = textarea.scrollHeight - } - - </script> - -</body> - -</html>
\ No newline at end of file diff --git a/src/bot/js.rs b/src/bot/js.rs index 38f839d..b4940ff 100644 --- a/src/bot/js.rs +++ b/src/bot/js.rs @@ -1,6 +1,6 @@ use super::{Context, Result}; use crate::{return_next, send_ctx}; -use minify_js::TopLevelMode; +use minify_js::{Session, TopLevelMode}; use regex::Regex; use std::sync::LazyLock; @@ -13,7 +13,14 @@ fn parse_js(from: &str) -> Result<String> { let script = mat.get(2).unwrap().as_str(); let mut out = vec![]; Ok( - if minify_js::minify(TopLevelMode::Global, script.into(), &mut out).is_ok() { + if minify_js::minify( + &Session::new(), + TopLevelMode::Global, + script.as_bytes(), + &mut out, + ) + .is_ok() + { String::from_utf8_lossy(&out).to_string() } else { script.replace('\n', ";") diff --git a/src/main.rs b/src/main.rs index ee1fc78..aa78c35 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,6 @@ mod bot; mod process; mod server; mod webhook; -mod websocket; use process::*; use server::*; diff --git a/src/process.rs b/src/process.rs index da36818..302a173 100644 --- a/src/process.rs +++ b/src/process.rs @@ -1,5 +1,3 @@ -use ansi_to_html::convert_escaped; -use std::sync::Arc; use std::time::Duration; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpStream; @@ -7,12 +5,10 @@ use tokio::sync::broadcast; use tokio::sync::broadcast::error::TryRecvError; use tokio::task::JoinHandle; -use crate::server::State; pub struct Process { inner: TcpStream, input: Option<broadcast::Receiver<String>>, - html_output: Option<broadcast::Sender<String>>, - plain_output: Option<broadcast::Sender<String>>, + output: Option<broadcast::Sender<String>>, } impl Process { @@ -23,8 +19,7 @@ impl Process { Self { inner: stream, input: None, - html_output: None, - plain_output: None, + output: None, } } @@ -33,30 +28,19 @@ impl Process { self } - pub fn html_output(mut self, output: broadcast::Sender<String>) -> Self { - self.html_output = Some(output); + pub fn output(mut self, output: broadcast::Sender<String>) -> Self { + self.output = Some(output); self } - pub fn plain_output(mut self, output: broadcast::Sender<String>) -> Self { - self.plain_output = Some(output); - self - } - - pub fn with_state(self, state: &Arc<State>) -> Self { - self.html_output(state.stdout_html.clone()) - .plain_output(state.stdout_plain.clone()) - } - pub fn link(mut self) -> JoinHandle<()> { define_print!("process"); let mut input = self.input.unwrap(); - let html_output = self.html_output.unwrap(); - let plain_output = self.plain_output.unwrap(); + let output = self.output.unwrap(); tokio::spawn(async move { let mut stdout = [0; 4096]; loop { - if html_output.receiver_count() + plain_output.receiver_count() == 0 { + if output.receiver_count() == 0 { async_std::task::sleep(Duration::from_millis(500)).await; continue; } @@ -84,27 +68,12 @@ impl Process { for line in string.lines() { output!("{line}"); } - if plain_output.receiver_count() > 0 { - let stripped = - String::from_utf8_lossy(&strip_ansi_escapes::strip(&string).unwrap()) - .into_owned(); - plain_output.send(stripped).unwrap(); - } - if html_output.receiver_count() > 0 { - html_output.send(ansi2html(&string)).unwrap(); - } + let stripped = + String::from_utf8_lossy(&strip_ansi_escapes::strip(&string).unwrap()) + .into_owned(); + output.send(stripped).unwrap(); 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") -} diff --git a/src/server.rs b/src/server.rs index 3426530..50b5cbd 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,37 +1,27 @@ use crate::bot::Bot; use crate::process::Process; -use crate::websocket::WebSocket; use axum::{ - extract::{ - ws::{Message, WebSocketUpgrade}, - Path, State as StateW, - }, http::header::CONTENT_TYPE, - response::{AppendHeaders, Html, IntoResponse}, + response::{AppendHeaders, Html}, routing::get, Router, Server as AxumServer, }; -use futures::sink::SinkExt; + use std::{net::SocketAddr, sync::Arc}; use tokio::sync::broadcast; +// its a arced arcs pub struct State { // sent from the process to the websockets - pub stdout_html: broadcast::Sender<String>, - pub stdout_plain: broadcast::Sender<String>, + pub stdout: broadcast::Sender<String>, // sent to the process pub stdin: broadcast::Sender<String>, } impl State { fn new(stdin: broadcast::Sender<String>) -> Self { - let (stdout_html, _) = broadcast::channel(16); - let (stdout_plain, _) = broadcast::channel(2); - Self { - stdin, - stdout_html, - stdout_plain, - } + let (stdout, _) = broadcast::channel(2); + Self { stdin, stdout } } } @@ -68,10 +58,8 @@ impl Server { let state = Arc::new(State::new(stdin_tx)); let router = Router::new() .route("/", html!(index)) - .route("/panel", html!(panel)) .route("/plaguess.png", png!(plaguess)) .route("/favicon.ico", png!(logo32)) - .route("/connect/:id", get(connect_ws)) .with_state(state.clone()); let mut server_handle = tokio::spawn(async move { AxumServer::bind(&addr) @@ -79,8 +67,8 @@ impl Server { .await .unwrap() }); - let mut process_handle = proc.input(stdin).with_state(&state).link(); - Bot::spawn(state.stdout_plain.subscribe(), state.stdin.clone()).await; + let mut process_handle = proc.input(stdin).output(state.stdout.clone()).link(); + Bot::spawn(state.stdout.subscribe(), state.stdin.clone()).await; tokio::select! { _ = (&mut server_handle) => process_handle.abort(), _ = (&mut process_handle) => server_handle.abort(), @@ -88,22 +76,3 @@ impl Server { panic!("oh no"); } } - -fn matches(id: &str) -> bool { - std::env::var("ID").as_deref().unwrap_or("4") == id -} - -async fn connect_ws( - ws: WebSocketUpgrade, - StateW(state): StateW<Arc<State>>, - Path(id): Path<String>, -) -> impl IntoResponse { - ws.on_upgrade(|socket| async move { - if !matches(&id) { - let mut s = futures::stream::StreamExt::split(socket).0; - let _ = s.send(Message::Text("correct id".to_string())).await; - return; - } - tokio::spawn(WebSocket::spawn(socket, state)); - }) -} diff --git a/src/websocket.rs b/src/websocket.rs deleted file mode 100644 index df614f4..0000000 --- a/src/websocket.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::server::State; -use axum::extract::ws::{Message, WebSocket as RealWebSocket}; -use futures_util::SinkExt; -use std::{ - sync::Arc, - time::{Duration, Instant}, -}; -use tokio::{sync::broadcast::error::TryRecvError, task::JoinHandle}; -use tokio_stream::StreamExt; -pub struct WebSocket(JoinHandle<()>); -impl WebSocket { - pub async fn spawn(stream: RealWebSocket, state: Arc<State>) { - let (mut sender, mut reciever) = futures::stream::StreamExt::split(stream); - let mut stdout = state.stdout_html.subscribe(); - dummy_print!("websocket"); - let mut last: Option<Instant> = None; - let mut waiting: usize = 0; - loop { - let out = stdout.try_recv(); - let now = Instant::now(); - match out { - Err(e) => match e { - TryRecvError::Closed => fail!("closed"), - TryRecvError::Lagged(_) => continue, // no delay - _ => { - if let Some(earlier) = last { - let since = now.duration_since(earlier).as_millis(); - if since > 200 || waiting > 15 { - last.take(); - sender.flush().await.unwrap(); - waiting = 0; - flush!(); - } - } - } - }, - Ok(m) => { - #[allow(unused_variables)] - for line in m.lines() { - input!("{line}"); - if let Err(e) = sender.feed(Message::Text(line.to_owned())).await { - fail!("{e}"); - }; - waiting += 1; - } - last = Some(now); - } - } - match tokio::select! { - next = reciever.next() => next, - _ = async_std::task::sleep(Duration::from_millis(20)) => continue, - } { - Some(r) => match r { - Ok(m) => { - if let Message::Text(m) = m { - output!("{m}"); - state.stdin.send(m).unwrap(); - } - } - #[allow(unused_variables)] - Err(e) => { - fail!("{e}"); - } - }, - None => { - nooutput!(); - } - } - async_std::task::sleep(Duration::from_millis(20)).await; - continue; - } - } -} |