use crate::config::BotConfig;
use crate::event::{MessageEvent, SelfId};
use crate::utils::timestamp;
use crate::Action;
use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
mod action;
#[doc(hidden)]
pub mod api;
#[doc(hidden)]
pub mod matchers;
#[doc(hidden)]
pub mod message_event_matcher;
pub mod prelude;
#[doc(hidden)]
pub mod set_get;
pub type Rule<E> = Arc<dyn Fn(&E, &BotConfig) -> bool + Send + Sync>;
pub type PreMatcher<E> = fn(&mut E, BotConfig) -> bool;
#[derive(Clone)]
pub struct Matcher<E>
where
E: Clone,
{
pub name: String,
pub bot: Option<crate::bot::Bot>,
action_sender: Option<matchers::ActionSender>,
pub priority: i8,
pre_matchers: Vec<Arc<PreMatcher<E>>>,
rules: Vec<Rule<E>>,
pub block: bool,
handler: Arc<RwLock<dyn Handler<E> + Sync + Send>>,
pub disable: bool,
pub temp: bool,
pub timeout: Option<i64>,
#[doc(hidden)]
event: Option<E>,
}
#[doc(hidden)]
impl<E> std::fmt::Debug for Matcher<E>
where
E: Clone,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Matcher")
.field("name", &self.name)
.field("priority", &self.priority)
.field("block", &self.block)
.field("disable", &self.disable)
.field("temp", &self.temp)
.field("timeout", &self.timeout)
.field("bot", &self.bot)
.finish()
}
}
#[async_trait]
pub trait Handler<E>
where
E: Clone,
{
fn on_bot_connect(&self, _: Matcher<E>) {}
fn on_bot_disconnect(&self, _: Matcher<E>) {}
fn timeout_drop(&self, _: &Matcher<E>) {}
fn match_(&self, event: &mut E) -> bool;
async fn handle(&self, event: E, matcher: Matcher<E>);
#[allow(unused_variables)]
fn load_config(&mut self, config: HashMap<String, toml::Value>) {}
}
impl<E> Matcher<E>
where
E: Clone,
{
pub fn new<H>(name: &str, handler: H) -> Matcher<E>
where
H: Handler<E> + Sync + Send + 'static,
{
Matcher {
name: name.to_string(),
bot: None,
action_sender: None,
priority: 1,
pre_matchers: vec![],
rules: vec![],
block: true,
handler: Arc::new(RwLock::new(handler)),
disable: false,
temp: false,
timeout: None,
event: None,
}
}
#[doc(hidden)]
fn pre_matcher_handle(&self, event: &mut E, config: BotConfig) -> bool {
for premather in &self.pre_matchers {
if !premather(event, config.clone()) {
return false;
}
}
true
}
#[doc(hidden)]
fn check_rules(&self, event: &E, config: &BotConfig) -> bool {
for rule in &self.rules {
if !rule(event, config) {
return false;
}
}
true
}
#[doc(hidden)]
pub async fn match_(
&self,
event: E,
config: BotConfig,
matchers: &mut matchers::Matchers,
) -> bool
where
E: Send + 'static + SelfId,
{
let mut event = event.clone();
if let Some(timeout) = self.timeout {
if timestamp() > timeout {
matchers.remove_matcher(&self.name);
{
let handler = self.handler.read().await;
handler.timeout_drop(&self);
}
return false;
}
}
if self.disable {
return false;
}
if !self.pre_matcher_handle(&mut event, config.clone()) {
return false;
}
if !self.check_rules(&event, &config) {
return false;
}
{
let handler = self.handler.read().await;
if !handler.match_(&mut event) {
return false;
}
let matcher = self.clone().set_event(&event);
let handler = self.handler.clone();
tokio::spawn(async move {
let handler = handler.read().await;
handler.handle(event, matcher).await
});
}
return true;
}
pub async fn set(&self, set: Action) {
if let Some(bot) = &self.bot {
bot.action_sender.send(set).await.unwrap();
}
}
pub async fn set_message_matcher(&self, matcher: Matcher<MessageEvent>) {
let action = action::MatchersAction::AddMessageEventMatcher {
message_event_matcher: matcher,
};
if let Some(action_sender) = &self.action_sender {
action_sender.send(action).unwrap();
} else {
tracing::event!(tracing::Level::WARN, "Action Sender not init.")
}
}
}
pub fn build_temp_message_event_matcher<H>(
event: &MessageEvent,
handler: H,
) -> Matcher<MessageEvent>
where
H: Handler<MessageEvent> + Send + Sync + 'static,
{
use crate::event::UserId;
let mut m = Matcher::new(
&format!(
"{}-{}-{}",
event.get_self_id(),
event.get_user_id(),
event.get_time()
),
handler,
)
.add_rule(crate::builtin::rules::is_user(event.get_user_id()))
.add_rule(crate::builtin::rules::is_bot(event.get_self_id()));
if let MessageEvent::Group(g) = event {
m.add_rule(crate::builtin::rules::in_group(g.group_id.clone()));
} else {
m.add_rule(crate::builtin::rules::is_private_message_event());
}
m.set_priority(0)
.set_temp(true)
.set_timeout(timestamp() + 30)
}