Files
payphone/src/framework/commands/messages.rs
T
2026-03-07 19:27:40 -03:00

251 lines
6.6 KiB
Rust

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<T, E> {
channel_id: Id<ChannelMarker>,
rt: Arc<Runtime<T, E>>,
content: Option<String>,
embeds: Vec<Embed>,
// Row index, component
components: Vec<(u8, Arc<dyn Component<T, E>>)>,
}
impl<T, E> MessageSender<T, E>
where
T: Send + Sync + 'static,
E: Send + Sync + 'static,
{
pub fn new(channel_id: Id<ChannelMarker>, rt: Arc<Runtime<T, E>>) -> 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<T, E> + 'static, row: u8) -> Self {
self.components.push((row, Arc::new(component)));
self
}
pub async fn send(self) -> Result<Response<Message>, 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<TwilightComponent> = vec![];
let mut custom_ids: Vec<String> = 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<T: Send + Sync + 'static, E: Send + Sync + 'static> IntoFuture for MessageSender<T, E> {
type Output = Result<Response<Message>, Error>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.send())
}
}
pub struct OriginalMessageUpdater<T, E> {
interaction_id: Id<InteractionMarker>,
interaction_token: String,
rt: Arc<Runtime<T, E>>,
content: Option<String>,
embeds: Vec<Embed>,
// Row index, component
components: Vec<(u8, Arc<dyn Component<T, E>>)>,
}
impl<T, E> OriginalMessageUpdater<T, E>
where
T: Send + Sync + 'static,
E: Send + Sync + 'static,
{
pub fn new(
interaction_id: Id<InteractionMarker>,
interaction_token: String,
rt: Arc<Runtime<T, E>>,
) -> 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<T, E> + 'static, row: u8) -> Self {
self.components.push((row, Arc::new(component)));
self
}
pub async fn send(self) -> Result<Response<EmptyBody>, 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<TwilightComponent> = vec![];
let mut custom_ids: Vec<String> = 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<T: Send + Sync + 'static, E: Send + Sync + 'static> IntoFuture
for OriginalMessageUpdater<T, E>
{
type Output = Result<Response<EmptyBody>, Error>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.send())
}
}