Added basic listener

+ Only support chat events now
+ Created a listener for host message snooping
+ Clippy + fmt
main
Joey Hines 2023-01-08 13:44:11 -07:00
parent 4b7570b24c
commit 7af3bab486
Signed by: joeyahines
GPG Key ID: 995E531F7A569DDB
7 changed files with 164 additions and 21 deletions

View File

@ -167,7 +167,7 @@ async fn say(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
let data = ctx.data.read().await; let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap(); let global_data = data.get::<GlobalData>().unwrap();
let global_data = global_data.lock().await; let mut global_data = global_data.lock().await;
let msg = WoxlfMessage::default() let msg = WoxlfMessage::default()
.source(MessageSource::Host) .source(MessageSource::Host)
@ -176,7 +176,7 @@ async fn say(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
.content(args.rest()) .content(args.rest())
.clone(); .clone();
dispatch_message(ctx, &global_data, msg).await?; dispatch_message(ctx, &mut global_data, msg).await?;
Ok(()) Ok(())
} }
@ -188,7 +188,7 @@ async fn broadcast(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
let data = ctx.data.read().await; let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap(); let global_data = data.get::<GlobalData>().unwrap();
let global_data = global_data.lock().await; let mut global_data = global_data.lock().await;
let broadcast = global_data let broadcast = global_data
.templates()? .templates()?
@ -201,7 +201,7 @@ async fn broadcast(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
.median(Median::Webhook) .median(Median::Webhook)
.clone(); .clone();
dispatch_message(ctx, &global_data, woxlf_msg).await?; dispatch_message(ctx, &mut global_data, woxlf_msg).await?;
Ok(()) Ok(())
} }
@ -210,8 +210,8 @@ async fn broadcast(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
#[only_in(guilds)] #[only_in(guilds)]
#[allowed_roles("wolfx host")] #[allowed_roles("wolfx host")]
async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let mut data = ctx.data.write().await; let data = ctx.data.read().await;
let global_data = data.get_mut::<GlobalData>().unwrap(); let global_data = data.get::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).unwrap(); let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await; let mut global_data = global_data.lock().await;
@ -237,7 +237,7 @@ async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
.content(&broadcast) .content(&broadcast)
.clone(); .clone();
dispatch_message(ctx, &global_data, woxlf_msg).await?; dispatch_message(ctx, &mut global_data, woxlf_msg).await?;
if global_data.game_state_mut()?.current_phase == Phase::Day { if global_data.game_state_mut()?.current_phase == Phase::Day {
let vote_channel = guild let vote_channel = guild
@ -303,8 +303,8 @@ async fn kill(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
#[only_in(guilds)] #[only_in(guilds)]
#[allowed_roles("wolfx host")] #[allowed_roles("wolfx host")]
async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let mut data = ctx.data.write().await; let data = ctx.data.read().await;
let global_data = data.get_mut::<GlobalData>().unwrap(); let global_data = data.get::<GlobalData>().unwrap();
let mut global_data = global_data.lock().await; let mut global_data = global_data.lock().await;
@ -335,7 +335,7 @@ async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
.content(&broadcast) .content(&broadcast)
.clone(); .clone();
dispatch_message(ctx, &global_data, woxlf_msg).await?; dispatch_message(ctx, &mut global_data, woxlf_msg).await?;
msg.reply(&ctx.http, "Phase has been updated") msg.reply(&ctx.http, "Phase has been updated")
.await .await
@ -644,7 +644,7 @@ async fn whisper(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
} else { } else {
let data = ctx.data.read().await; let data = ctx.data.read().await;
let global_data = data.get::<GlobalData>().unwrap(); let global_data = data.get::<GlobalData>().unwrap();
let global_data = global_data.lock().await; let mut global_data = global_data.lock().await;
let target = args.single::<String>()?; let target = args.single::<String>()?;
let pm = args.rest(); let pm = args.rest();
@ -674,7 +674,7 @@ async fn whisper(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
.content(pm) .content(pm)
.clone(); .clone();
dispatch_message(ctx, &global_data, woxlf_msg).await?; dispatch_message(ctx, &mut global_data, woxlf_msg).await?;
} else { } else {
msg.reply( msg.reply(
&ctx.http, &ctx.http,

View File

@ -26,7 +26,7 @@ impl EventHandler for Handler {
let global_data = data.get::<GlobalData>().unwrap(); let global_data = data.get::<GlobalData>().unwrap();
let global_data = global_data.lock().await; let mut global_data = global_data.lock().await;
if global_data.game_state.is_none() { if global_data.game_state.is_none() {
// no game in progress // no game in progress
@ -75,7 +75,7 @@ impl EventHandler for Handler {
.attachments(attachments) .attachments(attachments)
.clone(); .clone();
dispatch_message(&ctx, &global_data, woxlf_msg) dispatch_message(&ctx, &mut global_data, woxlf_msg)
.await .await
.expect("Unable to send message to players"); .expect("Unable to send message to players");
} }

View File

@ -0,0 +1,29 @@
use crate::game::listener::{EventStatus, Listener, ListenerContext, Priority};
use crate::game::message_router::{send_to_host_channel, WoxlfMessage};
use serenity::async_trait;
use serenity::model::prelude::GuildId;
use std::fmt::Debug;
#[derive(Debug)]
pub struct HostSnooper {}
#[async_trait]
impl Listener for HostSnooper {
fn get_priority(&self) -> Priority {
Priority::Logging
}
async fn on_chat(
&mut self,
ctx: &mut ListenerContext,
msg: &WoxlfMessage,
) -> crate::error::Result<EventStatus> {
let guild_id = ctx.data.cfg.discord_config.guild_id;
let guild = GuildId::from(guild_id)
.to_guild_cached(&ctx.ctx.cache)
.unwrap();
send_to_host_channel(&ctx.ctx.http, &guild, ctx.data, msg.clone()).await?;
Ok(EventStatus::Okay)
}
}

View File

@ -0,0 +1,103 @@
pub mod host_snooper;
use crate::error::Result;
use crate::game::global_data::GlobalData;
use crate::game::listener::host_snooper::HostSnooper;
use crate::game::message_router::WoxlfMessage;
use serenity::async_trait;
use serenity::client::Context;
use serenity::prelude::TypeMapKey;
use std::fmt::Debug;
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(Debug)]
pub struct Listeners {
listeners: Vec<Box<dyn Listener>>,
}
impl Listeners {
pub async fn process_event(
&mut self,
ctx: &Context,
data: &mut GlobalData,
event: WoxlfEvent<'_>,
) -> Result<EventStatus> {
let mut listener_ctx = ListenerContext { data, ctx };
for listener in &mut self.listeners {
let status = match &event {
WoxlfEvent::Chat(msg) => listener.on_chat(&mut listener_ctx, msg).await?,
};
if status == EventStatus::Canceled {
return Ok(status);
}
}
Ok(EventStatus::Okay)
}
pub fn add_listener(&mut self, listener: Box<dyn Listener>) {
self.listeners.push(listener);
self.listeners.sort_by_key(|l1| l1.get_priority());
}
}
impl Default for Listeners {
fn default() -> Self {
let mut listeners = Self { listeners: vec![] };
// Add default listeners here
listeners.add_listener(Box::new(HostSnooper {}));
listeners
}
}
impl TypeMapKey for Listeners {
type Value = Arc<Mutex<Listeners>>;
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum EventStatus {
Okay,
Canceled,
}
#[derive(Debug, Clone)]
pub enum WoxlfEvent<'a> {
Chat(WoxlfMessage<'a>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
#[allow(dead_code)]
pub enum Priority {
Highest,
High,
Medium,
Low,
Lowest,
Logging,
}
pub struct ListenerContext<'a> {
data: &'a GlobalData,
ctx: &'a Context,
}
#[async_trait]
pub trait Listener: Debug + Send + Sync {
fn get_priority(&self) -> Priority {
Priority::Medium
}
async fn on_chat(
&mut self,
_ctx: &mut ListenerContext,
_msg: &WoxlfMessage,
) -> Result<EventStatus> {
return Ok(EventStatus::Okay);
}
}

View File

@ -1,13 +1,14 @@
use crate::error; use crate::error;
use crate::error::WoxlfError; use crate::error::WoxlfError;
use crate::game::global_data::GlobalData; use crate::game::global_data::GlobalData;
use crate::game::listener::{EventStatus, Listeners, WoxlfEvent};
use crate::game::player_data::PlayerData; use crate::game::player_data::PlayerData;
use bitflags::bitflags; use bitflags::bitflags;
use serenity::client::Context; use serenity::client::Context;
use serenity::http::{CacheHttp, Http}; use serenity::http::{CacheHttp, Http};
use serenity::model::guild::Guild; use serenity::model::guild::Guild;
use serenity::model::id::{ChannelId, UserId}; use serenity::model::id::{ChannelId, UserId};
use serenity::model::prelude::{AttachmentType, GuildId, WebhookId}; use serenity::model::prelude::{AttachmentType, WebhookId};
use serenity::utils::MessageBuilder; use serenity::utils::MessageBuilder;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -190,7 +191,7 @@ async fn send_private_message(
Ok(()) Ok(())
} }
async fn send_to_host_channel( pub async fn send_to_host_channel(
http: &Http, http: &Http,
guild: &Guild, guild: &Guild,
global_data: &GlobalData, global_data: &GlobalData,
@ -284,11 +285,20 @@ pub async fn send_message(
pub async fn dispatch_message( pub async fn dispatch_message(
ctx: &Context, ctx: &Context,
global_data: &GlobalData, global_data: &mut GlobalData,
msg: WoxlfMessage<'_>, msg: WoxlfMessage<'_>,
) -> error::Result<()> { ) -> error::Result<()> {
let guild_id = global_data.cfg.discord_config.guild_id; let data = ctx.data.read().await;
let guild = GuildId::from(guild_id).to_guild_cached(&ctx.cache).unwrap(); let listeners = data.get::<Listeners>().unwrap();
let mut listeners = listeners.lock().await;
if listeners
.process_event(ctx, global_data, WoxlfEvent::Chat(msg.clone()))
.await?
== EventStatus::Canceled
{
return Ok(());
};
let msg_tasks = global_data let msg_tasks = global_data
.game_state()? .game_state()?
@ -309,7 +319,5 @@ pub async fn dispatch_message(
results?; results?;
send_to_host_channel(&ctx.http, &guild, global_data, msg).await?;
Ok(()) Ok(())
} }

View File

@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
pub mod game_state; pub mod game_state;
pub mod global_data; pub mod global_data;
pub mod listener;
pub mod message_router; pub mod message_router;
pub mod player_data; pub mod player_data;

View File

@ -8,6 +8,7 @@ use discord::event_handler::Handler;
use game::global_data::GlobalData; use game::global_data::GlobalData;
use crate::config::{Args, BotConfig}; use crate::config::{Args, BotConfig};
use crate::game::listener::Listeners;
mod config; mod config;
mod discord; mod discord;
@ -35,6 +36,7 @@ async fn main() {
.event_handler(Handler {}) .event_handler(Handler {})
.framework(command_framework()) .framework(command_framework())
.type_map_insert::<GlobalData>(Arc::new(Mutex::new(global_data))) .type_map_insert::<GlobalData>(Arc::new(Mutex::new(global_data)))
.type_map_insert::<Listeners>(Arc::new(Mutex::new(Listeners::default())))
.await .await
.expect("Err creating client"); .expect("Err creating client");