smol bot
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/bot/mod.rs | 32 | ||||
| -rw-r--r-- | src/bot/schematic.rs | 62 |
3 files changed, 65 insertions, 30 deletions
@@ -37,6 +37,7 @@ rust-fuzzy-search = "0.1.1" jemallocator-global = "0.3.2" const_format = { version = "0.2.32", features = ["fmt"] } logos = "0.14.0" +base64 = "0.21.7" [profile.release] strip = true diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 13d2914..4ede96a 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -137,9 +137,7 @@ pub async fn scour(c: Context<'_>, ch: ChannelId) -> Result<()> { continue; }; if let Ok(Some(x)) = schematic::from((&msg.content, &msg.attachments)).await { - let mut w = mindus::data::DataWrite::default(); - x.serialize(&mut w).unwrap(); - _ = std::fs::write(format!("repo/{d}/{:x}.msch", msg.id.get()), w.consume()); + _ = std::fs::write(format!("repo/{d}/{:x}.msch", msg.id.get()), x.data); msg.react(c, emojis::get!(MERGE)).await?; n += 1; } @@ -183,6 +181,8 @@ where } mod git { + use self::schematic::Schem; + use super::*; pub fn schem(dir: &str, x: MessageId) -> std::io::Result<mindus::Schematic> { std::fs::read(path(dir, x)) @@ -253,11 +253,9 @@ mod git { .success()) } - pub fn write(dir: &str, x: MessageId, s: &mindus::Schematic) { + pub fn write(dir: &str, x: MessageId, s: Schem) { _ = std::fs::create_dir(format!("repo/{dir}")); - let mut w = mindus::data::DataWrite::default(); - s.serialize(&mut w).unwrap(); - std::fs::write(path(dir, x), w.consume()).unwrap(); + std::fs::write(path(dir, x), s.data).unwrap(); add(); } @@ -361,17 +359,17 @@ impl Bot { } if let Some(dir) = dir { // add :) - git::write(dir, new_message.id, &s); - git::add(); - git::commit(&who, &format!("add {:x}.msch", new_message.id.get())); - git::push(); - new_message.react(c, emojis::get!(MERGE)).await?; send(c,|x| x .avatar_url(new_message.author.avatar_url().unwrap_or(CAT.to_string())) - .username(who) + .username(&who) .embed(CreateEmbed::new().color(AD) .description(format!("https://discord.com/channels/925674713429184564/{}/{} {ADD} add {} (`{:x}.msch`)", m.channel_id,m.id, emoji::mindustry::to_discord(&strip_colors(s.tags.get("name").unwrap())), new_message.id.get()))) ).await; + git::write(dir, new_message.id, s); + git::add(); + git::commit(&who, &format!("add {:x}.msch", new_message.id.get())); + git::push(); + new_message.react(c, emojis::get!(MERGE)).await?; } d.tracker.insert(new_message.id, m); return Ok(()); @@ -412,15 +410,15 @@ impl Bot { d.tracker.insert(*id, m); if let Some(dir) = dir && git::has(dir, *id) { // update :) - git::write(dir, *id, &s); - git::commit(&who,&format!("update {:x}.msch", id.get())); - git::push(); send(c,|x| x .avatar_url(author.avatar_url().unwrap_or(CAT.to_string())) - .username(who) + .username(&who) .embed(CreateEmbed::new().color(AD) .description(format!("https://discord.com/channels/925674713429184564/{channel_id}/{id} {ROTATE} update {} (`{:x}.msch`)", emoji::mindustry::to_discord(&strip_colors(s.tags.get("name").unwrap())), id.get()))) ).await; + git::write(dir, *id, s); + git::commit(&who,&format!("update {:x}.msch", id.get())); + git::push(); } } } diff --git a/src/bot/schematic.rs b/src/bot/schematic.rs index b28df4a..1450b91 100644 --- a/src/bot/schematic.rs +++ b/src/bot/schematic.rs @@ -1,38 +1,63 @@ use anyhow::Result; +use base64::Engine; use logos::Logos; use mindus::data::DataRead; use mindus::*; use poise::serenity_prelude::*; use regex::Regex; -use std::fmt::Write; use std::ops::ControlFlow; use std::sync::LazyLock; +use std::{fmt::Write, ops::Deref}; use super::{strip_colors, Msg, SUCCESS}; static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(```)?(\n)?([^`]+)(\n)?(```)?").unwrap()); -pub async fn from_attachments(attchments: &[Attachment]) -> Result<Option<Schematic>> { +pub struct Schem { + schem: Schematic, + pub data: Vec<u8>, // work around bugs +} + +impl Deref for Schem { + type Target = Schematic; + + fn deref(&self) -> &Self::Target { + &self.schem + } +} + +pub async fn from_attachments(attchments: &[Attachment]) -> Result<Option<Schem>> { for a in attchments { if a.filename.ends_with("msch") { - let s = a.download().await?; - let mut s = DataRead::new(&s); + let sd = a.download().await?; + let mut s = DataRead::new(&sd); let Ok(s) = Schematic::deserialize(&mut s) else { println!("failed to read {}", a.filename); continue; }; - return Ok(Some(s)); + return Ok(Some(Schem { schem: s, data: sd })); // discord uploads base64 as a file when its too long } else if a.filename == "message.txt" { let Ok(s) = String::from_utf8(a.download().await?) else { continue; }; - let Ok(s) = Schematic::deserialize_base64(s.trim()) else { + let mut buff = vec![0; s.len() / 4 * 3 + 1]; + let Ok(s) = base64::engine::general_purpose::STANDARD + .decode_slice(s.as_bytes(), &mut buff) + .map_err(|_| ()) + .and_then(|n_out| { + buff.truncate(n_out); + Schematic::deserialize(&mut DataRead::new(&buff)).map_err(|_| ()) + }) + else { println!("failed to read msg.txt"); continue; }; - return Ok(Some(s)); + return Ok(Some(Schem { + schem: s, + data: buff, + })); } } Ok(None) @@ -42,9 +67,9 @@ pub async fn with( m: Msg, c: &serenity::client::Context, labels: Option<String>, -) -> Result<ControlFlow<(Message, String, Schematic), ()>> { +) -> Result<ControlFlow<(Message, String, Schem), ()>> { let author = m.author; - let send = |v: Schematic| async move { + let send = |v: Schem| async move { let name = emoji::mindustry::to_discord(&strip_colors(v.tags.get("name").unwrap())); println!("deser {name}"); let vclone = v.clone(); @@ -96,7 +121,7 @@ pub async fn with( if let Ok(Some(mut v)) = from((&m.content, &m.attachments)).await { labels.map(|x| { - v.tags.insert("labels".into(), x); + v.schem.tags.insert("labels".into(), x); }); return Ok(ControlFlow::Break(send(v).await?)); } @@ -108,14 +133,14 @@ pub fn to_png(s: &Schematic) -> Vec<u8> { super::png(s.render()) } -pub async fn from(m: (&str, &[Attachment])) -> Result<Option<Schematic>> { +pub async fn from(m: (&str, &[Attachment])) -> Result<Option<Schem>> { match from_msg(m.0) { x @ Ok(Some(_)) => x, _ => from_attachments(m.1).await, } } -pub fn from_msg(msg: &str) -> Result<Option<Schematic>> { +pub fn from_msg(msg: &str) -> Result<Option<Schem>> { let schem_text = match RE.captures(msg) { None => return Ok(None), Some(x) => x, @@ -124,7 +149,18 @@ pub fn from_msg(msg: &str) -> Result<Option<Schematic>> { .unwrap() .as_str() .trim(); - Ok(Some(Schematic::deserialize_base64(schem_text)?)) + let mut buff = vec![0; schem_text.len() / 4 * 3 + 1]; + let s = base64::engine::general_purpose::STANDARD + .decode_slice(schem_text.as_bytes(), &mut buff) + .map_err(anyhow::Error::from) + .and_then(|n_out| { + buff.truncate(n_out); + Schematic::deserialize(&mut DataRead::new(&buff)).map_err(anyhow::Error::from) + })?; + Ok(Some(Schem { + schem: s, + data: buff, + })) } fn decode_tags(tags: &str) -> Vec<String> { |