Responding to chat pings

This commit is contained in:
Daniel Flanagan 2024-04-12 11:59:46 -05:00
parent 427afa921d
commit 2559ef4452

View file

@ -6,9 +6,229 @@
use std::{any::Any, future};
use discord::{
model::{Event, Message},
Discord,
model::{ChannelId, Event, Message, ReadyEvent},
Discord as DDiscord,
};
use tokio::sync::Mutex;
const COMMAND_PREFIX: &str = "!";
struct Discord {
discord: DDiscord,
connection: Option<Arc<Mutex<discord::Connection>>>,
}
impl Discord {
pub fn try_new(conf: Arc<Config>) -> Result<Self> {
let discord = DDiscord::from_bot_token(
conf.discord
.as_ref()
.unwrap()
.bot_token
.clone()
.expose_secret(),
)?;
Ok(Self {
discord,
connection: None,
})
}
pub async fn connect(&mut self) -> Result<ReadyEvent> {
if self.connection.is_some() {
return Err(anyhow::anyhow!("already connected"));
}
let (connection, ready_ev) = self.discord.connect()?;
self.connection = Some(Arc::new(Mutex::new(connection)));
Ok(ready_ev)
}
pub async fn handle_commands(self: Arc<Self>) -> Result<()> {
if let Some(conn) = self.connection.clone() {
loop {
// TODO: I'm suspicious this will just always be locked here and
// I'm doing something stupid.
let mut conn = conn.lock().await;
while let Ok(event) = conn.recv_event() {
let rself = self.clone();
tokio::spawn(async move {
match rself.handle_event(event).await {
Ok(_) => {}
Err(err) => {
error!("Failed to handle Discord event: {err}")
}
}
});
}
}
}
Ok(())
}
pub async fn handle_event(&self, event: Event) -> Result<()> {
match event {
Event::Ready(_) => return Ok(self.ignore_event(event)),
Event::Resumed { trace: _ } => return Ok(self.ignore_event(event)),
Event::UserUpdate(_) => return Ok(self.ignore_event(event)),
Event::UserNoteUpdate(_, _) => return Ok(self.ignore_event(event)),
Event::UserSettingsUpdate {
detect_platform_accounts: _,
developer_mode: _,
enable_tts_command: _,
inline_attachment_media: _,
inline_embed_media: _,
locale: _,
message_display_compact: _,
render_embeds: _,
server_positions: _,
show_current_game: _,
status: _,
theme: _,
convert_emoticons: _,
friend_source_flags: _,
} => return Ok(self.ignore_event(event)),
Event::UserServerSettingsUpdate(_) => return Ok(self.ignore_event(event)),
Event::VoiceStateUpdate(_, _) => return Ok(self.ignore_event(event)),
Event::VoiceServerUpdate {
server_id: _,
channel_id: _,
endpoint: _,
token: _,
} => return Ok(self.ignore_event(event)),
Event::CallCreate(_) => return Ok(self.ignore_event(event)),
Event::CallUpdate {
channel_id: _,
message_id: _,
region: _,
ringing: _,
} => return Ok(self.ignore_event(event)),
Event::CallDelete(_) => return Ok(self.ignore_event(event)),
Event::ChannelRecipientAdd(_, _) => return Ok(self.ignore_event(event)),
Event::ChannelRecipientRemove(_, _) => return Ok(self.ignore_event(event)),
Event::TypingStart {
channel_id: _,
user_id: _,
timestamp: _,
} => return Ok(self.ignore_event(event)),
Event::PresenceUpdate {
presence: _,
server_id: _,
roles: _,
} => return Ok(self.ignore_event(event)),
Event::PresencesReplace(_) => return Ok(self.ignore_event(event)),
Event::RelationshipAdd(_) => return Ok(self.ignore_event(event)),
Event::RelationshipRemove(_, _) => return Ok(self.ignore_event(event)),
Event::MessageCreate(msg) => return Ok(self.handle_message(msg)?),
Event::MessageUpdate {
id: _,
channel_id: _,
kind: _,
content: _,
nonce: _,
tts: _,
pinned: _,
timestamp: _,
edited_timestamp: _,
author: _,
mention_everyone: _,
mentions: _,
mention_roles: _,
attachments: _,
embeds: _,
} => return Ok(self.ignore_event(event)),
Event::MessageAck {
channel_id: _,
message_id: _,
} => return Ok(self.ignore_event(event)),
Event::MessageDelete {
channel_id: _,
message_id: _,
} => return Ok(self.ignore_event(event)),
Event::MessageDeleteBulk {
channel_id: _,
ids: _,
} => return Ok(self.ignore_event(event)),
Event::ServerCreate(_) => return Ok(self.ignore_event(event)),
Event::ServerUpdate(_) => return Ok(self.ignore_event(event)),
Event::ServerDelete(_) => return Ok(self.ignore_event(event)),
Event::ServerMemberAdd(_, _) => return Ok(self.ignore_event(event)),
Event::ServerMemberUpdate {
server_id: _,
roles: _,
user: _,
nick: _,
} => return Ok(self.ignore_event(event)),
Event::ServerMemberRemove(_, _) => return Ok(self.ignore_event(event)),
Event::ServerMembersChunk(_, _) => return Ok(self.ignore_event(event)),
Event::ServerSync {
server_id: _,
large: _,
members: _,
presences: _,
} => return Ok(self.ignore_event(event)),
Event::ServerRoleCreate(_, _) => return Ok(self.ignore_event(event)),
Event::ServerRoleUpdate(_, _) => return Ok(self.ignore_event(event)),
Event::ServerRoleDelete(_, _) => return Ok(self.ignore_event(event)),
Event::ServerBanAdd(_, _) => return Ok(self.ignore_event(event)),
Event::ServerBanRemove(_, _) => return Ok(self.ignore_event(event)),
Event::ServerIntegrationsUpdate(_) => return Ok(self.ignore_event(event)),
Event::ServerEmojisUpdate(_, _) => return Ok(self.ignore_event(event)),
Event::ChannelCreate(_) => return Ok(self.ignore_event(event)),
Event::ChannelUpdate(_) => return Ok(self.ignore_event(event)),
Event::ChannelDelete(_) => return Ok(self.ignore_event(event)),
Event::ChannelPinsAck {
channel_id: _,
timestamp: _,
} => return Ok(self.ignore_event(event)),
Event::ChannelPinsUpdate {
channel_id: _,
last_pin_timestamp: _,
} => return Ok(self.ignore_event(event)),
Event::ReactionAdd(_) => return Ok(self.ignore_event(event)),
Event::ReactionRemove(_) => return Ok(self.ignore_event(event)),
Event::Unknown(_, _) => return Ok(self.ignore_event(event)),
_ => return Ok(self.ignore_event(event)),
}
}
pub fn ignore_event(&self, event: Event) -> () {
let event_type_id = event.type_id();
info!("Ignoring Discord event of type: {event_type_id:?}")
}
pub fn handle_message(&self, msg: Message) -> Result<()> {
info!(
"Recieved Discord message in channel {} with content: {}",
msg.channel_id, msg.content
);
let text = msg.content.clone();
let trimmed_text = text.trim();
if trimmed_text.starts_with(COMMAND_PREFIX) {
self.handle_text_command(trimmed_text, msg)?
}
Ok(())
}
fn send_message(&self, channel: ChannelId, text: &str) -> Result<Message> {
self.discord
.send_message(channel, text, "", false)
.map_err(|e| e.into())
}
fn handle_text_command(&self, trimmed_text: &str, msg: Message) -> Result<()> {
let trimmed_text = trimmed_text.trim_start_matches(COMMAND_PREFIX);
match trimmed_text {
s if s.starts_with("ping") => {
let _ = self.send_message(msg.channel_id, "`pong`")?;
}
_ => {}
}
Ok(())
}
}
use crate::prelude::*;
@ -19,167 +239,9 @@ pub async fn start(conf: Arc<Config>) -> Result<()> {
future::pending::<()>().await;
}
let discord = Discord::from_bot_token(
conf.discord
.as_ref()
.unwrap()
.bot_token
.clone()
.expose_secret(),
)?;
let (mut conn, ready_ev) = discord.connect()?;
let mut discord = Discord::try_new(conf.clone())?;
let ready_ev = discord.connect().await;
info!("Discord connection ready: {ready_ev:?}");
while let Ok(event) = conn.recv_event() {
tokio::spawn(async move {
match handle_event(event).await {
Ok(_) => {}
Err(err) => {
error!("Failed to handle Discord event: {err}")
}
}
});
}
Ok(())
}
pub async fn handle_event(event: Event) -> Result<()> {
match event {
Event::Ready(_) => return Ok(ignore_event(event)),
Event::Resumed { trace: _ } => return Ok(ignore_event(event)),
Event::UserUpdate(_) => return Ok(ignore_event(event)),
Event::UserNoteUpdate(_, _) => return Ok(ignore_event(event)),
Event::UserSettingsUpdate {
detect_platform_accounts: _,
developer_mode: _,
enable_tts_command: _,
inline_attachment_media: _,
inline_embed_media: _,
locale: _,
message_display_compact: _,
render_embeds: _,
server_positions: _,
show_current_game: _,
status: _,
theme: _,
convert_emoticons: _,
friend_source_flags: _,
} => return Ok(ignore_event(event)),
Event::UserServerSettingsUpdate(_) => return Ok(ignore_event(event)),
Event::VoiceStateUpdate(_, _) => return Ok(ignore_event(event)),
Event::VoiceServerUpdate {
server_id: _,
channel_id: _,
endpoint: _,
token: _,
} => return Ok(ignore_event(event)),
Event::CallCreate(_) => return Ok(ignore_event(event)),
Event::CallUpdate {
channel_id: _,
message_id: _,
region: _,
ringing: _,
} => return Ok(ignore_event(event)),
Event::CallDelete(_) => return Ok(ignore_event(event)),
Event::ChannelRecipientAdd(_, _) => return Ok(ignore_event(event)),
Event::ChannelRecipientRemove(_, _) => return Ok(ignore_event(event)),
Event::TypingStart {
channel_id: _,
user_id: _,
timestamp: _,
} => return Ok(ignore_event(event)),
Event::PresenceUpdate {
presence: _,
server_id: _,
roles: _,
} => return Ok(ignore_event(event)),
Event::PresencesReplace(_) => return Ok(ignore_event(event)),
Event::RelationshipAdd(_) => return Ok(ignore_event(event)),
Event::RelationshipRemove(_, _) => return Ok(ignore_event(event)),
Event::MessageCreate(msg) => return Ok(handle_message(msg)),
Event::MessageUpdate {
id: _,
channel_id: _,
kind: _,
content: _,
nonce: _,
tts: _,
pinned: _,
timestamp: _,
edited_timestamp: _,
author: _,
mention_everyone: _,
mentions: _,
mention_roles: _,
attachments: _,
embeds: _,
} => return Ok(ignore_event(event)),
Event::MessageAck {
channel_id: _,
message_id: _,
} => return Ok(ignore_event(event)),
Event::MessageDelete {
channel_id: _,
message_id: _,
} => return Ok(ignore_event(event)),
Event::MessageDeleteBulk {
channel_id: _,
ids: _,
} => return Ok(ignore_event(event)),
Event::ServerCreate(_) => return Ok(ignore_event(event)),
Event::ServerUpdate(_) => return Ok(ignore_event(event)),
Event::ServerDelete(_) => return Ok(ignore_event(event)),
Event::ServerMemberAdd(_, _) => return Ok(ignore_event(event)),
Event::ServerMemberUpdate {
server_id: _,
roles: _,
user: _,
nick: _,
} => return Ok(ignore_event(event)),
Event::ServerMemberRemove(_, _) => return Ok(ignore_event(event)),
Event::ServerMembersChunk(_, _) => return Ok(ignore_event(event)),
Event::ServerSync {
server_id: _,
large: _,
members: _,
presences: _,
} => return Ok(ignore_event(event)),
Event::ServerRoleCreate(_, _) => return Ok(ignore_event(event)),
Event::ServerRoleUpdate(_, _) => return Ok(ignore_event(event)),
Event::ServerRoleDelete(_, _) => return Ok(ignore_event(event)),
Event::ServerBanAdd(_, _) => return Ok(ignore_event(event)),
Event::ServerBanRemove(_, _) => return Ok(ignore_event(event)),
Event::ServerIntegrationsUpdate(_) => return Ok(ignore_event(event)),
Event::ServerEmojisUpdate(_, _) => return Ok(ignore_event(event)),
Event::ChannelCreate(_) => return Ok(ignore_event(event)),
Event::ChannelUpdate(_) => return Ok(ignore_event(event)),
Event::ChannelDelete(_) => return Ok(ignore_event(event)),
Event::ChannelPinsAck {
channel_id: _,
timestamp: _,
} => return Ok(ignore_event(event)),
Event::ChannelPinsUpdate {
channel_id: _,
last_pin_timestamp: _,
} => return Ok(ignore_event(event)),
Event::ReactionAdd(_) => return Ok(ignore_event(event)),
Event::ReactionRemove(_) => return Ok(ignore_event(event)),
Event::Unknown(_, _) => return Ok(ignore_event(event)),
_ => return Ok(ignore_event(event)),
}
}
pub fn ignore_event(event: Event) -> () {
let event_type_id = event.type_id();
info!("Ignoring Discord event of type: {event_type_id:?}")
}
pub fn handle_message(msg: Message) -> () {
info!(
"Recieved Discord message in channel {} with content: {}",
msg.channel_id, msg.content
);
return ();
let adiscord = Arc::new(discord);
adiscord.handle_commands().await
}