mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 16:58:55 +00:00
Core: asyncify Votes
This commit is contained in:
parent
890cb21770
commit
9975aa5880
1 changed files with 100 additions and 106 deletions
|
@ -1,14 +1,18 @@
|
|||
use serenity::framework::standard::CommandError as Error;
|
||||
use serenity::{
|
||||
collector::ReactionAction,
|
||||
framework::standard::{macros::command, Args, CommandResult},
|
||||
model::{
|
||||
channel::{Message, Reaction, ReactionType},
|
||||
channel::{Message, ReactionType},
|
||||
id::UserId,
|
||||
},
|
||||
utils::MessageBuilder,
|
||||
};
|
||||
use std::collections::{HashMap as Map, HashSet as Set};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::{HashMap as Map, HashSet as Set},
|
||||
convert::TryFrom,
|
||||
};
|
||||
use youmubot_prelude::{Duration as ParseDuration, *};
|
||||
|
||||
#[command]
|
||||
|
@ -19,13 +23,13 @@ use youmubot_prelude::{Duration as ParseDuration, *};
|
|||
#[only_in(guilds)]
|
||||
#[min_args(2)]
|
||||
#[owner_privilege]
|
||||
pub fn vote(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
pub async fn vote(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
// Parse stuff first
|
||||
let args = args.quoted();
|
||||
let _duration = args.single::<ParseDuration>()?;
|
||||
let duration = &_duration.0;
|
||||
if *duration < Duration::from_secs(2 * 60) || *duration > Duration::from_secs(60 * 60 * 24) {
|
||||
msg.reply(ctx, format!("😒 Invalid duration ({}). The voting time should be between **2 minutes** and **1 day**.", _duration))?;
|
||||
msg.reply(ctx, format!("😒 Invalid duration ({}). The voting time should be between **2 minutes** and **1 day**.", _duration)).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let question = args.single::<String>()?;
|
||||
|
@ -41,7 +45,8 @@ pub fn vote(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
|||
msg.reply(
|
||||
ctx,
|
||||
"😒 Can't have a nice voting session if you only have one choice.",
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
if choices.len() > MAX_CHOICES {
|
||||
|
@ -52,7 +57,8 @@ pub fn vote(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
|||
"😵 Too many choices... We only support {} choices at the moment!",
|
||||
MAX_CHOICES
|
||||
),
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -89,70 +95,59 @@ pub fn vote(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
|||
.description(MessageBuilder::new().push_bold_line_safe(&question).push("\nThis question was asked by ").push(author.mention()))
|
||||
.fields(fields.into_iter())
|
||||
})
|
||||
})?;
|
||||
msg.delete(&ctx)?;
|
||||
}).await?;
|
||||
msg.delete(&ctx).await?;
|
||||
// React on all the choices
|
||||
choices
|
||||
.iter()
|
||||
.try_for_each(|(emote, _)| panel.react(&ctx, &emote[..]))?;
|
||||
.map(|(emote, _)| {
|
||||
panel
|
||||
.react(&ctx, ReactionType::try_from(&emote[..]).unwrap())
|
||||
.map_ok(|_| ())
|
||||
})
|
||||
.collect::<stream::FuturesUnordered<_>>()
|
||||
.try_collect::<()>()
|
||||
.await?;
|
||||
|
||||
// A handler for votes.
|
||||
struct VoteHandler {
|
||||
pub ctx: Context,
|
||||
pub msg: Message,
|
||||
pub user_reactions: Map<String, Set<UserId>>,
|
||||
|
||||
pub panel: Message,
|
||||
}
|
||||
|
||||
impl VoteHandler {
|
||||
fn new(ctx: Context, msg: Message, panel: Message, choices: &[(String, String)]) -> Self {
|
||||
VoteHandler {
|
||||
ctx,
|
||||
msg,
|
||||
user_reactions: choices
|
||||
let mut user_reactions: Map<String, Set<UserId>> = choices
|
||||
.iter()
|
||||
.map(|(emote, _)| (emote.clone(), Set::new()))
|
||||
.collect(),
|
||||
panel,
|
||||
}
|
||||
}
|
||||
}
|
||||
.collect();
|
||||
|
||||
impl ReactionHandler for VoteHandler {
|
||||
fn handle_reaction(&mut self, reaction: &Reaction, is_add: bool) -> CommandResult {
|
||||
if reaction.message_id != self.panel.id {
|
||||
return Ok(());
|
||||
}
|
||||
if reaction.user(&self.ctx)?.bot {
|
||||
return Ok(());
|
||||
}
|
||||
// Collect reactions...
|
||||
msg.await_reactions(&ctx)
|
||||
.timeout(*duration)
|
||||
.await
|
||||
.scan(user_reactions, |set, reaction| async move {
|
||||
let (reaction, is_add) = match &*reaction {
|
||||
ReactionAction::Added(r) => (r, true),
|
||||
ReactionAction::Removed(r) => (r, false),
|
||||
};
|
||||
let users = if let ReactionType::Unicode(ref s) = reaction.emoji {
|
||||
if let Some(users) = self.user_reactions.get_mut(s.as_str()) {
|
||||
if let Some(users) = set.get_mut(s.as_str()) {
|
||||
users
|
||||
} else {
|
||||
return Ok(());
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
return Ok(());
|
||||
return None;
|
||||
};
|
||||
let user_id = match reaction.user_id {
|
||||
Some(v) => v,
|
||||
None => return None,
|
||||
};
|
||||
if is_add {
|
||||
users.insert(reaction.user_id);
|
||||
users.insert(user_id);
|
||||
} else {
|
||||
users.remove(&reaction.user_id);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
users.remove(&user_id);
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
.collect::<()>()
|
||||
.await;
|
||||
|
||||
ctx.data
|
||||
.get_cloned::<ReactionWatcher>()
|
||||
.handle_reactions_timed(
|
||||
VoteHandler::new(ctx.clone(), msg.clone(), panel, &choices),
|
||||
*duration,
|
||||
move |vh| {
|
||||
let (ctx, msg, user_reactions, panel) =
|
||||
(vh.ctx, vh.msg, vh.user_reactions, vh.panel);
|
||||
// Handle choices
|
||||
let choice_map = choices.into_iter().collect::<Map<_, _>>();
|
||||
let result: Vec<(String, Vec<UserId>)> = user_reactions
|
||||
.into_iter()
|
||||
|
@ -169,8 +164,10 @@ pub fn vote(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
|||
.push(", sorry 😭")
|
||||
.build(),
|
||||
)
|
||||
.ok();
|
||||
} else {
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
channel
|
||||
.send_message(&ctx, |c| {
|
||||
c.content({
|
||||
|
@ -201,11 +198,8 @@ pub fn vote(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
|||
content.build()
|
||||
})
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
panel.delete(&ctx).ok();
|
||||
},
|
||||
);
|
||||
.await?;
|
||||
panel.delete(&ctx).await?;
|
||||
|
||||
Ok(())
|
||||
// unimplemented!();
|
||||
|
|
Loading…
Add table
Reference in a new issue