Responding to chat pings
This commit is contained in:
parent
427afa921d
commit
2559ef4452
1 changed files with 226 additions and 164 deletions
390
src/chatbot.rs
390
src/chatbot.rs
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue