use futures::future::join_all; use twilight_http::Client; use twilight_model::channel::{message::{AllowedMentions, MentionType, MessageType}, Message}; use std::sync::Arc; use tokio::sync::Mutex; use twilight_model::http::attachment::Attachment; pub enum ProxyError { InvalidMessage(twilight_validate::message::MessageValidationError), AttachmentRequest(reqwest::Error), MessageCreate(twilight_http::error::Error), ResponseDeserialization(twilight_http::response::DeserializeBodyError), } impl From for ProxyError { fn from(value: twilight_validate::message::MessageValidationError) -> Self { ProxyError::InvalidMessage(value) } } impl From for ProxyError{ fn from(value: reqwest::Error) -> Self { ProxyError::AttachmentRequest(value) } } impl From for ProxyError{ fn from(value: twilight_http::error::Error) -> Self { ProxyError::MessageCreate(value) } } impl From for ProxyError{ fn from(value: twilight_http::response::DeserializeBodyError) -> Self { ProxyError::ResponseDeserialization(value) } } pub async fn duplicate_message(client: &Arc>, message: &Message, content: &str) -> Result { let client = client.lock().await; let mut create_message = client.create_message(message.channel_id).content(content)?; let mut allowed_mentions = AllowedMentions { parse: Vec::new(), replied_user: false, roles: message.mention_roles.clone(), users: message.mentions.iter().map(|user| user.id).collect(), }; if message.mention_everyone { allowed_mentions.parse.push(MentionType::Everyone); } if message.kind == MessageType::Reply { if let Some(ref_message) = message.referenced_message.as_ref() { create_message = create_message.reply(ref_message.id); let pings_referenced_author = message .mentions .iter() .any(|user| user.id == ref_message.author.id); if pings_referenced_author { allowed_mentions.replied_user = true; } else { allowed_mentions.replied_user = false; } } else { panic!("Cannot proxy message: Was reply but no referenced message"); } } let attachments = join_all(message.attachments.iter().map(|attachment| async { let filename = attachment.filename.clone(); let description_opt = attachment.description.clone(); let bytes = reqwest::get(attachment.proxy_url.clone()) .await? .bytes() .await?; let mut new_attachment = Attachment::from_bytes(filename, bytes.try_into().unwrap(), attachment.id.into()); if let Some(description) = description_opt { new_attachment.description(description); } Ok(new_attachment) })) .await .iter() .filter_map( |result: &Result| match result { Ok(attachment) => Some(attachment.clone()), Err(_) => None, }, ) .collect::>(); if attachments.len() > 0 { create_message = create_message.attachments(attachments.as_slice())?; } if let Some(flags) = message.flags { create_message = create_message.flags(flags); } create_message = create_message.allowed_mentions(Some(&allowed_mentions)); let new_message = create_message.await?.model().await?; Ok(new_message) }