use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use regex::Regex;
use rust_tg_bot_raw::types::update::Update;
use super::base::{Handler, HandlerCallback, HandlerResult, MatchResult};
use crate::context::CallbackContext;
pub struct InlineQueryHandler {
callback: HandlerCallback,
pattern: Option<Regex>,
chat_types: Option<Vec<String>>,
block: bool,
}
impl InlineQueryHandler {
pub fn new(
callback: HandlerCallback,
pattern: Option<Regex>,
chat_types: Option<Vec<String>>,
block: bool,
) -> Self {
Self {
callback,
pattern,
chat_types,
block,
}
}
}
impl Handler for InlineQueryHandler {
fn check_update(&self, update: &Update) -> Option<MatchResult> {
let iq = update.inline_query()?;
if let Some(ref allowed) = self.chat_types {
let chat_type = iq.chat_type.as_deref()?;
if !allowed.iter().any(|t| t == chat_type) {
return None;
}
}
if let Some(ref re) = self.pattern {
let query = &iq.query;
let caps = re.captures(query)?;
let positional: Vec<String> = caps
.iter()
.filter_map(|m| m.map(|m| m.as_str().to_owned()))
.collect();
let mut named: HashMap<String, String> = HashMap::new();
for name in re.capture_names().flatten() {
if let Some(m) = caps.name(name) {
named.insert(name.to_owned(), m.as_str().to_owned());
}
}
return if named.is_empty() {
Some(MatchResult::RegexMatch(positional))
} else {
Some(MatchResult::RegexMatchWithNames { positional, named })
};
}
Some(MatchResult::Empty)
}
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
}
fn collect_additional_context(
&self,
context: &mut CallbackContext,
match_result: &MatchResult,
) {
match match_result {
MatchResult::RegexMatch(groups) => {
context.matches = Some(groups.clone());
}
MatchResult::RegexMatchWithNames { positional, named } => {
context.matches = Some(positional.clone());
context.named_matches = Some(named.clone());
}
_ => {}
}
}
}