html terminal
-rw-r--r--Cargo.toml7
-rw-r--r--src/bot/maps.rs52
-rw-r--r--src/bot/mod.rs69
-rw-r--r--src/bot/player.rs36
-rw-r--r--src/bot/status.rs30
-rw-r--r--src/bot/voting.rs187
-rw-r--r--src/webhook.rs33
7 files changed, 230 insertions, 184 deletions
diff --git a/Cargo.toml b/Cargo.toml
index f854730..4bf932b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,7 @@ tokio = { version = "1.28.2", features = [
], default-features = false }
tokio-stream = "0.1.14"
futures-util = "0.3.28"
-serenity = { version = "0.11.5", features = [
+serenity = { version = "0.12", features = [
"builder",
"client",
"utils",
@@ -30,7 +30,7 @@ serenity = { version = "0.11.5", features = [
"cache",
"gateway",
], default-features = false }
-poise = "0.5.5"
+poise = { git = "https://github.com/serenity-rs/poise" }
anyhow = "1.0.75"
regex = { version = "1.8.4", features = ["std"], default-features = false }
minify-js = "0.5.6"
@@ -59,3 +59,6 @@ opt-level = 3
[profile.dev.package.fimg]
opt-level = 3
+
+[patch.crates-io]
+serenity = { git = "https://github.com/bend-n/serenity", branch = "opt" }
diff --git a/src/bot/maps.rs b/src/bot/maps.rs
index b9df598..94321db 100644
--- a/src/bot/maps.rs
+++ b/src/bot/maps.rs
@@ -4,7 +4,6 @@ use futures_util::StreamExt;
use mindus::*;
use oxipng::*;
use poise::serenity_prelude::*;
-use std::borrow::Cow;
use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
use std::time::{Duration, Instant, SystemTime};
use tokio::sync::broadcast::{self, Sender};
@@ -50,15 +49,12 @@ pub async fn autocomplete<'a>(
pub async fn list(ctx: Context<'_>) -> Result<()> {
let _ = ctx.defer_or_broadcast().await;
let maps = Maps::get_all(&ctx.data().stdin).await;
- poise::send_reply(ctx, |m| {
- m.embed(|e| {
- for (k, v) in maps.iter().enumerate() {
- e.field((k + 1).to_string(), v, true);
- }
- e.description("map list.").color(SUCCESS)
- })
- })
- .await?;
+ let mut e = CreateEmbed::default();
+ for (k, v) in maps.iter().enumerate() {
+ e = e.field((k + 1).to_string(), v, true);
+ }
+ e = e.description("map list.").color(SUCCESS);
+ poise::send_reply(ctx, poise::CreateReply::default().embed(e)).await?;
Ok(())
}
@@ -148,18 +144,30 @@ impl MapImage {
pub async fn view(ctx: Context<'_>) -> Result<()> {
let _ = ctx.defer_or_broadcast().await;
let (i, info) = MAP_IMAGE.get(&ctx.data().stdin).await?;
- poise::send_reply(ctx, |m| {
- m.attachment(AttachmentType::Bytes {
- data: Cow::Borrowed(&i),
- filename: "0.png".to_string(),
- })
- .embed(|e| {
- if let Some(RenderInfo { deserialization, render, compression, total, name }) = info {
- e.footer(|f| f.text(format!("render of {name} took: {:.3}s (deser: {}ms, render: {:.3}s, compression: {:.3}s)", total.as_secs_f32(), deserialization.as_millis(), render.as_secs_f32(), compression.as_secs_f32())));
- }
- e.attachment("0.png").color(SUCCESS)
- })
- })
+ let mut e = CreateEmbed::default();
+ if let Some(RenderInfo {
+ deserialization,
+ render,
+ compression,
+ total,
+ name,
+ }) = info
+ {
+ e = e.footer(CreateEmbedFooter::new(format!(
+ "render of {name} took: {:.3}s (deser: {}ms, render: {:.3}s, compression: {:.3}s)",
+ total.as_secs_f32(),
+ deserialization.as_millis(),
+ render.as_secs_f32(),
+ compression.as_secs_f32()
+ )));
+ }
+ e = e.attachment("0.png").color(SUCCESS);
+ poise::send_reply(
+ ctx,
+ poise::CreateReply::default()
+ .attachment(CreateAttachment::bytes(&**i, "0.png"))
+ .embed(e),
+ )
.await?;
Ok(())
}
diff --git a/src/bot/mod.rs b/src/bot/mod.rs
index e85015f..4e960c1 100644
--- a/src/bot/mod.rs
+++ b/src/bot/mod.rs
@@ -17,6 +17,7 @@ use serenity::http::Http;
use serenity::model::channel::Message;
use std::fmt::Write;
use std::fs::read_to_string;
+use std::str::FromStr;
use std::sync::LazyLock;
use std::sync::{
atomic::{AtomicU8, Ordering},
@@ -48,8 +49,7 @@ macro_rules! send_ctx {
pub const SOURCE_GUILD: u64 = 1003092764919091282;
pub mod emojis {
use super::SOURCE_GUILD;
- use poise::serenity_prelude::Emoji;
- use serenity::http::client::Http;
+ use poise::serenity_prelude::*;
use std::sync::OnceLock;
macro_rules! create {
@@ -57,7 +57,7 @@ pub mod emojis {
$(pub static $i: OnceLock<Emoji> = OnceLock::new();)+
pub async fn load(c: &Http) {
- let all = c.get_emojis(SOURCE_GUILD).await.unwrap();
+ let all = c.get_emojis(SOURCE_GUILD.into()).await.unwrap();
for e in all {
match e.name.as_str() {
$(stringify!([< $i:lower >])=>{let _=$i.get_or_init(||e);},)+
@@ -94,7 +94,7 @@ const FAIL: (u8, u8, u8) = (255, 69, 0);
const DISABLED: (u8, u8, u8) = (112, 128, 144);
pub async fn in_guild(ctx: Context<'_>) -> Result<bool> {
- Ok(ctx.guild_id().map_or(false, |i| i.0 == GUILD))
+ Ok(ctx.guild_id().map_or(false, |i| i == GUILD))
}
pub async fn discord_to_mindustry(m: &Message, c: &serenity::client::Context) -> String {
@@ -103,7 +103,11 @@ pub async fn discord_to_mindustry(m: &Message, c: &serenity::client::Context) ->
for u in &m.mentions {
let mut at_distinct = String::with_capacity(33);
at_distinct.push('@');
- at_distinct.push_str(&u.nick_in(c, GuildId(GUILD)).await.unwrap_or(u.name.clone()));
+ at_distinct.push_str(
+ &u.nick_in(c, GuildId::new(GUILD))
+ .await
+ .unwrap_or(u.name.clone()),
+ );
let mut m = u.mention().to_string();
if !result.contains(&m) {
@@ -112,22 +116,19 @@ pub async fn discord_to_mindustry(m: &Message, c: &serenity::client::Context) ->
result = result.replace(&m, &at_distinct);
}
- for id in &m.mention_roles {
- let mention = id.mention().to_string();
+ if let Some(guild_id) = m.guild_id {
+ for id in &m.mention_roles {
+ let mention = id.mention().to_string();
- if let Some(role) = id.to_role_cached(c) {
- result = result.replace(&mention, &["@", &role.name].concat());
- } else {
- result = result.replace(&mention, "@deleted-role");
- }
- }
+ if let Some(guild) = <_ as AsRef<Cache>>::as_ref(c).guild(guild_id) {
+ if let Some(role) = guild.roles.get(id) {
+ result = result.replace(&mention, &format!("@{}", role.name));
+ continue;
+ }
+ }
- pub fn parse(x: &[u8]) -> u64 {
- let mut n = 0;
- for &b in x {
- n = n * 10 + (b - b'0') as u64
+ result = result.replace(&mention, "@deleted-role");
}
- n
}
static CHANNEL: LazyLock<Regex> = LazyLock::new(|| Regex::new("<#([0-9]+)>").unwrap());
@@ -138,7 +139,7 @@ pub async fn discord_to_mindustry(m: &Message, c: &serenity::client::Context) ->
&[
"#",
c.http()
- .get_channel(parse(m.get(1).unwrap().as_str().as_bytes()))
+ .get_channel(ChannelId::from_str(m.get(1).unwrap().as_str()).unwrap())
.await
.unwrap()
.guild()
@@ -178,7 +179,7 @@ impl Bot {
pub async fn spawn(stdout: broadcast::Receiver<String>, stdin: broadcast::Sender<String>) {
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>::builder()
.options(poise::FrameworkOptions {
commands: vec![
raw(),
@@ -204,18 +205,18 @@ impl Bot {
event_handler: |c, e, _, d| {
Box::pin(async move {
match e {
- poise::Event::Ready { .. } => {
+ FullEvent::Ready { .. } => {
println!("bot ready");
emojis::load(&c.http).await;
}
- 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
{
return Ok(());
}
- if CHANNEL == new_message.channel_id.0 {
+ if new_message.channel_id == CHANNEL {
say(c, new_message, d).await?;
}
}
@@ -226,16 +227,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::all())
.setup(|ctx, _ready, framework| {
Box::pin(async move {
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
@@ -246,7 +245,8 @@ impl Bot {
})
// todo: voting::fixall() auto
})
- });
+ })
+ .build();
tokio::spawn(async move {
let http = Http::new("");
let wh = std::env::var("WEBHOOK")
@@ -255,7 +255,13 @@ impl Bot {
SKIPPING.get_or_init(|| (wh.skip.clone(), wh.skipped.clone()));
wh.link(stdout).await;
});
- f.run().await.unwrap();
+ ClientBuilder::new(tok, GatewayIntents::all())
+ .framework(f)
+ .await
+ .unwrap()
+ .start()
+ .await
+ .unwrap();
}
}
@@ -264,7 +270,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();
@@ -324,7 +330,8 @@ async fn raw(
macro_rules! return_next {
($ctx:expr) => {{
let line = $crate::bot::get_nextblock().await;
- $ctx.send(|m| m.content(line)).await?;
+ $ctx.send(poise::CreateReply::default().content(line))
+ .await?;
return Ok(());
}};
}
diff --git a/src/bot/player.rs b/src/bot/player.rs
index 489a4ec..9cfa9ba 100644
--- a/src/bot/player.rs
+++ b/src/bot/player.rs
@@ -3,6 +3,7 @@ use crate::send;
use anyhow::Result;
use futures_util::StreamExt;
use itertools::Itertools;
+use poise::serenity_prelude::*;
use std::net::Ipv4Addr;
use std::str::FromStr;
use std::time::Instant;
@@ -88,23 +89,24 @@ pub async fn autocomplete<'a>(
pub async fn list(ctx: Context<'_>) -> Result<()> {
let _ = ctx.defer().await;
let players = Players::get_all(&ctx.data().stdin).await.unwrap().clone();
- poise::send_reply(ctx, |m| {
- m.embed(|e| {
- if players.is_empty() {
- return e.title("no players online.").color(FAIL);
- }
- e.fields(players.into_iter().map(|p| {
- let admins = if p.admin {
- "<:admin:1182128872435749005>"
- } else {
- ""
- };
- (p.name, admins, true)
- }))
- .description("currently online players.")
- .color(SUCCESS)
- })
- })
+ poise::send_reply(
+ ctx,
+ poise::CreateReply::default().embed(if players.is_empty() {
+ CreateEmbed::new().title("no players online.").color(FAIL)
+ } else {
+ CreateEmbed::new()
+ .fields(players.into_iter().map(|p| {
+ let admins = if p.admin {
+ "<:admin:1182128872435749005>"
+ } else {
+ ""
+ };
+ (p.name, admins, true)
+ }))
+ .description("currently online players.")
+ .color(SUCCESS)
+ }),
+ )
.await?;
Ok(())
}
diff --git a/src/bot/status.rs b/src/bot/status.rs
index 852042f..d0792ec 100644
--- a/src/bot/status.rs
+++ b/src/bot/status.rs
@@ -2,6 +2,7 @@ use super::{get_nextblock, Context, FAIL, SUCCESS};
use crate::send_ctx;
use anyhow::Result;
use itertools::Itertools;
+use poise::serenity_prelude::*;
use std::str::FromStr;
use tokio::time::{sleep, Duration};
@@ -58,7 +59,12 @@ pub async fn command(ctx: Context<'_>) -> Result<()> {
send_ctx!(ctx, "status")?;
macro_rules! fail {
($ctx:expr,$fail:expr) => {{
- poise::send_reply(ctx, |m| m.embed(|e| e.title("server down").color($fail))).await?;
+ poise::send_reply(
+ ctx,
+ poise::CreateReply::default()
+ .embed(CreateEmbed::new().title("server down").color($fail)),
+ )
+ .await?;
return Ok(());
}};
}
@@ -69,18 +75,20 @@ pub async fn command(ctx: Context<'_>) -> Result<()> {
let Some((tps, mem, pcount)) = parse(&block) else {
fail!(ctx, FAIL);
};
- poise::send_reply(ctx, |m| {
- m.embed(|e| {
- if pcount > 0 {
- e.footer(|f| f.text("see /players for player list"));
- }
- e.title("server online")
- .field("tps", tps, true)
+ poise::send_reply(
+ ctx,
+ poise::CreateReply::default().embed(if pcount > 0 {
+ CreateEmbed::new()
+ .title("server online")
+ .field("tps", format!("{tps}"), true)
.field("memory use", humanize_bytes(Size::Mb(f64::from(mem))), true)
- .field("players", pcount, true)
+ .field("players", format!("{pcount}"), true)
.color(SUCCESS)
- })
- })
+ .footer(CreateEmbedFooter::new("see /players for player list"))
+ } else {
+ CreateEmbed::new().title("no players online").color(FAIL)
+ }),
+ )
.await?;
Ok(())
}
diff --git a/src/bot/voting.rs b/src/bot/voting.rs
index 61b789e..83807f5 100644
--- a/src/bot/voting.rs
+++ b/src/bot/voting.rs
@@ -69,12 +69,19 @@ pub enum VoteData {
pub type Votes = Mutex<Vec<VoteData>>;
trait EmbedUtil {
- fn imageor<S: ToString>(&mut self, img: Option<S>) -> &mut Self;
- fn set_fields<M: IntoIterator<Item = (S, S)>, S: ToString>(&mut self, fields: M) -> &mut Self;
+ fn imageor<S>(self, img: Option<S>) -> Self
+ where
+ String: From<S>;
+ fn set_fields<M: IntoIterator<Item = (S, S)>, S: ToString>(self, fields: M) -> Self
+ where
+ String: From<S>;
}
impl EmbedUtil for CreateEmbed {
- fn imageor<S: ToString>(&mut self, img: Option<S>) -> &mut Self {
+ fn imageor<S: Into<String>>(self, img: Option<S>) -> Self
+ where
+ String: From<S>,
+ {
if let Some(iuri) = img {
self.image(iuri)
} else {
@@ -82,9 +89,12 @@ impl EmbedUtil for CreateEmbed {
}
}
- fn set_fields<M: IntoIterator<Item = (S, S)>, S: ToString>(&mut self, fields: M) -> &mut Self {
+ fn set_fields<M: IntoIterator<Item = (S, S)>, S: ToString>(mut self, fields: M) -> Self
+ where
+ String: From<S>,
+ {
for (k, v) in fields {
- self.field(k, v, false);
+ self = self.field(k, v, false);
}
self
}
@@ -180,27 +190,29 @@ impl VoteData {
pub async fn begin(mut self, ctx: Context<'_>) -> Result<Self> {
self.set_end();
let o = self.options();
- let handle = poise::send_reply(ctx, |m| {
- m.embed(|e| {
- e.imageor(o.image.as_ref())
- .color(SUCCESS)
- .title(&o.title)
- .description(format!("vote ends {}", self.end_stamp()))
- .set_fields(&o.fields)
- })
- .components(|c| {
- c.create_action_row(|r| {
- for (n, option) in o.options.iter().enumerate() {
- r.create_button(|b| {
- b.custom_id(format!("{}{n}", self.id()))
+ let handle = poise::send_reply(
+ ctx,
+ poise::CreateReply::default()
+ .embed(
+ CreateEmbed::new()
+ .imageor(o.image.as_ref())
+ .color(SUCCESS)
+ .title(&o.title)
+ .description(format!("vote ends {}", self.end_stamp()))
+ .set_fields(&o.fields),
+ )
+ .components(vec![CreateActionRow::Buttons(
+ o.options
+ .iter()
+ .enumerate()
+ .map(|(n, option)| {
+ CreateButton::new(format!("{}{n}", self.id()))
.label(option)
.style(o.styles[n])
- });
- }
- r
- })
- })
- })
+ })
+ .collect(),
+ )]),
+ )
.await?;
let msg = handle.into_message().await?;
self.set_reply(&ctx, msg);
@@ -255,7 +267,7 @@ impl VoteData {
let ctx_id_len = ctx_id.to_string().len();
let o = self.options().clone();
let timestamp = self.end_stamp();
- while let Some(press) = CollectComponentInteraction::new(ctx)
+ while let Some(press) = ComponentInteractionCollector::new(ctx)
.filter(move |press| press.data.custom_id.starts_with(&ctx_id.to_string()))
.timeout(dead)
.await
@@ -276,24 +288,30 @@ impl VoteData {
};
self.save_ref(ctx)?;
let (_m, _) = tokio::join!(
- press.create_followup_message(ctx, |m| { m.ephemeral(true).content(s) }),
- press.create_interaction_response(ctx, |c| {
- c.kind(InteractionResponseType::UpdateMessage)
- .interaction_response_data(|m| {
- m.embed(|e| {
- for (option, votes) in
- self.summarize(ctx, o.options.len()).iter().enumerate()
- {
- e.field(&o.options[option], votes, true);
- }
- e.imageor(o.image.as_ref())
- .color(SUCCESS)
- .title(&o.title)
- .set_fields(&o.fields)
- .description(format!("vote ends {timestamp}"))
- })
+ press.create_followup(
+ ctx,
+ CreateInteractionResponseFollowup::default()
+ .ephemeral(true)
+ .content(s)
+ ),
+ press.create_response(
+ ctx,
+ CreateInteractionResponse::UpdateMessage(
+ CreateInteractionResponseMessage::new().embed({
+ let mut e = CreateEmbed::new();
+ for (option, votes) in
+ self.summarize(ctx, o.options.len()).iter().enumerate()
+ {
+ e = e.field(&o.options[option], votes.to_string(), true);
+ }
+ e.imageor(o.image.as_ref())
+ .color(SUCCESS)
+ .title(&o.title)
+ .set_fields(&o.fields)
+ .description(format!("vote ends {timestamp}"))
})
- })
+ )
+ )
);
// let m = m?;
// let http = ctx.serenity_context().http.clone();
@@ -313,38 +331,41 @@ impl VoteData {
let _ = std::fs::remove_file(p);
}
self.get_reply(ctx)
- .edit(ctx, |m| {
- m.embed(|e| {
- for (option, votes) in self
- .remove(ctx)
- .summarize(ctx, o.options.len())
- .iter()
- .enumerate()
- {
- e.field(&o.options[option], votes, true);
- }
- e.color(DISABLED)
- .title(&o.title)
- .imageor(o.image.as_ref())
- .set_fields(o.fields)
- .description(format!("vote ended!"))
- })
- .components(|c| {
- c.set_action_row({
- let mut r = CreateActionRow::default();
- for (n, option) in o.options.iter().enumerate() {
- r.create_button(|b| {
- b.label(option)
- .disabled(true)
- .style(o.styles[n])
- .custom_id("_")
- });
+ .edit(
+ ctx,
+ EditMessage::default()
+ .embed({
+ let mut e = CreateEmbed::new();
+
+ for (option, votes) in self
+ .remove(ctx)
+ .summarize(ctx, o.options.len())
+ .iter()
+ .enumerate()
+ {
+ e = e.field(&o.options[option], votes.to_string(), true);
}
- r
+ e.color(DISABLED)
+ .title(&o.title)
+ .imageor(o.image.as_ref())
+ .set_fields(o.fields)
+ .description(format!("vote ended!"))
})
- })
- })
+ .components(vec![CreateActionRow::Buttons(
+ o.options
+ .iter()
+ .enumerate()
+ .map(|(n, option)| {
+ CreateButton::new("_")
+ .label(option)
+ .disabled(true)
+ .style(o.styles[n])
+ })
+ .collect(),
+ )]),
+ )
.await?;
+
Ok(())
}
}
@@ -453,7 +474,7 @@ pub async fn create(
async fn fix(ctx: &Context<'_>, data: BufReader<std::fs::File>) -> Result<()> {
let mut v: BeforePushVoteData = serde_json::from_reader(data)?;
- let m = ctx.http().get_message(v.cid.0, v.mid.0).await?;
+ let m = ctx.http().get_message(v.cid, v.mid).await?;
let end = dbg!(m.timestamp.unix_timestamp()) as u64;
v.reply = Some(Box::new(m));
let now = SystemTime::now()
@@ -496,7 +517,11 @@ pub async fn fixall(ctx: Context<'_>) -> Result<()> {
}
}
let msg = format!("fixed {}", futs.len());
- poise::send_reply(ctx, |m| m.content(msg).ephemeral(true)).await?;
+ poise::send_reply(
+ ctx,
+ poise::CreateReply::default().content(msg).ephemeral(true),
+ )
+ .await?;
future::join_all(futs).await;
Ok(())
}
@@ -569,11 +594,13 @@ pub async fn list(ctx: Context<'_>, #[description = "the vote title"] vote: Stri
VoteData::After(_) => unreachable!(),
}
};
- poise::send_reply(ctx, |m| {
- m.allowed_mentions(|x| x.empty_parse()).embed(|e| {
+ poise::send_reply(
+ ctx,
+ poise::CreateReply::default().embed({
+ let mut e = CreateEmbed::default();
let mut votes: HashMap<usize, Vec<u64>> = HashMap::new();
for (user, vote) in vd.votes {
- votes.entry(vote).or_default().push(user.0);
+ votes.entry(vote).or_default().push(user.get());
}
for (vote, voters) in votes {
let mut s = vec![];
@@ -581,13 +608,13 @@ pub async fn list(ctx: Context<'_>, #[description = "the vote title"] vote: Stri
for person in voters {
s.push(format!("<@{person}>"));
}
- e.field(&vd.options.options[vote], s.join("\n"), false);
+ e = e.field(&vd.options.options[vote], s.join("\n"), false);
}
e.color(SUCCESS)
.title(format!("voter list for {vote}"))
- .footer(|f| f.text("privacy is a illusion"))
- })
- })
+ .footer(CreateEmbedFooter::new("privacy is a illusion"))
+ }),
+ )
.await?;
Ok(())
}
diff --git a/src/webhook.rs b/src/webhook.rs
index 6b04b78..dcf9f16 100644
--- a/src/webhook.rs
+++ b/src/webhook.rs
@@ -1,6 +1,6 @@
-use poise::serenity_prelude::Webhook as RealHook;
+use poise::serenity_prelude::{Webhook as RealHook, *};
use regex::Regex;
-use serenity::{builder::ExecuteWebhook, http::Http, json};
+use serenity::{builder::ExecuteWebhook, http::Http};
use std::convert::AsRef;
use std::sync::{
atomic::{AtomicU8, Ordering},
@@ -30,34 +30,25 @@ impl<'a> Webhook<'a> {
async fn send<F>(&self, block: F)
where
- for<'b> F: FnOnce(&'b mut ExecuteWebhook<'a>) -> &'b mut ExecuteWebhook<'a>,
+ for<'b> F: FnOnce(ExecuteWebhook) -> ExecuteWebhook,
{
- let mut execute_webhook = ExecuteWebhook::default();
- execute_webhook.allowed_mentions(|m| {
- m.empty_parse()
+ let execute_webhook = ExecuteWebhook::default().allowed_mentions(
+ CreateAllowedMentions::default()
.roles(vec![1110088946374938715, 1133416252791074877])
.users(vec![
696196765564534825,
600014432298598400,
1173213085553660034,
- ])
- });
- block(&mut execute_webhook);
-
- let map = json::hashmap_to_json_map(execute_webhook.0);
+ ]),
+ );
+ let execute_webhook = block(execute_webhook);
if let Err(e) = self
- .http
- .as_ref()
- .execute_webhook(
- self.inner.id.0,
- self.inner.token.as_ref().unwrap(),
- false,
- &map,
- )
+ .inner
+ .execute(self.http, false, execute_webhook.clone())
.await
{
- println!("sending {map:#?} got error {e}.");
- };
+ println!("sending {execute_webhook:#?} got error {e}.");
+ }
}
async fn send_message(&self, username: &str, content: &str) {