251 lines
6.6 KiB
Rust
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())
|
|
}
|
|
}
|