use std::collections::HashSet;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use rust_tg_bot_raw::types::update::Update;
use super::base::{Handler, HandlerCallback, HandlerResult, MatchResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum MessageReactionType {
Updated,
CountUpdated,
Any,
}
pub struct MessageReactionHandler {
callback: HandlerCallback,
reaction_type: MessageReactionType,
chat_ids: HashSet<i64>,
chat_usernames: HashSet<String>,
user_ids: HashSet<i64>,
user_usernames: HashSet<String>,
block: bool,
}
impl MessageReactionHandler {
pub fn new(
callback: HandlerCallback,
reaction_type: MessageReactionType,
chat_ids: HashSet<i64>,
chat_usernames: HashSet<String>,
user_ids: HashSet<i64>,
user_usernames: HashSet<String>,
block: bool,
) -> Self {
let has_user_filter = !user_ids.is_empty() || !user_usernames.is_empty();
let includes_anonymous = matches!(
reaction_type,
MessageReactionType::Any | MessageReactionType::CountUpdated
);
assert!(
!(has_user_filter && includes_anonymous),
"Cannot filter by user and include anonymous reactions. \
Set reaction_type to MessageReactionType::Updated."
);
let chat_usernames = chat_usernames
.into_iter()
.map(|u| u.trim_start_matches('@').to_lowercase())
.collect();
let user_usernames = user_usernames
.into_iter()
.map(|u| u.trim_start_matches('@').to_lowercase())
.collect();
Self {
callback,
reaction_type,
chat_ids,
chat_usernames,
user_ids,
user_usernames,
block,
}
}
}
impl Handler for MessageReactionHandler {
fn check_update(&self, update: &Update) -> Option<MatchResult> {
let has_reaction = update.message_reaction().is_some();
let has_count = update.message_reaction_count().is_some();
if !has_reaction && !has_count {
return None;
}
match self.reaction_type {
MessageReactionType::Updated => {
if has_count && !has_reaction {
return None;
}
}
MessageReactionType::CountUpdated => {
if has_reaction && !has_count {
return None;
}
}
MessageReactionType::Any => {}
}
let no_filters = self.chat_ids.is_empty()
&& self.chat_usernames.is_empty()
&& self.user_ids.is_empty()
&& self.user_usernames.is_empty();
if no_filters {
return Some(MatchResult::Empty);
}
if let Some(chat) = update.effective_chat() {
if self.chat_ids.contains(&chat.id) {
return Some(MatchResult::Empty);
}
if let Some(ref uname) = chat.username {
if self.chat_usernames.contains(&uname.to_lowercase()) {
return Some(MatchResult::Empty);
}
}
}
if let Some(user) = update.effective_user() {
if self.user_ids.contains(&user.id) {
return Some(MatchResult::Empty);
}
if let Some(ref uname) = user.username {
if self.user_usernames.contains(&uname.to_lowercase()) {
return Some(MatchResult::Empty);
}
}
}
None
}
fn handle_update(
&self,
update: Arc<Update>,
match_result: MatchResult,
) -> Pin<Box<dyn Future<Output = HandlerResult> + Send>> {
(self.callback)(update, match_result)
}
fn block(&self) -> bool {
self.block
}
}