mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-05-24 17:20:49 +00:00
Implement ReactionHandler
This commit is contained in:
parent
ac4e60c596
commit
486bd6b88d
5 changed files with 89 additions and 0 deletions
|
@ -3,10 +3,12 @@ use std::sync::Arc;
|
|||
|
||||
pub mod announcer;
|
||||
pub mod args;
|
||||
pub mod reaction_watch;
|
||||
pub mod setup;
|
||||
|
||||
pub use announcer::Announcer;
|
||||
pub use args::Duration;
|
||||
pub use reaction_watch::{ReactionHandler, ReactionWatcher};
|
||||
|
||||
/// The global app data.
|
||||
pub type AppData = Arc<RwLock<ShareMap>>;
|
||||
|
|
72
youmubot-prelude/src/reaction_watch.rs
Normal file
72
youmubot-prelude/src/reaction_watch.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use crossbeam_channel::{after, bounded, select, Sender};
|
||||
use serenity::{framework::standard::CommandResult, model::channel::Reaction, prelude::*};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// Handles a reaction.
|
||||
///
|
||||
/// Every handler needs an expire time too.
|
||||
pub trait ReactionHandler {
|
||||
/// Handle a reaction. This is fired on EVERY reaction.
|
||||
/// You do the filtering yourself.
|
||||
fn handle_reaction(&mut self, reaction: &Reaction) -> CommandResult;
|
||||
}
|
||||
|
||||
impl<T> ReactionHandler for T
|
||||
where
|
||||
T: FnMut(&Reaction) -> CommandResult,
|
||||
{
|
||||
fn handle_reaction(&mut self, reaction: &Reaction) -> CommandResult {
|
||||
self(reaction)
|
||||
}
|
||||
}
|
||||
|
||||
/// The store for a set of dynamic reaction handlers.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReactionWatcher {
|
||||
channels: Arc<Mutex<Vec<Sender<Arc<Reaction>>>>>,
|
||||
}
|
||||
|
||||
impl TypeMapKey for ReactionWatcher {
|
||||
type Value = ReactionWatcher;
|
||||
}
|
||||
|
||||
impl ReactionWatcher {
|
||||
/// Create a new ReactionWatcher.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
channels: Arc::new(Mutex::new(vec![])),
|
||||
}
|
||||
}
|
||||
/// Send a reaction.
|
||||
pub fn send(&self, r: Reaction) {
|
||||
let r = Arc::new(r);
|
||||
self.channels
|
||||
.lock()
|
||||
.expect("Poisoned!")
|
||||
.retain(|e| e.send(r.clone()).is_ok());
|
||||
}
|
||||
/// React! to a series of reaction
|
||||
///
|
||||
/// The reactions stop after `duration`.
|
||||
pub fn handle_reactions(
|
||||
&self,
|
||||
mut h: impl ReactionHandler,
|
||||
duration: std::time::Duration,
|
||||
) -> CommandResult {
|
||||
let (send, reactions) = bounded(0);
|
||||
{
|
||||
self.channels.lock().expect("Poisoned!").push(send);
|
||||
}
|
||||
let timeout = after(duration);
|
||||
loop {
|
||||
let r = select! {
|
||||
recv(reactions) -> r => h.handle_reaction(&*r.unwrap()),
|
||||
recv(timeout) -> _ => break,
|
||||
};
|
||||
if let Err(v) = r {
|
||||
return Err(v);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -9,5 +9,9 @@ pub fn setup_prelude(db_path: &Path, data: &mut ShareMap, _: &mut StandardFramew
|
|||
crate::announcer::AnnouncerChannels::insert_into(data, db_path.join("announcers.yaml"))
|
||||
.expect("Announcers DB set up");
|
||||
|
||||
// Set up the HTTP client.
|
||||
data.insert::<crate::HTTPClient>(reqwest::blocking::Client::new());
|
||||
|
||||
// Set up the reaction watcher.
|
||||
data.insert::<crate::ReactionWatcher>(crate::ReactionWatcher::new());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue