html terminal
use spawn_blocking where applicable
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | src/bot/logic.rs | 83 | ||||
| -rw-r--r-- | src/bot/maps.rs | 89 | ||||
| -rw-r--r-- | src/bot/schematic.rs | 31 |
4 files changed, 102 insertions, 105 deletions
@@ -40,11 +40,11 @@ parse_duration = "2.1.1" serde = "1.0" serde_json = "1.0" btparse = "0.1.1" -mindus = { version = "4", features = [], default-features = false } +mindus = { version = "5", features = [], default-features = false } oxipng = { git = "https://github.com/shssoichiro/oxipng", branch = "master", features = [], default-features = false } strip-ansi-escapes = "0.2.0" dashmap = "5.5.1" -lemu = { features = ["diagnose", "__send__"], default-features = false, version = "0.2.0" } +lemu = { features = ["diagnose"], default-features = false, version = "0.2.0" } [profile.release] strip = true diff --git a/src/bot/logic.rs b/src/bot/logic.rs index e41733e..4f4314a 100644 --- a/src/bot/logic.rs +++ b/src/bot/logic.rs @@ -14,8 +14,8 @@ pub async fn run( output: Some(output), displays, .. - } = ({ - match Executor::with_output(vec![]) + } = (match tokio::task::spawn_blocking(move || { + Executor::with_output(vec![]) .display() .limit_iterations( kv.get("iters") @@ -23,20 +23,22 @@ pub async fn run( ) .limit_instructions(30000) .program(&block.code) - { - Ok(mut v) => { + .map(|mut v| { v.run(); v.output() - } - Err(e) => { - let s = format!("{}", e.diagnose(&block.code)).replace("`", "\u{200b}`"); - ctx.send(|c| { - c.allowed_mentions(|a| a.empty_parse()) - .content(format!("```ansi\n{s}\n```")) - }) - .await?; - return Ok(()); - } + }) + .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 { @@ -44,44 +46,41 @@ pub async fn run( }; 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| { - let mut empty = true; + 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}`") )); - empty = false; } - if display.buffer().iter().any(|&n| n != 0) { - let p = oxipng::RawImage::new( - display.width(), - display.height(), - oxipng::ColorType::RGBA, - oxipng::BitDepth::Eight, - display.take_buffer(), - ) - .unwrap(); - let p = p - .create_optimized_png(&oxipng::Options { - filter: oxipng::indexset! { oxipng::RowFilter::None }, - bit_depth_reduction: false, - color_type_reduction: false, - palette_reduction: false, - grayscale_reduction: false, - ..oxipng::Options::from_preset(0) - }) - .unwrap(); + if let Some(display) = display { c.attachment(AttachmentType::Bytes { - data: Cow::from(p), + data: Cow::from(display), filename: "display1.png".to_string(), - }); - c.embed(|e| e.attachment("display1.png")); - empty = false; - } - if empty { - c.content("no output"); + }) + .embed(|e| e.attachment("display1.png")); } c.allowed_mentions(|a| a.empty_parse()) }) diff --git a/src/bot/maps.rs b/src/bot/maps.rs index fa00f58..b18a305 100644 --- a/src/bot/maps.rs +++ b/src/bot/maps.rs @@ -8,7 +8,7 @@ use std::borrow::Cow; use std::sync::atomic::{AtomicU64, Ordering::Relaxed}; use std::time::{Duration, Instant, SystemTime}; use tokio::sync::broadcast::{self, Sender}; -use tokio::sync::{MutexGuard, OnceCell}; +use tokio::sync::{Mutex, MutexGuard, OnceCell}; pub struct Maps; impl Maps { pub async fn find(map: &str, stdin: &broadcast::Sender<String>) -> usize { @@ -78,7 +78,6 @@ impl MapImage { stdin: &Sender<String>, // returning a guard is questionable ) -> Result<(MutexGuard<Vec<u8>>, Option<RenderInfo>)> { - let mut lock = self.0.lock().await; // me in a million years when its 1901 and we never get a new render let now = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) @@ -90,53 +89,59 @@ impl MapImage { .fetch_update(Relaxed, Relaxed, |then| (now > then + 70).then_some(now)) .is_err() { - (lock, None) + (self.0.lock().await, None) } else { send!(stdin, "save 0")?; let _ = get_nextblock().await; // parsing the thing doesnt negate the need for a env var sooo let o = std::fs::read(std::env::var("SAVE_PATH").unwrap())?; - let then = Instant::now(); - let m = Map::deserialize(&mut mindus::data::DataRead::new(&o))?; - let deser_took = then.elapsed(); - let name = m.tags.get("mapname").unwrap().to_owned(); - let render_took = Instant::now(); - let i = m.render(); - let render_took = render_took.elapsed(); - let compression_took = Instant::now(); - let i = RawImage::new( - i.width(), - i.height(), - ColorType::RGB { - transparent_color: None, - }, - BitDepth::Eight, - i.take_buffer(), - ) - .unwrap(); - *lock = i - .create_optimized_png(&oxipng::Options { - filter: indexset! { RowFilter::None }, - bit_depth_reduction: false, - color_type_reduction: false, - palette_reduction: false, - grayscale_reduction: false, - ..oxipng::Options::from_preset(0) - }) + let (i, info) = tokio::task::spawn_blocking(move || { + let then = Instant::now(); + let m = Map::deserialize(&mut mindus::data::DataRead::new(&o))?; + let deser_took = then.elapsed(); + let name = m.tags.get("mapname").unwrap().to_owned(); + let render_took = Instant::now(); + let i = m.render(); + let render_took = render_took.elapsed(); + let compression_took = Instant::now(); + let i = RawImage::new( + i.width(), + i.height(), + ColorType::RGB { + transparent_color: None, + }, + BitDepth::Eight, + i.take_buffer(), + ) .unwrap(); - let compression_took = compression_took.elapsed(); - let total = then.elapsed(); - ( - lock, - Some(RenderInfo { - deserialization: deser_took, - render: render_took, - compression: compression_took, - name, - total, - }), - ) + let i = i + .create_optimized_png(&oxipng::Options { + filter: indexset! { RowFilter::None }, + bit_depth_reduction: false, + color_type_reduction: false, + palette_reduction: false, + grayscale_reduction: false, + ..oxipng::Options::from_preset(0) + }) + .unwrap(); + let compression_took = compression_took.elapsed(); + let total = then.elapsed(); + anyhow::Ok(( + i, + RenderInfo { + deserialization: deser_took, + render: render_took, + compression: compression_took, + name, + total, + }, + )) + }) + .await??; + let mut lock = self.0.lock().await; + *lock = i; + (lock, Some(info)) }, ) } diff --git a/src/bot/schematic.rs b/src/bot/schematic.rs index 2172927..a8c5374 100644 --- a/src/bot/schematic.rs +++ b/src/bot/schematic.rs @@ -12,7 +12,7 @@ use super::{emojis, strip_colors, SMsg, SUCCESS}; static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(```)?(\n)?([^`]+)(\n)?(```)?").unwrap()); -async fn from_attachments(attchments: &[Attachment]) -> Result<Option<Schematic<'_>>> { +async fn from_attachments(attchments: &[Attachment]) -> Result<Option<Schematic>> { for a in attchments { if a.filename.ends_with("msch") { let s = a.download().await?; @@ -37,8 +37,11 @@ async fn from_attachments(attchments: &[Attachment]) -> Result<Option<Schematic< pub async fn with(m: SMsg, c: &serenity::client::Context) -> Result<ControlFlow<Message, ()>> { let author = m.author; - let send = |v| async move { - let p = to_png(&v); + let send = |v: Schematic| async move { + let d = v.tags.get("description").cloned(); + let name = strip_colors(v.tags.get("name").unwrap()); + let cost = v.compute_total_cost().0; + let p = tokio::task::spawn_blocking(move || to_png(&v)).await?; anyhow::Ok( m.channel .send_message(c, |m| { @@ -48,11 +51,9 @@ pub async fn with(m: SMsg, c: &serenity::client::Context) -> Result<ControlFlow< }) .embed(|e| { e.attachment("image.png"); - if let Some(d) = v.tags.get("description") { - e.description(d); - } + d.map(|v| e.description(v)); let mut s = String::new(); - for (i, n) in v.compute_total_cost().0.iter() { + for (i, n) in cost.iter() { if n == 0 { continue; } @@ -60,7 +61,7 @@ pub async fn with(m: SMsg, c: &serenity::client::Context) -> Result<ControlFlow< write!(s, "{} {n} ", emojis::item(i)).unwrap(); } e.field("", s, true); - e.title(strip_colors(v.tags.get("name").unwrap())) + e.title(name) .footer(|f| f.text(format!("requested by {author}"))) .color(SUCCESS) }) @@ -80,7 +81,7 @@ pub async fn with(m: SMsg, c: &serenity::client::Context) -> Result<ControlFlow< Ok(ControlFlow::Continue(())) } -pub fn to_png(s: &Schematic<'_>) -> Vec<u8> { +pub fn to_png(s: &Schematic) -> Vec<u8> { let p = s.render(); let p = RawImage::new( p.width(), @@ -92,18 +93,10 @@ pub fn to_png(s: &Schematic<'_>) -> Vec<u8> { p.take_buffer(), ) .unwrap(); - p.create_optimized_png(&oxipng::Options { - filter: indexset! { RowFilter::None }, - bit_depth_reduction: false, - color_type_reduction: false, - palette_reduction: false, - grayscale_reduction: false, - ..oxipng::Options::from_preset(0) - }) - .unwrap() + p.create_optimized_png(&oxipng::Options::default()).unwrap() } -fn from_msg<'l>(msg: &str) -> Result<Schematic<'l>> { +fn from_msg(msg: &str) -> Result<Schematic> { let schem_text = RE .captures(msg) .ok_or(anyhow!("couldnt find schematic"))? |