Add /eval command

This commit is contained in:
toast 2023-12-05 14:18:30 +11:00
parent 0837a65bf4
commit d33a479f5c
6 changed files with 63 additions and 2 deletions

View File

@ -1,5 +1,6 @@
{
"rust-analyzer.linkedProjects": [
"./Cargo.toml"
]
],
"rust-analyzer.showUnlinkedFileNotification": false
}

1
Cargo.lock generated
View File

@ -1146,6 +1146,7 @@ version = "0.1.0"
dependencies = [
"poise",
"serenity 0.12.0",
"tempfile",
"tokio",
"tracing",
"tracing-subscriber",

View File

@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
poise = "0.5.7"
serenity = "0.12.0"
tempfile = "3.8.1"
tokio = { version = "1.34.0", features = ["macros", "signal", "rt-multi-thread"] }
tracing = "0.1.40"
tracing-subscriber = "0.3.18"

56
src/commands/eval.rs Normal file
View File

@ -0,0 +1,56 @@
use crate::Error;
use poise::serenity_prelude::UserId;
use std::os::unix::fs::PermissionsExt;
use std::process::Command;
use std::io::Write;
const WHITELISTED_USERS: &[UserId] = &[
poise::serenity_prelude::UserId(190407856527376384)
];
/// Evaluate a piece of code
#[poise::command(slash_command)]
pub async fn eval(
ctx: poise::Context<'_, (), Error>,
#[description = "The Rust code to evaluate"] code: String
) -> Result<(), Error> {
if !WHITELISTED_USERS.contains(&ctx.author().id) {
ctx.reply("Whitelisted users can only use this command!").await?;
return Ok(());
}
// Create a temp directory
let dir = tempfile::tempdir()?;
let file_path = dir.path().join("temp.rs");
{
let mut file = std::fs::File::create(&file_path)?;
writeln!(file, "{}", code)?;
}
// Compile
let compiled_path = dir.path().join("temp");
let output = Command::new("rustc").arg(&file_path).arg("-o").arg(&compiled_path).output()?;
if !output.status.success() {
ctx.reply(format!("Compilation failed:\n```{}```", String::from_utf8_lossy(&output.stderr))).await?;
return Ok(());
}
// Update binary's permissions before execution stage
let permissions = std::fs::Permissions::from_mode(0o755);
let compiled_path = dir.path().join("temp");
std::fs::set_permissions(&compiled_path, permissions)?;
// If success, run it.
let output = Command::new(compiled_path).output()?;
if !output.status.success() {
ctx.reply(format!("Execution failed:\n```{}```", String::from_utf8_lossy(&output.stderr))).await?;
return Ok(());
}
ctx.reply(format!("Code output:\n```rs\n{}```", String::from_utf8_lossy(&output.stdout))).await?;
Ok(())
}

View File

@ -1 +1,2 @@
pub mod ping;
pub mod eval;

View File

@ -37,7 +37,8 @@ async fn main() {
.intents(serenity::GatewayIntents::MESSAGE_CONTENT | serenity::GatewayIntents::GUILDS)
.options(poise::FrameworkOptions {
commands: vec![
commands::ping::ping()
commands::ping::ping(),
commands::eval::eval()
],
pre_command: |ctx| {
Box::pin(async move {