use std::future::{Future, IntoFuture}; use std::pin::Pin; use std::sync::Arc; use twilight_http::response::marker::EmptyBody; use twilight_http::{Error, Response}; use twilight_model::channel::Message; use twilight_model::channel::message::{Component as TwilightComponent, Embed}; use twilight_model::http::interaction::{InteractionResponse, InteractionResponseType}; use twilight_model::id::Id; use twilight_model::id::marker::{ChannelMarker, InteractionMarker}; use twilight_util::builder::InteractionResponseDataBuilder; use crate::framework::interactions::components::{ActionRow, Component}; use crate::framework::runtime::Runtime; pub struct MessageSender { channel_id: Id, rt: Arc>, content: Option, embeds: Vec, // Row index, component components: Vec<(u8, Arc>)>, } impl MessageSender where T: Send + Sync + 'static, E: Send + Sync + 'static, { pub fn new(channel_id: Id, rt: Arc>) -> Self { Self { channel_id, rt, content: None, components: vec![], embeds: vec![], } } pub fn content(mut self, content: impl ToString) -> Self { self.content = Some(content.to_string()); self } pub fn embed(mut self, embed: Embed) -> Self { self.embeds.push(embed); self } pub fn component(mut self, component: impl Component + 'static, row: u8) -> Self { self.components.push((row, Arc::new(component))); self } pub async fn send(self) -> Result, Error> { let mut builder = self.rt.http.create_message(self.channel_id); if let Some(content) = &self.content { builder = builder.content(content); } let mut current_row = ActionRow::new(&[]); let mut current_index = 0; let mut rows: Vec = vec![]; let mut custom_ids: Vec = vec![]; for (index, component) in self.components { if index != current_index { if !current_row.is_empty() { rows.push(current_row.build()); current_row = ActionRow::new(&[]); } current_index += 1; } let custom_id = component.custom_id(); if let Some(custom_id) = &custom_id { custom_ids.push(custom_id.clone()); self.rt.registry.register(custom_id, component.clone()); } current_row.add(custom_id.clone(), component.clone()); } if !current_row.is_empty() { rows.push(current_row.build()); } builder = builder.components(&rows); builder = builder.embeds(&self.embeds); let result = builder.await; if result.is_err() { for custom_id in custom_ids { self.rt.registry.unregister(custom_id); } } result } } impl IntoFuture for MessageSender { type Output = Result, Error>; type IntoFuture = Pin + Send>>; fn into_future(self) -> Self::IntoFuture { Box::pin(self.send()) } } pub struct OriginalMessageUpdater { interaction_id: Id, interaction_token: String, rt: Arc>, content: Option, embeds: Vec, // Row index, component components: Vec<(u8, Arc>)>, } impl OriginalMessageUpdater where T: Send + Sync + 'static, E: Send + Sync + 'static, { pub fn new( interaction_id: Id, interaction_token: String, rt: Arc>, ) -> Self { Self { interaction_id, interaction_token, rt, content: None, components: vec![], embeds: vec![], } } #[allow(dead_code)] pub fn content(mut self, content: impl ToString) -> Self { self.content = Some(content.to_string()); self } pub fn embed(mut self, embed: Embed) -> Self { self.embeds.push(embed); self } pub fn component(mut self, component: impl Component + 'static, row: u8) -> Self { self.components.push((row, Arc::new(component))); self } pub async fn send(self) -> Result, Error> { let mut builder = InteractionResponseDataBuilder::new(); if let Some(content) = &self.content { builder = builder.content(content); } let mut current_row = ActionRow::new(&[]); let mut current_index = 0; let mut rows: Vec = vec![]; let mut custom_ids: Vec = vec![]; for (index, component) in self.components { if index != current_index { if !current_row.is_empty() { rows.push(current_row.build()); current_row = ActionRow::new(&[]); } current_index += 1; } let custom_id = component.custom_id(); if let Some(custom_id) = &custom_id { custom_ids.push(custom_id.clone()); self.rt.registry.register(custom_id, component.clone()); } current_row.add(custom_id.clone(), component.clone()); } if !current_row.is_empty() { rows.push(current_row.build()); } builder = builder.components(rows); builder = builder.embeds(self.embeds); let result = self .rt .http .interaction(self.rt.app.id) .create_response( self.interaction_id, &self.interaction_token, &InteractionResponse { data: Some(builder.build()), kind: InteractionResponseType::UpdateMessage, }, ) .await; if result.is_err() { for custom_id in custom_ids { self.rt.registry.unregister(custom_id); } } result } } impl IntoFuture for OriginalMessageUpdater { type Output = Result, Error>; type IntoFuture = Pin + Send>>; fn into_future(self) -> Self::IntoFuture { Box::pin(self.send()) } }