diff --git a/Cargo.lock b/Cargo.lock index f387f71..a6592b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,6 +118,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" + [[package]] name = "byteorder" version = "1.5.0" @@ -195,6 +201,31 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388979d208a049ffdfb22fa33b9c81942215b940910bccfe258caeb25d125cb3" +dependencies = [ + "serde", +] + +[[package]] +name = "femme" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc04871e5ae3aa2952d552dae6b291b3099723bf779a8054281c1366a54613ef" +dependencies = [ + "cfg-if", + "js-sys", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "fnv" version = "1.0.7" @@ -450,6 +481,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "js-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.153" @@ -477,6 +517,10 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "serde", + "value-bag", +] [[package]] name = "memchr" @@ -744,6 +788,8 @@ name = "sandy" version = "0.1.0" dependencies = [ "askama", + "femme", + "log", "rand", "serde", "serde_json", @@ -784,6 +830,15 @@ dependencies = [ "syn 2.0.49", ] +[[package]] +name = "serde_fmt" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4" +dependencies = [ + "serde", +] + [[package]] name = "serde_json" version = "1.0.113" @@ -875,6 +930,84 @@ dependencies = [ "warp", ] +[[package]] +name = "sval" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a2386bea23a121e4e72450306b1dd01078b6399af11b93897bf84640a28a59" + +[[package]] +name = "sval_buffer" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16c047898a0e19002005512243bc9ef1c1037aad7d03d6c594e234efec80795" +dependencies = [ + "sval", + "sval_ref", +] + +[[package]] +name = "sval_dynamic" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74fb116e2ecdcb280b0108aa2ee4434df50606c3208c47ac95432730eaac20c" +dependencies = [ + "sval", +] + +[[package]] +name = "sval_fmt" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10837b4f0feccef271b2b1c03784e08f6d0bb6d23272ec9e8c777bfadbb8f1b8" +dependencies = [ + "itoa", + "ryu", + "sval", +] + +[[package]] +name = "sval_json" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891f5ecdf34ce61a8ab2d10f9cfdc303347b0afec4dad6702757419d2d8312a9" +dependencies = [ + "itoa", + "ryu", + "sval", +] + +[[package]] +name = "sval_nested" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63fcffb4b79c531f38e3090788b64f3f4d54a180aacf02d69c42fa4e4bf284c3" +dependencies = [ + "sval", + "sval_buffer", + "sval_ref", +] + +[[package]] +name = "sval_ref" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af725f9c2aa7cec4ca9c47da2cc90920c4c82d3fa537094c66c77a5459f5809d" +dependencies = [ + "sval", +] + +[[package]] +name = "sval_serde" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7589c649a03d21df40b9a926787d2c64937fa1dccec8d87c6cd82989a2e0a4" +dependencies = [ + "serde", + "sval", + "sval_nested", +] + [[package]] name = "syn" version = "1.0.109" @@ -1109,6 +1242,42 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "value-bag" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" +dependencies = [ + "value-bag-serde1", + "value-bag-sval2", +] + +[[package]] +name = "value-bag-serde1" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede32f342edc46e84bd41fd394ce2192b553de11725dd83b6223150610c21b44" +dependencies = [ + "erased-serde", + "serde", + "serde_fmt", +] + +[[package]] +name = "value-bag-sval2" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0024e44b25144c2f4d0ed35d39688e0090d57753e20fef38d08e0c1a40bdf23d" +dependencies = [ + "sval", + "sval_buffer", + "sval_dynamic", + "sval_fmt", + "sval_json", + "sval_ref", + "sval_serde", +] + [[package]] name = "version_check" version = "0.9.4" @@ -1161,6 +1330,72 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.49", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.49", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" + +[[package]] +name = "web-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 61a9f20..013ae4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] askama = "0.12.1" +femme = "2.2.1" +log = "0.4.20" rand = "0.8.5" serde = { version = "1.0.196", features = ["derive"] } serde_json = "1.0.113" diff --git a/src/executor.rs b/src/executor.rs index cefbed1..18ea100 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -15,7 +15,7 @@ pub fn executors() -> Vec> { } pub fn executors_id() -> Vec { - executors() + filter_unavailable(&executors()) .iter() .map(|x| x.id()) .collect() @@ -27,7 +27,15 @@ pub fn get_executor<'a, T: Into>(id: T, executors: &'a Vec(executors: &'a Vec>) -> Vec<&Box> { + executors + .iter() + .filter(|x| x.available()) + .collect() +} + pub trait Executor { fn id(&self) -> String; fn exec(&self, code: String) -> Result; + fn available(&self) -> bool; } \ No newline at end of file diff --git a/src/executor/helper.rs b/src/executor/helper.rs index 6bed093..0df2e5b 100644 --- a/src/executor/helper.rs +++ b/src/executor/helper.rs @@ -1,4 +1,4 @@ -use std::{fs::create_dir_all, io::Read, process::{ChildStdout, ExitStatus}}; +use std::{env, fs::{self, create_dir_all}, io::Read, process::{ChildStdout, ExitStatus}}; use rand::{distributions::Alphanumeric, Rng, thread_rng}; @@ -41,4 +41,26 @@ pub fn get_stdout(stdout: Option) -> Result { }; Ok(ret) +} + + +pub fn cmd_exists, B: From>(program: T) -> B { + let program: String = program.into(); + + if let Ok(path) = env::var("PATH") { + const SEP: char = { + if cfg!(unix) { + ':' + } else { + ';' + } + }; + for p in path.split(SEP) { + let p_str = format!("{}/{}", p, program); + if fs::metadata(p_str).is_ok() { + return true.into(); + } + } + } + false.into() } \ No newline at end of file diff --git a/src/executor/javascript.rs b/src/executor/javascript.rs index e13bbfa..13f2531 100644 --- a/src/executor/javascript.rs +++ b/src/executor/javascript.rs @@ -6,9 +6,14 @@ use super::Executor; use super::helper::*; +#[derive(Debug, Clone, Copy)] pub struct NodeJSExecutor {} impl Executor for NodeJSExecutor { + fn available(&self) -> bool { + cmd_exists("node") + } + fn id(&self) -> String { "javascript".into() } diff --git a/src/executor/php.rs b/src/executor/php.rs index 38cc157..52bb443 100644 --- a/src/executor/php.rs +++ b/src/executor/php.rs @@ -10,6 +10,10 @@ use super::helper::*; pub struct PhpExecutor {} impl Executor for PhpExecutor { + fn available(&self) -> bool { + cmd_exists("php") + } + fn id(&self) -> String { "php".into() } diff --git a/src/executor/python.rs b/src/executor/python.rs index 37489c4..70e4b47 100644 --- a/src/executor/python.rs +++ b/src/executor/python.rs @@ -11,6 +11,34 @@ use super::helper::*; pub struct PythonExecutor {} impl Executor for PythonExecutor { + fn available(&self) -> bool { + let cmd_ok = cmd_exists("python"); + if cmd_ok { + let version_check = + Command::new("python") + .arg("--version") + .stdout(Stdio::piped()) + .spawn(); + if let Ok(version_check) = version_check { + if let Some(mut sout) = version_check.stdout { + let mut buf = String::new(); + let res = sout.read_to_string(&mut buf); + if res.is_err() { + return false; + } + + let is_py3 = buf.starts_with("Python 3"); + if ! is_py3 { + log::warn!("`python` command is not a Python 3 interpreter.") + } + return is_py3 + } + } + } + + false + } + fn id(&self) -> String { "python".into() } diff --git a/src/main.rs b/src/main.rs index de78901..a99c6bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::{fs::create_dir_all, net::SocketAddr, process::Stdio}; use web::state::{SharedState, TemplateState}; -use executor::executors_id; +use executor::{executors, executors_id, Executor}; mod web; pub mod executor; @@ -21,10 +21,34 @@ fn check() { if create_dir_all("/tmp/sandy-tmp").is_err() { panic!("Cannot create temporary directory on /tmp/sandy-tmp"); } + + let execs = executors(); + let available = execs + .iter() + .map(|x| { + if ! x.available() { + log::warn!("{} is not available in this environment!", x.id()) + } + x + }) + .filter(|x| x.available()) + .collect::>>() + .len(); + + if available == 0 { + panic!("No executors are available."); + } } #[tokio::main] async fn main() { + + if cfg!(debug_assertions) { + femme::with_level(log::LevelFilter::Debug) + } else { + femme::with_level(log::LevelFilter::Info) + } + check(); let state = SharedState {