smol bot
Diffstat (limited to 'src/bot/schematic.rs')
| -rw-r--r-- | src/bot/schematic.rs | 62 |
1 files changed, 49 insertions, 13 deletions
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> { |