only responds one to multiple regex matches

master
Edward Shen 2020-05-13 21:55:09 -04:00
parent 4e6430ad27
commit b184361355
Signed by: edward
GPG Key ID: 19182661E818369F
4 changed files with 114 additions and 55 deletions

View File

@ -1,3 +1,5 @@
use super::{PassiveResponder, PassiveResponse};
use crate::util::debug_say_owned;
use futures::future::BoxFuture; use futures::future::BoxFuture;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::trace; use log::trace;
@ -5,9 +7,8 @@ use rand::seq::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
use rand::Rng; use rand::Rng;
use regex::Regex; use regex::Regex;
use serenity::async_trait;
use serenity::model::channel::Message; use serenity::model::channel::Message;
use serenity::prelude::{Context, EventHandler}; use serenity::prelude::Context;
lazy_static! { lazy_static! {
#[derive(Debug)] #[derive(Debug)]
@ -18,34 +19,41 @@ lazy_static! {
pub(crate) struct DesuResponder; pub(crate) struct DesuResponder;
#[async_trait] impl PassiveResponder for DesuResponder {
impl EventHandler for DesuResponder { fn get_message(
async fn message(&self, ctx: Context, message: Message) { &self,
let content = message.content_safe(ctx.clone()).await; received_msg: String,
let fufufu_match = FUFUFU_REGEX.is_match(&content); ctx: Context,
let desu_match = DESU_REGEX.is_match(&content) && thread_rng().gen::<f32>() < 0.1; message: Message,
) -> Option<PassiveResponse<'_>> {
let fufufu_match = FUFUFU_REGEX.is_match(&received_msg);
let desu_match = DESU_REGEX.is_match(&received_msg) && thread_rng().gen::<f32>() < 0.1;
if fufufu_match || desu_match { if fufufu_match || desu_match {
trace!( trace!(
"Responding to `{}` because one of the following matched: fufufu={}, desu={}", "Responding to `{}` because one of the following matched: fufufu={}, desu={}",
content, received_msg,
fufufu_match, fufufu_match,
desu_match desu_match
); );
let random_action =
DESU_ACTIONS.choose(&mut thread_rng()).unwrap().clone()(ctx, message); Some(DESU_ACTIONS.choose(&mut thread_rng()).unwrap().clone()(
random_action.await.unwrap(); ctx, message,
))
} else {
None
} }
} }
} }
type DesuAction<'r, T> = &'r (dyn Fn(Context, Message) -> T + Sync); type DesuAction<'r, T> = &'r (dyn Fn(Context, Message) -> T + Sync);
const DESU_ACTIONS: &[DesuAction<BoxFuture<Result<Message, serenity::Error>>>] = &[ const DESU_ACTIONS: &[DesuAction<BoxFuture<Result<Option<Message>, serenity::Error>>>] = &[
&|ctx, msg| Box::pin(msg.channel_id.say(ctx, "です。")), &|ctx, msg| Box::pin(debug_say_owned(msg, ctx, "です。")),
&|ctx, msg| Box::pin(msg.channel_id.say(ctx, "desu~")), &|ctx, msg| Box::pin(debug_say_owned(msg, ctx, "desu~")),
&|ctx, msg| Box::pin(msg.channel_id.say(ctx, "desu.")), &|ctx, msg| Box::pin(debug_say_owned(msg, ctx, "desu.")),
&|ctx, msg| { &|ctx, msg| {
Box::pin(msg.channel_id.say( Box::pin(debug_say_owned(
msg,
ctx, ctx,
r#" r#"
``` ```
@ -64,17 +72,24 @@ const DESU_ACTIONS: &[DesuAction<BoxFuture<Result<Message, serenity::Error>>>] =
&|ctx, msg| { &|ctx, msg| {
// https://imgur.com/a/yOb5n // https://imgur.com/a/yOb5n
// One day. // One day.
Box::pin( Box::pin(debug_say_owned(
msg.channel_id msg,
.say(ctx, "https://www.youtube.com/watch?v=60mLvBWOMb4"), ctx,
) "https://www.youtube.com/watch?v=60mLvBWOMb4",
}, ))
&|ctx, msg| {
Box::pin(msg.channel_id.send_message(ctx, |m| {
m.add_file(serenity::http::AttachmentType::Bytes {
data: std::borrow::Cow::from(&include_bytes!("../../res/desu.jpg")[..]),
filename: "desu.jpg".to_string(),
})
}))
}, },
&|ctx, msg| Box::pin(send_desu_image(ctx, msg)),
]; ];
async fn send_desu_image(ctx: Context, msg: Message) -> Result<Option<Message>, serenity::Error> {
Ok(Some(
msg.channel_id
.send_message(ctx, |m| {
m.add_file(serenity::http::AttachmentType::Bytes {
data: std::borrow::Cow::from(&include_bytes!("../../res/desu.jpg")[..]),
filename: "desu.jpg".to_string(),
})
})
.await?,
))
}

View File

@ -2,6 +2,8 @@ use ahhhh::YellResponder;
use all_caps::AllCapsResponder; use all_caps::AllCapsResponder;
use best_doctor::BestDoctorResponder; use best_doctor::BestDoctorResponder;
use desu::DesuResponder; use desu::DesuResponder;
use futures::future::BoxFuture;
use rand::{rngs::OsRng, seq::IteratorRandom};
use reee::ReeeResponder; use reee::ReeeResponder;
use serenity::async_trait; use serenity::async_trait;
use serenity::model::channel::Message; use serenity::model::channel::Message;
@ -14,7 +16,7 @@ mod desu;
mod reee; mod reee;
pub(crate) struct Handler { pub(crate) struct Handler {
responders: Vec<Box<dyn EventHandler>>, responders: Vec<Box<dyn PassiveResponder + Send + Sync>>,
} }
impl Default for Handler { impl Default for Handler {
@ -34,8 +36,15 @@ impl Default for Handler {
#[async_trait] #[async_trait]
impl EventHandler for Handler { impl EventHandler for Handler {
async fn message(&self, ctx: Context, message: Message) { async fn message(&self, ctx: Context, message: Message) {
for responder in self.responders.iter() { let received_msg = message.content_safe(ctx.clone()).await;
responder.message(ctx.clone(), message.clone()).await; let valid_responses = self.responders.iter().filter_map(|responder| {
responder.get_message(received_msg.clone(), ctx.clone(), message.clone())
});
if let Some(fut) = valid_responses.choose(&mut OsRng) {
if let Err(err) = fut.await {
log::warn!("Got an error while sending a passive response: {}", err);
}
} }
} }
} }
@ -52,19 +61,33 @@ macro_rules! simple_responder {
pub(crate) struct $name; pub(crate) struct $name;
#[serenity::async_trait] impl crate::passive::PassiveResponder for $name {
impl serenity::prelude::EventHandler for $name { fn get_message(
async fn message(
&self, &self,
received_msg: String,
ctx: serenity::prelude::Context, ctx: serenity::prelude::Context,
message: serenity::model::channel::Message, message: serenity::model::channel::Message,
) { ) -> Option<crate::passive::PassiveResponse<'_>> {
let msg = message.content_safe(ctx.clone()).await; if REGEX.is_match(&received_msg) {
if REGEX.is_match(&msg) { log::trace!("{} matched regex {:?}", received_msg, REGEX);
log::trace!("{} matched regex {:?}", msg, REGEX); Some(Box::pin(crate::util::debug_say_owned(
message.channel_id.say(ctx, $phrase).await.unwrap(); message, ctx, $phrase,
)))
} else {
None
} }
} }
} }
}; };
} }
type PassiveResponse<'a> = BoxFuture<'a, Result<Option<Message>, serenity::Error>>;
trait PassiveResponder {
fn get_message(
&self,
received_msg: String,
ctx: Context,
message: Message,
) -> Option<PassiveResponse>;
}

View File

@ -1,8 +1,9 @@
use super::{PassiveResponder, PassiveResponse};
use crate::util::debug_say_owned;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use serenity::async_trait;
use serenity::model::channel::Message; use serenity::model::channel::Message;
use serenity::prelude::{Context, EventHandler}; use serenity::prelude::Context;
lazy_static! { lazy_static! {
static ref REGEX: Regex = Regex::new("RE{5,}").unwrap(); static ref REGEX: Regex = Regex::new("RE{5,}").unwrap();
@ -10,19 +11,24 @@ lazy_static! {
pub(crate) struct ReeeResponder; pub(crate) struct ReeeResponder;
#[async_trait] impl PassiveResponder for ReeeResponder {
impl EventHandler for ReeeResponder { fn get_message(
async fn message(&self, ctx: Context, message: Message) { &self,
if REGEX.is_match(&message.content_safe(ctx.clone()).await) { received_msg: String,
if let Some(guild_id) = message.guild_id { ctx: Context,
if guild_id == 679888177951277102 { message: Message,
message ) -> Option<PassiveResponse<'_>> {
.channel_id if REGEX.is_match(&received_msg) {
.say(ctx, "<:texaspat:680231475928498217>") if let Some(guild_id) = &message.guild_id {
.await if guild_id == &679888177951277102 {
.unwrap(); return Some(Box::pin(debug_say_owned(
message,
ctx,
"<:texaspat:680231475928498217>",
)));
} }
} }
} }
None
} }
} }

View File

@ -1,10 +1,9 @@
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serenity::{ use serenity::{
// builder::CreateMessage,
http::Http, http::Http,
model::{channel::Message, id::ChannelId}, model::{channel::Message, id::ChannelId},
}; };
use std::env::var; use std::{borrow::Cow, env::var};
pub mod db; pub mod db;
pub mod error; pub mod error;
pub mod operators; pub mod operators;
@ -28,6 +27,22 @@ pub async fn debug_say(
msg: &Message, msg: &Message,
ctx: impl AsRef<Http>, ctx: impl AsRef<Http>,
resp: impl std::fmt::Display, resp: impl std::fmt::Display,
) -> Result<Option<Message>, serenity::Error> {
debug_say_cow(Cow::Borrowed(msg), ctx, resp).await
}
pub async fn debug_say_owned(
msg: Message,
ctx: impl AsRef<Http>,
resp: impl std::fmt::Display,
) -> Result<Option<Message>, serenity::Error> {
debug_say_cow(Cow::Owned(msg), ctx, resp).await
}
async fn debug_say_cow(
msg: Cow<'_, Message>,
ctx: impl AsRef<Http>,
resp: impl std::fmt::Display,
) -> Result<Option<Message>, serenity::Error> { ) -> Result<Option<Message>, serenity::Error> {
debug_channel_say(&msg.channel_id, *msg.author.id.as_u64(), ctx, resp).await debug_channel_say(&msg.channel_id, *msg.author.id.as_u64(), ctx, resp).await
} }