Skip to content
Snippets Groups Projects
react.rs 1.48 KiB
Newer Older
Stephen D's avatar
Stephen D committed
use crate::handlers::LineHandler;
use itertools::Itertools;
Stephen D's avatar
Stephen D committed
use phf::phf_map;
use serenity::async_trait;
use serenity::model::channel::{Message, ReactionType};
use serenity::prelude::*;
use std::str::FromStr;

static EMOJI_MAP: phf::Map<&'static str, &'static str> = phf_map! {
	"cat" => "🐈",
	"chicken" => "🐔",
	"spaghetti" => "🍝",
	"dog" => "🐕",
	"bot" => "🤖",
	"mango" => "🥭",
	"banana" => "🍌",
Stephen D's avatar
Stephen D committed
	"bee" => "🐝",
	"horse" => "🐎",
Stephen D's avatar
Stephen D committed
	"hat" => "🎩"
Stephen D's avatar
Stephen D committed
};

fn map_lookup(msg: &str) -> Option<&'static str> {
	// We lose the O(1) benefits of the hashmap
	// But whatever. It doesn't need to be fast
	for (k, v) in EMOJI_MAP.entries() {
		if msg.contains(k) {
			return Some(v);
		}
	}

	None
}

#[derive(Default)]
Stephen D's avatar
Stephen D committed
pub struct ReactHandler;

#[async_trait]
impl LineHandler for ReactHandler {
	async fn message(&self, ctx: &Context, msg: &Message) {
		// Kind of convoluted, but allows us to react in the correct order.
		let groups = msg
			.content
			.chars()
			.map(|c| match c {
				'!' | '?' | ',' | '.' => ' ',
				_ => c,
			})
			.group_by(|c| *c == ' ');
		let reacts: Vec<_> = groups
			.into_iter()
			.filter_map(|(_, c)| map_lookup(&c.collect::<String>().to_lowercase()))
			.unique()
			.collect();

		for r in reacts {
			let reaction_type = match ReactionType::from_str(r) {
				Ok(x) => x,
				Err(x) => {
					println!("Could not react: {}", x);
					return;
Stephen D's avatar
Stephen D committed
				}
			};
			if let Err(e) = msg.react(&ctx, reaction_type).await {
				println!("Error reacting: {}", e);
Stephen D's avatar
Stephen D committed
			}
		}
	}
}