smol bot
| -rw-r--r-- | Cargo.toml | 9 | ||||
| -rw-r--r-- | src/bot/logic.rs | 29 | ||||
| -rw-r--r-- | src/bot/map.rs | 5 | ||||
| -rw-r--r-- | src/bot/mod.rs | 99 | ||||
| -rw-r--r-- | src/bot/schematic.rs | 43 |
5 files changed, 94 insertions, 91 deletions
@@ -12,15 +12,13 @@ tokio = { version = "1.28.2", features = [ "parking_lot", ], default-features = false } clipline = "0.1.2" -serenity = { version = "0.11.5", features = [ +serenity = { version = "0.12", features = [ "builder", "client", "rustls_backend", "gateway", ], default-features = false } -poise = { version = "0.5.5", default-features = false, features = [ - "handle_panics", -] } +poise = { git = "https://github.com/serenity-rs/poise" } anyhow = "1.0.75" regex = { version = "1.8.4", features = ["std"], default-features = false } btparse = "0.1.1" @@ -46,3 +44,6 @@ debug-assertions = false [profile.dev.package.fimg] opt-level = 3 debug-assertions = false + +[patch.crates-io] +serenity = { git = "https://github.com/bend-n/serenity", branch = "opt" } diff --git a/src/bot/logic.rs b/src/bot/logic.rs index 3175e7e..10d5034 100644 --- a/src/bot/logic.rs +++ b/src/bot/logic.rs @@ -1,7 +1,6 @@ use super::{Context, Result}; use lemu::Executor; -use poise::{serenity_prelude::AttachmentType, CodeBlock, KeyValueArgs}; -use std::borrow::Cow; +use poise::{serenity_prelude::*, CodeBlock, KeyValueArgs}; #[poise::command(prefix_command, track_edits, rename = "eval")] pub async fn run( @@ -33,10 +32,11 @@ pub async fn run( { Ok(o) => o, Err(e) => { - ctx.send(|c| { - c.allowed_mentions(|a| a.empty_parse()) - .content(format!("```ansi\n{e}\n```")) - }) + ctx.send( + poise::CreateReply::default() + .allowed_mentions(CreateAllowedMentions::default().empty_users().empty_roles()) + .content(format!("```ansi\n{e}\n```")), + ) .await?; return Ok(()); } @@ -65,24 +65,23 @@ pub async fn run( None }; - ctx.send(|c| { + ctx.send({ + let mut c = poise::CreateReply::default(); if output.is_empty() && display.is_none() { - c.content("no output"); + c = c.content("no output"); } if !output.is_empty() { - c.content(format!( + c = 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 = c + .attachment(CreateAttachment::bytes(display, "display1.png")) + .embed(CreateEmbed::default().attachment("display1.png")); } - c.allowed_mentions(|a| a.empty_parse()) + c }) .await?; diff --git a/src/bot/map.rs b/src/bot/map.rs index 1da3be5..fea9dd5 100644 --- a/src/bot/map.rs +++ b/src/bot/map.rs @@ -1,7 +1,6 @@ use anyhow::Result; use mindus::{data::map::ReadError, *}; use poise::serenity_prelude::*; -use std::borrow::Cow; use std::time::Instant; use super::{strip_colors, SUCCESS}; @@ -48,7 +47,7 @@ pub async fn with(msg: &Message, c: &serenity::client::Context) -> Result<()> { ) } }; - let t = msg.channel_id.start_typing(&c.http)?; + let t = msg.channel_id.start_typing(&c.http); let deser_took = then.elapsed(); let name = strip_colors(m.tags.get("name").or(m.tags.get("name")).unwrap()); let (render_took, compression_took, total, png) = @@ -64,7 +63,7 @@ pub async fn with(msg: &Message, c: &serenity::client::Context) -> Result<()> { }) .await?; t.stop(); - msg.channel_id.send_message(c, |m| { m.add_file(AttachmentType::Bytes { data: Cow::from(png), filename: "map.png".to_string() }).embed(|e| e.title(&name).footer(|f| f.text(format!("render of {name} (requested by {auth}) took: {:.3}s (deser: {}ms, render: {:.3}s, compression: {:.3}s)", total.as_secs_f32(), deser_took.as_millis(), render_took.as_secs_f32(), compression_took.as_secs_f32()))).attachment("map.png").color(SUCCESS)) }).await?; + msg.channel_id.send_message(c,CreateMessage::new().add_file(CreateAttachment::bytes(png,"map.png")).embed(CreateEmbed::new().title(&name).footer(CreateEmbedFooter::new(format!("render of {name} (requested by {auth}) took: {:.3}s (deser: {}ms, render: {:.3}s, compression: {:.3}s)", total.as_secs_f32(), deser_took.as_millis(), render_took.as_secs_f32(), compression_took.as_secs_f32()))).attachment("map.png").color(SUCCESS))).await?; return Ok(()); } } diff --git a/src/bot/mod.rs b/src/bot/mod.rs index d29a4a5..85bb294 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -13,6 +13,7 @@ use std::fs::read_to_string; use std::ops::ControlFlow; use std::sync::{Arc, LazyLock}; use std::time::Duration; +use tokio::sync::Mutex; #[derive(Debug)] pub struct Data { @@ -43,16 +44,16 @@ impl Bot { pub async fn spawn() { println!("bot startup"); let tok = std::env::var("TOKEN").unwrap_or(read_to_string("token").expect("wher token")); - let f: poise::FrameworkBuilder<Data, anyhow::Error> = poise::Framework::builder() + let f: poise::Framework<Data, anyhow::Error> = poise::Framework::builder() .options(poise::FrameworkOptions { commands: vec![logic::run(), help()], event_handler: |c, e, _, d| { Box::pin(async move { match e { - poise::Event::Ready { .. } => { + FullEvent::Ready { .. } => { println!("bot ready"); } - poise::Event::GuildCreate { guild } => { + FullEvent::GuildCreate { guild ,..} => { static SEEN: LazyLock<Mutex<HashSet<GuildId>>> = LazyLock::new(|| Mutex::new(HashSet::new())); if SEEN.lock().await.insert(guild.id) { @@ -62,21 +63,19 @@ impl Bot { owner_id, .. } = guild; - let User{id,name:owner_name,..} = c.http().get_user(owner_id.0).await.unwrap(); + let User{id,name:owner_name,..} = c.http().get_user(*owner_id).await.unwrap(); c.http() - .get_user(696196765564534825) + .get_user(696196765564534825.into()) .await .unwrap() - .dm(c.http(), |b| { - b.allowed_mentions(|x|x.empty_users()).content(format!( - "{name} (owned by <@{id}>({owner_name})) has {member_count:?} members" - )) - }) + .dm(c.http(), CreateMessage::new().allowed_mentions(CreateAllowedMentions::default().empty_users()).content(format!( + "{name} (owned by <@{id}>({owner_name})) has {member_count:?} members" + ))) .await .unwrap(); } } - poise::Event::Message { new_message } => { + FullEvent::Message { new_message } => { if new_message.content.starts_with('!') || new_message.content.starts_with(PFX) || new_message.author.bot @@ -99,18 +98,17 @@ impl Bot { // not tracked, as you cant add a attachment afterwwards. map::with(new_message, c).await?; } - poise::Event::MessageUpdate { event, .. } => { - let MessageUpdateEvent { - author: Some(author), - guild_id: Some(guild_id), - content: Some(content), - attachments: Some(attachments), - .. - } = event.clone() - else { - return Ok(()); - }; - if let Some((_, r)) = d.tracker.remove(&event.id) { + FullEvent::MessageUpdate {event: MessageUpdateEvent { + author: Some(author), + guild_id: Some(guild_id), + content: Some(content), + attachments: Some(attachments), + id, + channel_id, + .. + }, ..} => { + + if let Some((_, r)) = d.tracker.remove(id) { r.delete(c).await.unwrap(); if let ControlFlow::Break(m) = schematic::with( Msg { @@ -118,19 +116,19 @@ impl Bot { .nick_in(c, guild_id) .await .unwrap_or(author.name.clone()), - content, - attachments, - channel: event.channel_id, + content:content.clone(), + attachments:attachments.clone(), + channel: *channel_id, }, c, ) .await? { - d.tracker.insert(event.id, m); + d.tracker.insert(*id, m); } } } - poise::Event::MessageDelete { + FullEvent::MessageDelete { deleted_message_id, .. } => { if let Some((_, r)) = d.tracker.remove(deleted_message_id) { @@ -144,16 +142,14 @@ impl Bot { }, on_error: |e| Box::pin(on_error(e)), prefix_options: poise::PrefixFrameworkOptions { - edit_tracker: Some(poise::EditTracker::for_timespan( + edit_tracker: Some(Arc::new(poise::EditTracker::for_timespan( std::time::Duration::from_secs(2 * 60), - )), + ))), prefix: Some(PFX.to_string()), ..Default::default() }, ..Default::default() }) - .token(tok) - .intents(GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT) .setup(|ctx, _ready, framework| { Box::pin(async move { poise::builtins::register_globally(ctx, &framework.options().commands).await?; @@ -173,8 +169,17 @@ impl Bot { }); Ok(Data { tracker }) }) - }); - f.run().await.unwrap(); + }).build(); + ClientBuilder::new( + tok, + GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT, + ) + .framework(f) + .await + .unwrap() + .start() + .await + .unwrap(); } } @@ -183,7 +188,7 @@ type Context<'a> = poise::Context<'a, Data, anyhow::Error>; async fn on_error(error: poise::FrameworkError<'_, Data, anyhow::Error>) { use poise::FrameworkError::Command; match error { - Command { error, ctx } => { + Command { error, ctx, .. } => { let mut msg; { let mut chain = error.chain(); @@ -202,7 +207,7 @@ async fn on_error(error: poise::FrameworkError<'_, Data, anyhow::Error>) { let mut s = vec![]; for frame in parsed.frames { if let Some(line) = frame.line - && (frame.function.contains("panel") + && (frame.function.contains("plent") || frame.function.contains("poise") || frame.function.contains("serenity") || frame.function.contains("mindus") @@ -243,18 +248,16 @@ pub async fn help( #[autocomplete = "poise::builtins::autocomplete_command"] command: Option<String>, ) -> Result<()> { - ctx.send(|m| { - m.ephemeral(true).content( - if matches!( - command.as_deref(), - Some("eval") | Some("exec") | Some("run") - ) { - include_str!("help_eval.md") - } else { - include_str!("usage.md") - }, - ) - }) + ctx.send(poise::CreateReply::default().ephemeral(true).content( + if matches!( + command.as_deref(), + Some("eval") | Some("exec") | Some("run") + ) { + include_str!("help_eval.md") + } else { + include_str!("usage.md") + }, + )) .await?; Ok(()) } diff --git a/src/bot/schematic.rs b/src/bot/schematic.rs index f760cd0..8d8f5f1 100644 --- a/src/bot/schematic.rs +++ b/src/bot/schematic.rs @@ -4,8 +4,8 @@ use mindus::*; use poise::serenity_prelude::*; use regex::Regex; use std::fmt::Write; +use std::ops::ControlFlow; use std::sync::LazyLock; -use std::{borrow::Cow, ops::ControlFlow}; use super::{strip_colors, Msg, SUCCESS}; @@ -51,27 +51,28 @@ pub async fn with(m: Msg, c: &serenity::client::Context) -> Result<ControlFlow<M println!("rend {name}"); anyhow::Ok( m.channel - .send_message(c, |m| { - m.add_file(AttachmentType::Bytes { - data: Cow::Owned(p), - filename: "image.png".to_string(), - }) - .embed(|e| { - e.attachment("image.png"); - d.map(|v| e.description(v)); - let mut s = String::new(); - for (i, n) in cost.iter() { - if n == 0 { - continue; + .send_message( + c, + CreateMessage::new() + .add_file(CreateAttachment::bytes(p, "image.png")) + .embed({ + let mut e = CreateEmbed::new().attachment("image.png"); + if let Some(v) = d { + e = e.description(v); } - write!(s, "{} {n} ", emoji::mindustry::item(i)).unwrap(); - } - e.field("req", s, true); - e.title(name) - .footer(|f| f.text(format!("requested by {author}"))) - .color(SUCCESS) - }) - }) + let mut s = String::new(); + for (i, n) in cost.iter() { + if n == 0 { + continue; + } + write!(s, "{} {n} ", emoji::mindustry::item(i)).unwrap(); + } + e.field("req", s, true) + .title(name) + .footer(CreateEmbedFooter::new(format!("requested by {author}"))) + .color(SUCCESS) + }), + ) .await?, ) }; |