smol bot
Diffstat (limited to 'src/bot/logic.rs')
| -rw-r--r-- | src/bot/logic.rs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/bot/logic.rs b/src/bot/logic.rs new file mode 100644 index 0000000..30631fb --- /dev/null +++ b/src/bot/logic.rs @@ -0,0 +1,90 @@ +use super::{Context, Result}; +use lemu::Executor; +use poise::{serenity_prelude::AttachmentType, CodeBlock, KeyValueArgs}; +use std::borrow::Cow; + +#[poise::command(prefix_command, track_edits, rename = "eval")] +pub async fn run( + ctx: Context<'_>, + #[description = "number of iterations"] kv: KeyValueArgs, + #[description = "Script"] block: CodeBlock, +) -> Result<()> { + let _ = ctx.channel_id().start_typing(&ctx.serenity_context().http); + let lemu::Output { + output: Some(output), + displays, + .. + } = (match tokio::task::spawn_blocking(move || { + Executor::with_output(vec![]) + .large_display() + .limit_iterations( + kv.get("iters") + .map_or(1, |v| v.parse::<usize>().unwrap_or(1).clamp(1, 50)), + ) + .limit_instructions(52789849) + .program(&block.code) + .map(|mut v| { + v.run(); + v.output() + }) + .map_err(|e| format!("{}", e.diagnose(&block.code)).replace("`", "\u{200b}`")) + }) + .await? + { + Ok(o) => o, + Err(e) => { + ctx.send(|c| { + c.allowed_mentions(|a| a.empty_parse()) + .content(format!("```ansi\n{e}\n```")) + }) + .await?; + return Ok(()); + } + }) + else { + unreachable!() + }; + let displays: Box<[_; 1]> = displays.try_into().unwrap(); + let [(display, _)] = *displays; + let display = if display.buffer().iter().any(|&n| n != 0) { + Some( + tokio::task::spawn_blocking(move || { + let p = oxipng::RawImage::new( + display.width(), + display.height(), + oxipng::ColorType::RGBA, + oxipng::BitDepth::Eight, + display.take_buffer(), + ) + .unwrap(); + p.create_optimized_png(&oxipng::Options::default()).unwrap() + }) + .await?, + ) + } else { + None + }; + + ctx.send(|c| { + if output.is_empty() && display.is_none() { + c.content("no output"); + } + if !output.is_empty() { + c.content(format!( + "```\n{}\n```", + String::from_utf8_lossy(&output).replace('`', "\u{200b}`") + )); + } + if let Some(display) = display { + c.attachment(AttachmentType::Bytes { + data: Cow::from(display), + filename: "display1.png".to_string(), + }) + .embed(|e| e.attachment("display1.png")); + } + c.allowed_mentions(|a| a.empty_parse()) + }) + .await?; + + Ok(()) +} |