From 6b07721ffa7d93721c18f984094b1b99b32c7b88 Mon Sep 17 00:00:00 2001 From: videogame hacker Date: Sat, 16 Apr 2022 10:45:42 +0100 Subject: [PATCH] Use a webhook for Discord if one is available --- mid-chat/src/lib.rs | 1 + services/phoebe-discord/Cargo.toml | 1 + services/phoebe-discord/src/handler.rs | 4 + services/phoebe-discord/src/sender.rs | 106 ++++++++++++++++++++++--- 4 files changed, 103 insertions(+), 9 deletions(-) diff --git a/mid-chat/src/lib.rs b/mid-chat/src/lib.rs index 8fa01d7..f74f77a 100644 --- a/mid-chat/src/lib.rs +++ b/mid-chat/src/lib.rs @@ -6,6 +6,7 @@ pub struct ChatAuthor { pub reference: ChatReference, pub display_name: String, pub display_color: Option<[u8; 3]>, + pub avatar_url: String, } mod content; diff --git a/services/phoebe-discord/Cargo.toml b/services/phoebe-discord/Cargo.toml index 7d48610..03fb235 100644 --- a/services/phoebe-discord/Cargo.toml +++ b/services/phoebe-discord/Cargo.toml @@ -10,3 +10,4 @@ sqlx = { version = "0.5", features = ["runtime-tokio-native-tls", "sqlite"] } tracing = "0.1" tokio = { version = "1", features = ["full"] } discord_message_format = { git = "https://git.lavender.software/charlotte/discord-message-format.git" } +serde_json = "1.0.79" diff --git a/services/phoebe-discord/src/handler.rs b/services/phoebe-discord/src/handler.rs index 946f981..3b2dccf 100644 --- a/services/phoebe-discord/src/handler.rs +++ b/services/phoebe-discord/src/handler.rs @@ -32,6 +32,10 @@ impl DiscordHandler { reference: discord_reference(message.author.id), display_name, display_color, + avatar_url: message + .author + .static_avatar_url() + .unwrap_or_else(|| message.author.default_avatar_url()), } } } diff --git a/services/phoebe-discord/src/sender.rs b/services/phoebe-discord/src/sender.rs index ba4b9a5..beeec41 100644 --- a/services/phoebe-discord/src/sender.rs +++ b/services/phoebe-discord/src/sender.rs @@ -1,25 +1,82 @@ use phoebe::{ mid_chat::{ChatMessage, ChatMessageReference, ChatReference}, - prelude::{future, Result}, + prelude::*, }; use serenity::{model::prelude::*, prelude::*}; use crate::{chat_conv, discord_reference, DiscordService}; +async fn get_or_create_webhook_for_channel( + discord: &mut DiscordService, + channel: &ChannelId, +) -> Option { + if let Ok(webhooks) = channel.webhooks(&discord.ctx).await { + for webhook in webhooks { + if matches!(webhook.name.as_deref(), Some("Phoebe")) { + return Some(webhook); + } + } + } + + if let Ok(webhook) = channel.create_webhook(&discord.ctx, "Phoebe").await { + return Some(webhook); + } + + None +} + +async fn create_webhook_reply_embeds( + discord_ctx: &Context, + channel_id: ChannelId, + message_id: MessageId, +) -> Vec { + if let Ok(replied_message) = channel_id.message(discord_ctx, message_id).await { + let replied_author_name = format!( + "{} ↩️", + replied_message + .author_nick(discord_ctx) + .await + .as_ref() + .unwrap_or(&replied_message.author.name) + ); + + let reply_description = format!( + "**[Reply to:]({})**\n{}", + replied_message.id.link( + channel_id, + discord_ctx + .cache + .guild_channel(channel_id) + .await + .map(|gc| gc.guild_id) + ), + &replied_message.content + ); + + return vec![Embed::fake(|e| { + e.author(|a| { + a.icon_url( + &replied_message + .author + .static_avatar_url() + .unwrap_or_else(|| replied_message.author.default_avatar_url()), + ) + .name(replied_author_name) + }) + .description(reply_description) + })]; + } + + vec![] +} + pub async fn send_discord_message( discord: &mut DiscordService, source: &ChatMessage, destination_channel: ChatReference, ) -> Result { - // TODO: If we have a webhook we should use the webhook - let channel_id = destination_channel.id.parse::()?; - let formatted_message = chat_conv::format(&source.content); - let content = format!( - "{} ({}): {}", - source.author.display_name, source.author.reference.service, formatted_message - ); let discord_reply = if let Some(reply) = &source.replying { if let Some(reply_ref) = discord @@ -37,6 +94,38 @@ pub async fn send_discord_message( None }; + if let Some(webhook) = get_or_create_webhook_for_channel(&mut *discord, &channel_id).await { + let reply_embeds = if let Some((channel, message)) = discord_reply { + create_webhook_reply_embeds(&discord.ctx, channel, message).await + } else { + vec![] + }; + + if let Some(sent_message) = webhook + .execute(&discord.ctx, true, |w| { + w.content(chat_conv::format(&source.content)) + .username(format!( + "{} ({})", + &source.author.display_name, &source.author.reference.service + )) + .avatar_url(&source.author.avatar_url) + .embeds(reply_embeds) + }) + .await? + { + return Ok(ChatMessageReference::new( + discord_reference(sent_message.channel_id), + sent_message.id, + )); + } + } + let content = format!( + "{} ({}): {}", + source.author.display_name, + source.author.reference.service, + chat_conv::format(&source.content) + ); + let sent_message = channel_id .send_message(&discord.ctx, move |m| { let m = m.content(content); @@ -47,7 +136,6 @@ pub async fn send_discord_message( } }) .await?; - Ok(ChatMessageReference::new( discord_reference(sent_message.channel_id), sent_message.id,