Initial refactor of message handling

+ Split all message handling into message_router.rs
+ Added whisper command
+ Updated serenity version
+ Fmt, but clippy failing
This commit is contained in:
2023-01-06 05:07:03 +00:00
committed by Gitea
parent 2aec084712
commit 3c219f5bff
11 changed files with 637 additions and 498 deletions
+76 -20
View File
@@ -10,20 +10,22 @@ use serenity::framework::standard::{
use serenity::framework::StandardFramework;
use serenity::model::guild::Member;
use serenity::model::id::ChannelId;
use serenity::model::prelude::{Message, UserId};
use serenity::model::prelude::{GuildId, Message, UserId};
use serenity::prelude::Context;
use serenity::utils::MessageBuilder;
use crate::discord::helper::{add_user_to_game, parse_duration_arg, send_msg_to_player_channels};
use crate::discord::helper::{add_user_to_game, parse_duration_arg};
use crate::error::{Result, WoxlfError};
use crate::game::global_data::GlobalData;
use crate::game::message_router::{dispatch_message, MessageDest, MessageSource};
use crate::game::player_data::PlayerData;
use crate::game::MessageSource;
use crate::game::Phase;
use crate::messages::DiscordUser;
#[group]
#[commands(start, say, end, broadcast, next_phase, kill, add_time, test_theme)]
#[commands(
start, say, end, broadcast, next_phase, kill, add_time, test_theme, whisper
)]
struct Host;
#[command]
@@ -34,7 +36,7 @@ async fn start(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
let game_name = args.single::<String>()?;
@@ -136,7 +138,7 @@ async fn start(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
async fn end(ctx: &Context, msg: &Message, mut _args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
@@ -162,18 +164,18 @@ async fn end(ctx: &Context, msg: &Message, mut _args: Args) -> CommandResult {
async fn say(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
send_msg_to_player_channels(
dispatch_message(
ctx,
&guild,
&mut global_data,
MessageSource::Host,
MessageDest::Broadcast,
args.rest(),
None,
false,
)
.await?;
@@ -186,7 +188,7 @@ async fn say(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
async fn broadcast(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
@@ -194,14 +196,14 @@ async fn broadcast(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
.templates()?
.build_announcement(&global_data, args.rest())?;
send_msg_to_player_channels(
dispatch_message(
ctx,
&guild,
&mut global_data,
MessageSource::Automated,
MessageDest::Broadcast,
&msg,
None,
true,
)
.await?;
@@ -214,7 +216,7 @@ async fn broadcast(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
@@ -232,14 +234,14 @@ async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
.templates()?
.build_announcement(&global_data, &broadcast)?;
send_msg_to_player_channels(
dispatch_message(
ctx,
&guild,
&mut global_data,
MessageSource::Automated,
MessageDest::Broadcast,
&broadcast,
None,
true,
)
.await?;
@@ -251,6 +253,7 @@ async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
))
.unwrap();
vote_channel
.id()
.send_message(&ctx.http, |m| {
m.content(format!(
"**{} {} Votes:**",
@@ -308,7 +311,7 @@ async fn kill(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
@@ -332,14 +335,14 @@ async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
.templates()?
.build_announcement(&global_data, &broadcast)?;
send_msg_to_player_channels(
dispatch_message(
ctx,
&guild,
&mut global_data,
MessageSource::Automated,
MessageDest::Broadcast,
&broadcast,
None,
true,
)
.await?;
@@ -501,7 +504,7 @@ struct Player;
async fn vote(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let mut data = ctx.data.write().await;
let global_data = data.get_mut::<GlobalData>().unwrap();
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let mut global_data = global_data.lock().await;
@@ -555,6 +558,7 @@ async fn vote(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
)?;
vote_channel
.id()
.send_message(&ctx.http, |m| m.content(vote_msg))
.await?;
} else {
@@ -626,7 +630,7 @@ async fn players(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
.push(alive_status);
if msg.channel_id.0 == global_data.cfg.discord_config.host_channel {
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let member = guild.members.get(&UserId::from(player.discord_id)).unwrap();
msg_builder.push_line(format!(" ({})", member.display_name()));
} else {
@@ -639,6 +643,58 @@ async fn players(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
Ok(())
}
#[command]
#[aliases("pm", "w")]
#[description = "Send a private message to another player."]
async fn whisper(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
if args.len() < 2 {
msg.reply(&ctx.http, "Need a recipient and message!")
.await?;
} else {
let data = ctx.data.write().await;
let global_data = data.get::<GlobalData>().unwrap();
let mut global_data = global_data.lock().await;
let guild = GuildId::from(global_data.cfg.discord_config.guild_id)
.to_guild_cached(&ctx.cache)
.unwrap();
let target = args.single::<String>()?;
let pm = args.rest();
let src_player = match global_data
.game_state()?
.get_player_from_discord_id(msg.author.id.0)
{
None => {
msg.reply(&ctx.http, "You are not in the game!").await?;
return Ok(());
}
Some(player) => player,
};
if let Some(target_player) = global_data.game_state()?.get_player_by_codename(&target) {
if src_player.discord_id == target_player.discord_id {
msg.reply(&ctx.http, "You can't send messages to yourself!")
.await?;
return Ok(());
}
let msg_src = MessageSource::Player(Box::new(src_player.clone()));
let msg_dest = MessageDest::PlayerDm(Box::new(target_player.clone()));
dispatch_message(ctx, &guild, &mut global_data, msg_src, msg_dest, pm, None).await?;
} else {
msg.reply(
&ctx.http,
format!("Could not find a player with codename {}.", target),
)
.await?;
}
}
Ok(())
}
#[help]
#[individual_command_tip = "If you want more information about a specific command, just pass the command as argument."]
#[command_not_found_text = "Could not find: `{}`."]
+7 -7
View File
@@ -1,13 +1,13 @@
use serenity::async_trait;
use serenity::client::{Context, EventHandler};
use serenity::http::AttachmentType;
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::model::prelude::AttachmentType;
use serenity::utils::parse_emoji;
use crate::discord::helper::send_webhook_msg_to_player_channels;
use crate::game::global_data::GlobalData;
use crate::game::MessageSource;
use crate::game::message_router::MessageSource;
use crate::game::message_router::{dispatch_message, MessageDest};
pub struct Handler {}
@@ -43,7 +43,7 @@ impl EventHandler for Handler {
return;
}
let guild = msg.guild(&ctx.cache).await.unwrap();
let guild = msg.guild(&ctx.cache).unwrap();
let user_msg = msg.content.clone();
let re = regex::Regex::new(r"<a?:.+:\d+>").unwrap();
@@ -52,7 +52,6 @@ impl EventHandler for Handler {
if let Some(emoji) = parse_emoji(&emoji_cap[0]) {
if !msg
.guild(&ctx.cache)
.await
.unwrap()
.emojis
.contains_key(&emoji.id)
@@ -66,16 +65,17 @@ impl EventHandler for Handler {
let attachments: Vec<AttachmentType> = msg
.attachments
.iter()
.map(|a| AttachmentType::Image(&a.url))
.map(|a| AttachmentType::Image((a.url).parse().unwrap()))
.collect();
let msg_source = MessageSource::Player(Box::new(player_data.clone()));
send_webhook_msg_to_player_channels(
dispatch_message(
&ctx,
&guild,
&mut global_data,
msg_source,
MessageDest::Broadcast,
&user_msg,
Some(attachments),
)
+3 -198
View File
@@ -1,9 +1,8 @@
use serenity::client::Context;
use serenity::framework::standard::Args;
use serenity::http::{AttachmentType, Http};
use serenity::model::channel::{Message, PermissionOverwrite, PermissionOverwriteType};
use serenity::model::channel::{PermissionOverwrite, PermissionOverwriteType};
use serenity::model::guild::{Guild, Member};
use serenity::model::id::{ChannelId, UserId};
use serenity::model::id::ChannelId;
use serenity::model::Permissions;
use crate::error;
@@ -11,201 +10,7 @@ use crate::error::WoxlfError;
use crate::game::game_state::PhaseDuration;
use crate::game::global_data::GlobalData;
use crate::game::player_data::PlayerData;
use crate::game::MessageSource;
use crate::imgur::Image;
use serenity::prelude::SerenityError;
fn filter_source_channel(player_data: &&PlayerData, msg_source: &MessageSource) -> bool {
if let MessageSource::Player(source_player) = &msg_source {
if source_player.channel == player_data.channel {
return false;
}
}
true
}
pub async fn send_msg_to_player_channels(
ctx: &Context,
guild: &Guild,
global_data: &mut GlobalData,
msg_source: MessageSource,
msg: &str,
attachment: Option<Vec<AttachmentType<'_>>>,
pin: bool,
) -> error::Result<()> {
let msg_tasks = global_data
.game_state_mut()?
.player_data
.iter()
.filter(|player| filter_source_channel(player, &msg_source))
.map(|player_data| {
let channel = guild
.channels
.get(&ChannelId::from(player_data.channel))
.unwrap();
channel.send_message(&ctx.http, |m| {
m.content(&msg);
if let Some(attachment) = attachment.clone() {
m.add_files(attachment);
}
m
})
});
let msgs: Result<Vec<Message>, SerenityError> = futures::future::join_all(msg_tasks)
.await
.into_iter()
.collect();
let msgs = msgs?;
if pin {
let pin_tasks = msgs.iter().map(|msg| msg.pin(&ctx.http));
let pins: Result<(), SerenityError> = futures::future::join_all(pin_tasks)
.await
.into_iter()
.collect();
pins?;
}
let host_channel = guild
.channels
.get(&ChannelId::from(
global_data.cfg.discord_config.host_channel,
))
.unwrap();
let source = match msg_source {
MessageSource::Player(player_data) => {
let name = guild
.members
.get(&UserId::from(player_data.discord_id))
.unwrap()
.display_name();
name.to_string()
}
MessageSource::Host => "Host".to_string(),
MessageSource::Automated => "Automated".to_string(),
};
host_channel
.send_message(&ctx.http, |m| {
m.content(format!("({}): {}", source, msg));
if let Some(attachment) = attachment {
m.add_files(attachment);
}
m
})
.await?;
Ok(())
}
pub async fn send_webhook_msg(
http: &Http,
webhook_id: u64,
username: &str,
profile_pic_url: Option<String>,
msg: &str,
attachment: Option<Vec<AttachmentType<'_>>>,
) -> error::Result<()> {
let webhook = http.get_webhook(webhook_id).await?;
webhook
.execute(http, false, |w| {
w.content(&msg).username(username);
if let Some(profile_pic_url) = profile_pic_url {
w.avatar_url(profile_pic_url);
}
if let Some(attachment) = attachment.clone() {
w.add_files(attachment);
}
w
})
.await?;
Ok(())
}
pub async fn send_webhook_msg_to_player_channels(
ctx: &Context,
guild: &Guild,
global_data: &mut GlobalData,
msg_source: MessageSource,
msg: &str,
attachment: Option<Vec<AttachmentType<'_>>>,
) -> error::Result<()> {
let msg_username = match &msg_source {
MessageSource::Player(p) => p.codename.clone(),
MessageSource::Host => "Woxlf".to_string(),
MessageSource::Automated => "Woxlf System Message".to_string(),
};
let profile_pic = match &msg_source {
MessageSource::Player(p) => Some(p.profile_pic_url.clone()),
MessageSource::Host | MessageSource::Automated => None,
};
let msg_tasks = global_data
.game_state_mut()?
.player_data
.iter()
.filter(|player| filter_source_channel(player, &msg_source))
.map(|player_data| {
send_webhook_msg(
&ctx.http,
player_data.channel_webhook_id,
&msg_username,
profile_pic.clone(),
msg,
attachment.clone(),
)
});
let msgs: Result<(), WoxlfError> = futures::future::join_all(msg_tasks)
.await
.into_iter()
.collect();
msgs?;
let source = match &msg_source {
MessageSource::Player(player_data) => {
let name = guild
.members
.get(&UserId::from(player_data.discord_id))
.unwrap()
.display_name();
name.to_string()
}
MessageSource::Host => "Host".to_string(),
MessageSource::Automated => "Automated".to_string(),
};
let host_channel_username = format!("{} ({})", msg_username, source);
send_webhook_msg(
&ctx.http,
global_data.cfg.discord_config.host_webhook_id,
&host_channel_username,
profile_pic,
msg,
attachment,
)
.await?;
Ok(())
}
pub async fn add_user_to_game(
ctx: &Context,
@@ -237,7 +42,7 @@ pub async fn add_user_to_game(
.await?;
let allow =
Permissions::SEND_MESSAGES | Permissions::READ_MESSAGE_HISTORY | Permissions::READ_MESSAGES;
Permissions::SEND_MESSAGES | Permissions::READ_MESSAGE_HISTORY | Permissions::VIEW_CHANNEL;
let overwrite = PermissionOverwrite {
allow,