diff --git a/Cargo.lock b/Cargo.lock index f7f525ab9722b92b4f44ef29ba7f969579131646..a5684ab057a8e89a26b48dae4b7f7eca2f530302 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2151,6 +2151,7 @@ dependencies = [ "futures", "grammers-client", "grammers-session", + "grammers-tl-types", "lazy_static", "log", "rand 0.8.5", diff --git a/Cargo.toml b/Cargo.toml index fbc8a78bd4d69a0e6911da6956149abfa7c15f45..421376d3ce48ea4f66008b50b1a88006cf9aa308 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ dyn-clone = "1.0.10" fern = { version = "0.6.1", features = ["chrono", "colored"] } futures = "0.3.26" grammers-client = { version = "0.4.0", features = ["markdown", "html"] } +grammers-tl-types = { version = "0.4.0" } grammers-session = "0.4.0" lazy_static = "1.4.0" log = "0.4.17" diff --git a/src/bot/filters/filtered_handler.rs b/src/bot/filters/filtered_handler.rs index 44fd29f9d7426246dfce2b3862b6eb89565dde7d..85a59cd3856fe799ed3b4d49ef510e4fb2b79fcd 100644 --- a/src/bot/filters/filtered_handler.rs +++ b/src/bot/filters/filtered_handler.rs @@ -1,6 +1,6 @@ use grammers_client::Update; -use crate::bot::handlers::Handler; +use crate::bot::{handlers::Handler, middlewares::base::Middleware}; use super::base::Filter; @@ -28,6 +28,12 @@ impl FilteredHandler { self } + /// Wraps a middleware around a handler. + pub fn add_middleware<M: Middleware + 'static>(mut self) -> Self { + self.handler = Box::new(M::from_handler(self.handler)); + self + } + /// This method performs checks for all filters we have. /// We run it not in parralel for fast fail strategy. pub fn check(&self, update: &Update) -> bool { diff --git a/src/bot/handlers/fun/greeter.rs b/src/bot/handlers/fun/greeter.rs index fc83bd3314217f75bf3a6ebef547cb15f52e6f59..f5ae4c8675253d6f047731f06a50df226b29ba66 100644 --- a/src/bot/handlers/fun/greeter.rs +++ b/src/bot/handlers/fun/greeter.rs @@ -20,17 +20,11 @@ pub struct Greeter; #[async_trait] impl Handler for Greeter { - async fn react(&self, client: &Client, update: &Update) -> anyhow::Result<()> { + async fn react(&self, _: &Client, update: &Update) -> anyhow::Result<()> { let Update::NewMessage(message) = update else {return Ok(())}; - // Check if chat has less than 100 participants. - let participants = client.iter_participants(message.chat()).total().await?; - if participants >= 100 { - return Ok(()); - } - // Choose random greeting from the list of greetings. - let reply_text = GREETINGS.iter().choose(&mut rand::thread_rng()).copied(); + let reply_text = GREETINGS.iter().choose(&mut rand::rngs::OsRng).copied(); if let Some(text) = reply_text { message.reply(text).await?; diff --git a/src/bot/main.rs b/src/bot/main.rs index 5241355e3ef4d91a127a62fe8d19481c545b56b0..1ea86239aa35e8ed016a6744d2c2ab22b58c8ef1 100644 --- a/src/bot/main.rs +++ b/src/bot/main.rs @@ -25,6 +25,7 @@ use super::{ fun::{blyaficator::Blyaficator, greeter::Greeter, repeator::Repeator, rotator::Rotator}, Handler, }, + middlewares::members_count::MembersCount, }; /// Authorization function. @@ -103,7 +104,8 @@ async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> { .add_filter(SilentFilter) .add_filter(ExcludedChatsFilter(vec![me.id()])) .add_filter(TextFilter(&["привет"], TextMatchMethod::IStartsWith)) - .add_filter(ExcludedChatsFilter(args.excluded_chats)), + .add_filter(ExcludedChatsFilter(args.excluded_chats)) + .add_middleware::<MembersCount<100>>(), // Getting chat id. FilteredHandler::new(GetChatId) .add_filter(TextFilter(&[".cid"], TextMatchMethod::IMatches)), @@ -117,7 +119,8 @@ async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> { .add_filter(UpdateTypeFilter(&[UpdateType::New])) .add_filter(SilentFilter) .add_filter(ExcludedChatsFilter(args.currency_excluded_chats)) - .add_filter(CurrencyTextFilter), + .add_filter(CurrencyTextFilter) + .add_middleware::<MembersCount<100>>(), // Simlpe rotator. FilteredHandler::new(Rotator) .add_filter(UpdateTypeFilter(&[UpdateType::New])) @@ -134,7 +137,8 @@ async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> { .add_filter(MessageDirectionFilter(MessageDirection::Incoming)) .add_filter(SilentFilter) .add_filter(ExcludedChatsFilter(vec![me.id()])) - .add_filter(RegexFilter(Regex::new("^[)0]+$")?)), + .add_filter(RegexFilter(Regex::new("^[)0]+$")?)) + .add_middleware::<MembersCount<100>>(), ]; let mut errors_count = 0; diff --git a/src/bot/middlewares/base.rs b/src/bot/middlewares/base.rs new file mode 100644 index 0000000000000000000000000000000000000000..f441fd7975ebb887d60848820bb71f46a86d5aad --- /dev/null +++ b/src/bot/middlewares/base.rs @@ -0,0 +1,5 @@ +use crate::bot::handlers::Handler; + +pub trait Middleware: Handler { + fn from_handler(handler: Box<dyn Handler>) -> Self; +} diff --git a/src/bot/middlewares/mark_unread.rs b/src/bot/middlewares/mark_unread.rs new file mode 100644 index 0000000000000000000000000000000000000000..186983a94034e0d83be9a7496f286302154562d9 --- /dev/null +++ b/src/bot/middlewares/mark_unread.rs @@ -0,0 +1,43 @@ +use grammers_client::{Client, Update}; +use grammers_tl_types::types::{InputDialogPeer, InputPeerChat}; + +use crate::{ + bot::{handlers::Handler, middlewares::base::Middleware}, + utils::messages::get_message, +}; + +#[derive(Clone)] +pub struct MarkUnread { + handler: Box<dyn Handler>, +} + +#[async_trait::async_trait] +impl Handler for MarkUnread { + async fn react(&self, client: &Client, update: &Update) -> anyhow::Result<()> { + let res = self.handler.react(client, update).await; + + if let Some(message) = get_message(update) { + let res = client + .invoke(&grammers_tl_types::functions::messages::MarkDialogUnread { + peer: grammers_tl_types::enums::InputDialogPeer::Peer(InputDialogPeer { + peer: grammers_tl_types::enums::InputPeer::Chat(InputPeerChat { + chat_id: message.chat().id(), + }), + }), + unread: true, + }) + .await; + if let Err(err) = res { + log::warn!("Cannot mark dialog unread. Reason: {err}."); + } + } + + res + } +} + +impl Middleware for MarkUnread { + fn from_handler(handler: Box<dyn Handler>) -> Self { + Self { handler } + } +} diff --git a/src/bot/middlewares/members_count.rs b/src/bot/middlewares/members_count.rs new file mode 100644 index 0000000000000000000000000000000000000000..ef7d8aacff5aaa283ec6d5993b44af6684ca1fe9 --- /dev/null +++ b/src/bot/middlewares/members_count.rs @@ -0,0 +1,36 @@ +use grammers_client::{Client, Update}; + +use crate::{ + bot::{handlers::Handler, middlewares::base::Middleware}, + utils::messages::get_message, +}; + +#[derive(Clone)] +pub struct MembersCount<const MAX_COUNT: usize> { + handler: Box<dyn Handler>, +} + +#[async_trait::async_trait] +impl<const MAX_COUNT: usize> Handler for MembersCount<MAX_COUNT> { + async fn react(&self, client: &Client, update: &Update) -> anyhow::Result<()> { + if let Some(message) = get_message(update) { + let participants = client + .iter_participants(message.chat()) + .total() + .await + .unwrap_or(0); + + if participants > MAX_COUNT { + log::warn!("Too many participants. Skipping."); + return Ok(()); + } + } + self.handler.react(client, update).await + } +} + +impl<const MAX_COUNT: usize> Middleware for MembersCount<MAX_COUNT> { + fn from_handler(handler: Box<dyn Handler>) -> Self { + Self { handler } + } +} diff --git a/src/bot/middlewares/mod.rs b/src/bot/middlewares/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..d0ec112ca7fa7eeacb0b70d9ad2db1c3665d67e9 --- /dev/null +++ b/src/bot/middlewares/mod.rs @@ -0,0 +1,3 @@ +pub mod base; +pub mod mark_unread; +pub mod members_count; diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 340c21b88b137d6496011a71e68a0711e01a23a4..0aeb3946d3308e839e9929ead72b99b71117aab1 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -1,6 +1,7 @@ mod filters; mod handlers; mod main; +pub mod middlewares; pub mod utils; pub use main::start;