Bottleneck Mass grave update< CAUSE IM A GOAT with No life please help me i need a life
This commit is contained in:
+227
-93
@@ -1,8 +1,8 @@
|
||||
use anyhow::{Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::time::Duration;
|
||||
use std::io::Write;
|
||||
use std::time::Duration;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct ExecutionResult {
|
||||
@@ -22,48 +22,54 @@ pub struct ScriptExecution {
|
||||
pub result: ExecutionResult,
|
||||
}
|
||||
|
||||
pub fn execute_command(cmd: &str, args: &[&str], timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
let _start = std::time::Instant::now();
|
||||
let mut child = Command::new(cmd)
|
||||
pub async fn execute_command(
|
||||
cmd: &str,
|
||||
args: &[&str],
|
||||
timeout_secs: u64,
|
||||
) -> Result<ExecutionResult> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
let mut child = tokio::process::Command::new(cmd)
|
||||
.args(args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.with_context(|| format!("Failed to spawn: {} {}", cmd, args.join(" ")))?;
|
||||
|
||||
let timeout = Duration::from_secs(timeout_secs);
|
||||
let mut elapsed = Duration::ZERO;
|
||||
let check_interval = Duration::from_millis(50);
|
||||
|
||||
loop {
|
||||
match child.try_wait()? {
|
||||
Some(status) => {
|
||||
let stdout = std::io::read_to_string(child.stdout.take().unwrap()).unwrap_or_default();
|
||||
let stderr = std::io::read_to_string(child.stderr.take().unwrap()).unwrap_or_default();
|
||||
return Ok(ExecutionResult {
|
||||
command: format!("{} {}", cmd, args.join(" ")),
|
||||
exit_code: status.code(),
|
||||
stdout: stdout.trim().to_string(),
|
||||
stderr: stderr.trim().to_string(),
|
||||
duration_ms: elapsed.as_millis() as u64,
|
||||
success: status.success(),
|
||||
});
|
||||
match tokio::time::timeout(timeout, child.wait()).await {
|
||||
Ok(Ok(status)) => {
|
||||
let elapsed = start.elapsed();
|
||||
let mut stdout_buf = String::new();
|
||||
let mut stderr_buf = String::new();
|
||||
if let Some(mut out) = child.stdout.take() {
|
||||
let _ = out.read_to_string(&mut stdout_buf).await;
|
||||
}
|
||||
None => {
|
||||
if elapsed >= timeout {
|
||||
child.kill()?;
|
||||
return Ok(ExecutionResult {
|
||||
command: format!("{} {}", cmd, args.join(" ")),
|
||||
exit_code: None,
|
||||
stdout: String::new(),
|
||||
stderr: format!("Killed after {}s timeout", timeout_secs),
|
||||
duration_ms: timeout.as_millis() as u64,
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
std::thread::sleep(check_interval);
|
||||
elapsed += check_interval;
|
||||
if let Some(mut err) = child.stderr.take() {
|
||||
let _ = err.read_to_string(&mut stderr_buf).await;
|
||||
}
|
||||
Ok(ExecutionResult {
|
||||
command: format!("{} {}", cmd, args.join(" ")),
|
||||
exit_code: status.code(),
|
||||
stdout: stdout_buf.trim().to_string(),
|
||||
stderr: stderr_buf.trim().to_string(),
|
||||
duration_ms: elapsed.as_millis() as u64,
|
||||
success: status.success(),
|
||||
})
|
||||
}
|
||||
Ok(Err(e)) => Err(anyhow::anyhow!("Process failed: {}", e)),
|
||||
Err(_) => {
|
||||
let _ = child.kill().await;
|
||||
let elapsed = start.elapsed();
|
||||
Ok(ExecutionResult {
|
||||
command: format!("{} {}", cmd, args.join(" ")),
|
||||
exit_code: None,
|
||||
stdout: String::new(),
|
||||
stderr: format!("Killed after {}s timeout", timeout_secs),
|
||||
duration_ms: elapsed.as_millis() as u64,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +78,6 @@ pub fn detect_language(code: &str) -> &'static str {
|
||||
let trimmed = code.trim();
|
||||
let first_line = trimmed.lines().next().unwrap_or("").trim();
|
||||
|
||||
// Shebang detection
|
||||
if first_line.starts_with("#!/") {
|
||||
if first_line.contains("python") || first_line.contains("python3") {
|
||||
return "python";
|
||||
@@ -94,7 +99,6 @@ pub fn detect_language(code: &str) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
// Rust: fn main, println!, use std, let mut
|
||||
if trimmed.contains("fn main")
|
||||
|| (trimmed.contains("println!") && trimmed.contains("fn "))
|
||||
|| trimmed.contains("use std::")
|
||||
@@ -102,7 +106,6 @@ pub fn detect_language(code: &str) -> &'static str {
|
||||
return "rust";
|
||||
}
|
||||
|
||||
// Go: package main, func main, import (, fmt.
|
||||
if (trimmed.contains("package main") && trimmed.contains("func main"))
|
||||
|| trimmed.contains("import (")
|
||||
|| trimmed.starts_with("package ")
|
||||
@@ -110,82 +113,176 @@ pub fn detect_language(code: &str) -> &'static str {
|
||||
return "go";
|
||||
}
|
||||
|
||||
// C/C++: #include
|
||||
if trimmed.contains("#include <") {
|
||||
if trimmed.contains("iostream") || trimmed.contains("std::") || trimmed.contains("using namespace") {
|
||||
if trimmed.contains("iostream")
|
||||
|| trimmed.contains("std::")
|
||||
|| trimmed.contains("using namespace")
|
||||
{
|
||||
return "cpp";
|
||||
}
|
||||
return "c";
|
||||
}
|
||||
|
||||
// PowerShell: Cmdlets (Get-*, Write-*), Param(, $var =, common aliases
|
||||
let ps_score = [
|
||||
"Write-Host", "Get-Process", "Get-Service", "Get-ChildItem", "Param(",
|
||||
"Write-Output", "Write-Error", "Get-Item", "Set-Item", "New-Item",
|
||||
"Remove-Item", "ForEach-Object", "Where-Object", "Select-Object",
|
||||
"| ForEach-Object", "foreach ($", "function ", "Export-Csv",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"Write-Host",
|
||||
"Get-Process",
|
||||
"Get-Service",
|
||||
"Get-ChildItem",
|
||||
"Param(",
|
||||
"Write-Output",
|
||||
"Write-Error",
|
||||
"Get-Item",
|
||||
"Set-Item",
|
||||
"New-Item",
|
||||
"Remove-Item",
|
||||
"ForEach-Object",
|
||||
"Where-Object",
|
||||
"Select-Object",
|
||||
"| ForEach-Object",
|
||||
"foreach ($",
|
||||
"function ",
|
||||
"Export-Csv",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if ps_score >= 2 || (trimmed.starts_with("#requires") || trimmed.starts_with("<#")) {
|
||||
return "powershell";
|
||||
}
|
||||
if trimmed.contains("$") && (trimmed.contains("Write-Host") || trimmed.contains("Write-Output")) {
|
||||
if trimmed.contains("$") && (trimmed.contains("Write-Host") || trimmed.contains("Write-Output"))
|
||||
{
|
||||
return "powershell";
|
||||
}
|
||||
|
||||
// Python: import, def, print(, class, if __name__, @
|
||||
let py_score = [
|
||||
"import ", "from ", "def ", "class ", "print(",
|
||||
"if __name__", "elif ", "except ", "with ", "as ",
|
||||
"lambda ", "yield ", "async def", "await ",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"import ",
|
||||
"from ",
|
||||
"def ",
|
||||
"class ",
|
||||
"print(",
|
||||
"if __name__",
|
||||
"elif ",
|
||||
"except ",
|
||||
"with ",
|
||||
"as ",
|
||||
"lambda ",
|
||||
"yield ",
|
||||
"async def",
|
||||
"await ",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if py_score >= 3 {
|
||||
return "python";
|
||||
}
|
||||
|
||||
// Node.js/JavaScript: require(, console.log, module.exports, process., =>
|
||||
let js_score = [
|
||||
"require(", "console.log", "module.exports", "process.env",
|
||||
"=>", "const ", "let ", "var ", "function(", "async (",
|
||||
"document.", "window.", "export default", "import ",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"require(",
|
||||
"console.log",
|
||||
"module.exports",
|
||||
"process.env",
|
||||
"=>",
|
||||
"const ",
|
||||
"let ",
|
||||
"var ",
|
||||
"function(",
|
||||
"async (",
|
||||
"document.",
|
||||
"window.",
|
||||
"export default",
|
||||
"import ",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if js_score >= 2 {
|
||||
return "node";
|
||||
}
|
||||
|
||||
// Ruby: def, end, puts, attr_accessor, require ', class .. <
|
||||
let rb_score = [
|
||||
"def ", "\nend", "puts ", "require '", "attr_accessor",
|
||||
"attr_reader", "attr_writer", "do |", "=>", "::",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"def ",
|
||||
"\nend",
|
||||
"puts ",
|
||||
"require '",
|
||||
"attr_accessor",
|
||||
"attr_reader",
|
||||
"attr_writer",
|
||||
"do |",
|
||||
"=>",
|
||||
"::",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if rb_score >= 2 {
|
||||
return "ruby";
|
||||
}
|
||||
|
||||
// Perl: use strict, my $, sub, shift, print "
|
||||
let pl_score = [
|
||||
"use strict", "use warnings", "my $", "sub ", "shift",
|
||||
"print \"", "print '", "chomp", "foreach my", "while (<",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"use strict",
|
||||
"use warnings",
|
||||
"my $",
|
||||
"sub ",
|
||||
"shift",
|
||||
"print \"",
|
||||
"print '",
|
||||
"chomp",
|
||||
"foreach my",
|
||||
"while (<",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if pl_score >= 2 {
|
||||
return "perl";
|
||||
}
|
||||
|
||||
// Bash: if [, $#, fi, done, then, case, esac, redirects
|
||||
let sh_score = [
|
||||
"if [", "if [[", "$#", "\nfi", "\ndone", "\nthen",
|
||||
"case ", "esac", ">&2", "2>&1", "#!/", "echo \"",
|
||||
"while read", "for i in", "do\n", "$((", "${",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"if [",
|
||||
"if [[",
|
||||
"$#",
|
||||
"\nfi",
|
||||
"\ndone",
|
||||
"\nthen",
|
||||
"case ",
|
||||
"esac",
|
||||
">&2",
|
||||
"2>&1",
|
||||
"#!/",
|
||||
"echo \"",
|
||||
"while read",
|
||||
"for i in",
|
||||
"do\n",
|
||||
"$((",
|
||||
"${",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if sh_score >= 2 {
|
||||
return "bash";
|
||||
}
|
||||
|
||||
// CMD/BAT: @echo, setlocal, %var%, REM
|
||||
let cmd_score = [
|
||||
"@echo", "echo off", "setlocal", "endlocal", "%",
|
||||
"REM ", "rem ", "color ", "title ", "exit /b",
|
||||
"if not", "if defined", "set \"", ">nul",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
"@echo",
|
||||
"echo off",
|
||||
"setlocal",
|
||||
"endlocal",
|
||||
"%",
|
||||
"REM ",
|
||||
"rem ",
|
||||
"color ",
|
||||
"title ",
|
||||
"exit /b",
|
||||
"if not",
|
||||
"if defined",
|
||||
"set \"",
|
||||
">nul",
|
||||
]
|
||||
.iter()
|
||||
.filter(|&&kw| trimmed.contains(kw))
|
||||
.count();
|
||||
if cmd_score >= 2 {
|
||||
return "cmd";
|
||||
}
|
||||
@@ -193,7 +290,11 @@ pub fn detect_language(code: &str) -> &'static str {
|
||||
"python"
|
||||
}
|
||||
|
||||
pub fn execute_script(language: &str, code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
pub async fn execute_script(
|
||||
language: &str,
|
||||
code: &str,
|
||||
timeout_secs: u64,
|
||||
) -> Result<ExecutionResult> {
|
||||
let (interpreter, ext) = match language.to_lowercase().as_str() {
|
||||
"python" | "py" => ("python", ".py"),
|
||||
"bash" | "sh" => ("bash", ".sh"),
|
||||
@@ -202,32 +303,32 @@ pub fn execute_script(language: &str, code: &str, timeout_secs: u64) -> Result<E
|
||||
"ruby" => ("ruby", ".rb"),
|
||||
"perl" => ("perl", ".pl"),
|
||||
"node" | "javascript" | "js" => ("node", ".js"),
|
||||
"rust" => return compile_and_run_rust(code, timeout_secs),
|
||||
"go" | "golang" => return compile_and_run_go(code, timeout_secs),
|
||||
"c" => return compile_and_run_c_cpp(code, timeout_secs, "c"),
|
||||
"cpp" | "c++" | "cxx" => return compile_and_run_c_cpp(code, timeout_secs, "cpp"),
|
||||
"rust" => return compile_and_run_rust(code, timeout_secs).await,
|
||||
"go" | "golang" => return compile_and_run_go(code, timeout_secs).await,
|
||||
"c" => return compile_and_run_c_cpp(code, timeout_secs, "c").await,
|
||||
"cpp" | "c++" | "cxx" => return compile_and_run_c_cpp(code, timeout_secs, "cpp").await,
|
||||
_ => return Err(anyhow::anyhow!("Unsupported language: {}. Supported: python, bash, powershell, cmd, ruby, perl, node, rust, go, c, cpp", language)),
|
||||
};
|
||||
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
let script_path = temp_dir.join(format!("script_{}{}", std::process::id(), ext));
|
||||
let script_path = temp_dir.join(format!("script_{}_{}", std::process::id(), ext));
|
||||
|
||||
let mut file = std::fs::File::create(&script_path)?;
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
|
||||
let result = if interpreter == "cmd" {
|
||||
execute_command("cmd", &["/C", script_path.to_str().unwrap()], timeout_secs)
|
||||
execute_command("cmd", &["/C", script_path.to_str().unwrap()], timeout_secs).await
|
||||
} else {
|
||||
execute_command(interpreter, &[script_path.to_str().unwrap()], timeout_secs)
|
||||
execute_command(interpreter, &[script_path.to_str().unwrap()], timeout_secs).await
|
||||
};
|
||||
|
||||
let _ = std::fs::remove_file(&script_path);
|
||||
result
|
||||
}
|
||||
|
||||
fn compile_and_run_rust(code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
async fn compile_and_run_rust(code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
|
||||
@@ -238,7 +339,17 @@ fn compile_and_run_rust(code: &str, timeout_secs: u64) -> Result<ExecutionResult
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
|
||||
let compile = execute_command("rustc", &[source_path.to_str().unwrap(), "-o", bin_path.to_str().unwrap(), "--quiet"], timeout_secs)?;
|
||||
let compile = execute_command(
|
||||
"rustc",
|
||||
&[
|
||||
source_path.to_str().unwrap(),
|
||||
"-o",
|
||||
bin_path.to_str().unwrap(),
|
||||
"--quiet",
|
||||
],
|
||||
timeout_secs,
|
||||
)
|
||||
.await?;
|
||||
if !compile.success {
|
||||
return Ok(ExecutionResult {
|
||||
command: "rustc (compile)".to_string(),
|
||||
@@ -250,14 +361,14 @@ fn compile_and_run_rust(code: &str, timeout_secs: u64) -> Result<ExecutionResult
|
||||
});
|
||||
}
|
||||
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs);
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs).await;
|
||||
|
||||
let _ = std::fs::remove_file(&source_path);
|
||||
let _ = std::fs::remove_file(&bin_path);
|
||||
run_result
|
||||
}
|
||||
|
||||
fn compile_and_run_go(code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
async fn compile_and_run_go(code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
|
||||
@@ -268,7 +379,17 @@ fn compile_and_run_go(code: &str, timeout_secs: u64) -> Result<ExecutionResult>
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
|
||||
let compile = execute_command("go", &["build", "-o", bin_path.to_str().unwrap(), source_path.to_str().unwrap()], timeout_secs)?;
|
||||
let compile = execute_command(
|
||||
"go",
|
||||
&[
|
||||
"build",
|
||||
"-o",
|
||||
bin_path.to_str().unwrap(),
|
||||
source_path.to_str().unwrap(),
|
||||
],
|
||||
timeout_secs,
|
||||
)
|
||||
.await?;
|
||||
if !compile.success {
|
||||
return Ok(ExecutionResult {
|
||||
command: "go build".to_string(),
|
||||
@@ -280,14 +401,18 @@ fn compile_and_run_go(code: &str, timeout_secs: u64) -> Result<ExecutionResult>
|
||||
});
|
||||
}
|
||||
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs);
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs).await;
|
||||
|
||||
let _ = std::fs::remove_file(&source_path);
|
||||
let _ = std::fs::remove_file(&bin_path);
|
||||
run_result
|
||||
}
|
||||
|
||||
fn compile_and_run_c_cpp(code: &str, timeout_secs: u64, lang: &str) -> Result<ExecutionResult> {
|
||||
async fn compile_and_run_c_cpp(
|
||||
code: &str,
|
||||
timeout_secs: u64,
|
||||
lang: &str,
|
||||
) -> Result<ExecutionResult> {
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
|
||||
@@ -300,7 +425,16 @@ fn compile_and_run_c_cpp(code: &str, timeout_secs: u64, lang: &str) -> Result<Ex
|
||||
drop(file);
|
||||
|
||||
let compiler = if lang == "cpp" { "g++" } else { "gcc" };
|
||||
let compile = execute_command(compiler, &[source_path.to_str().unwrap(), "-o", bin_path.to_str().unwrap()], timeout_secs)?;
|
||||
let compile = execute_command(
|
||||
compiler,
|
||||
&[
|
||||
source_path.to_str().unwrap(),
|
||||
"-o",
|
||||
bin_path.to_str().unwrap(),
|
||||
],
|
||||
timeout_secs,
|
||||
)
|
||||
.await?;
|
||||
if !compile.success {
|
||||
return Ok(ExecutionResult {
|
||||
command: format!("{} (compile)", compiler),
|
||||
@@ -312,7 +446,7 @@ fn compile_and_run_c_cpp(code: &str, timeout_secs: u64, lang: &str) -> Result<Ex
|
||||
});
|
||||
}
|
||||
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs);
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs).await;
|
||||
|
||||
let _ = std::fs::remove_file(&source_path);
|
||||
let _ = std::fs::remove_file(&bin_path);
|
||||
|
||||
Reference in New Issue
Block a user