html terminal
use spawn_blocking where applicable
bendn 2023-09-14
parent cb476c4 · commit 2449a22
-rw-r--r--Cargo.toml4
-rw-r--r--src/bot/logic.rs83
-rw-r--r--src/bot/maps.rs89
-rw-r--r--src/bot/schematic.rs31
4 files changed, 102 insertions, 105 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 9b461a6..886f7b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"))?