diff --git a/Cargo.lock b/Cargo.lock index c4881fc0..26b8a713 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1144,7 +1144,7 @@ dependencies = [ [[package]] name = "royalnet" -version = "0.2.1" +version = "0.3.0" dependencies = [ "anyhow", "chrono", diff --git a/src/services/telegram/commands/mod.rs b/src/services/telegram/commands/mod.rs index 155afab7..5221a71a 100644 --- a/src/services/telegram/commands/mod.rs +++ b/src/services/telegram/commands/mod.rs @@ -2,12 +2,10 @@ // https://github.com/teloxide/teloxide/blob/master/crates/teloxide/examples/dispatching_features.rs use anyhow::{Context, Error, Result}; -use teloxide::{Bot, dptree}; -use teloxide::dispatching::{DefaultKey, Dispatcher, HandlerExt, UpdateFilterExt}; -use teloxide::dptree::entry; +use teloxide::Bot; use teloxide::payloads::SendMessageSetters; use teloxide::requests::Requester; -use teloxide::types::{ChatId, Message, MessageId, Update}; +use teloxide::types::{ChatId, Message, MessageId}; use teloxide::utils::command::BotCommands; mod start; @@ -50,43 +48,43 @@ impl Command { log::trace!("Setting commands successful!"); Ok(()) } -} -async fn handle_command(bot: Bot, command: Command, message: Message) -> CommandResult { - log::trace!("Received command: {command:?}"); + pub async fn handle(self, bot: Bot, message: Message) -> CommandResult { + log::trace!("Handling command: {self:?}"); - let result = match command { - Command::Start => start::handler(&bot, &message).await, - Command::Help(target) => match target.as_str() { - "" => help::handler_all(&bot, &message).await, - _ => help::handler_specific(&bot, &message, &target).await, - }, - Command::Fortune => fortune::handler(&bot, &message).await, - Command::Echo(text) => echo::handler(&bot, &message, &text).await, - Command::WhoAmI => whoami::handler(&bot, &message).await, - Command::Answer(_) => answer::handler(&bot, &message).await, - Command::Reminder(args) => reminder::handler(&bot, &message, args).await, - }; + let result = match self { + Command::Start => start::handler(&bot, &message).await, + Command::Help(target) => match target.as_str() { + "" => help::handler_all(&bot, &message).await, + _ => help::handler_specific(&bot, &message, &target).await, + }, + Command::Fortune => fortune::handler(&bot, &message).await, + Command::Echo(text) => echo::handler(&bot, &message, &text).await, + Command::WhoAmI => whoami::handler(&bot, &message).await, + Command::Answer(_) => answer::handler(&bot, &message).await, + Command::Reminder(args) => reminder::handler(&bot, &message, args).await, + }; - if result.is_ok() { - return Ok(()) + if result.is_ok() { + return Ok(()) + } + + let chat_id = message.chat.id; + let message_id = message.id; + let error = result.unwrap_err(); + + let result2 = error_command(&bot, chat_id, message_id, &error).await; + + if result2.is_ok() { + return Ok(()) + } + + let error2 = result2.unwrap_err(); + + log::error!("Command message {message_id:?} in {chat_id:?} errored out with `{error}`, and it was impossible to handle the error because of `{error2}`\n\n{error2:?}"); + + Ok(()) } - - let chat_id = message.chat.id; - let message_id = message.id; - let error = result.unwrap_err(); - - let result2 = error_command(&bot, chat_id, message_id, &error).await; - - if result2.is_ok() { - return Ok(()) - } - - let error2 = result2.unwrap_err(); - - log::error!("Command message {message_id:?} in {chat_id:?} errored out with `{error}`, and it was impossible to handle the error because of `{error2}`\n\n{error2:?}"); - - Ok(()) } async fn error_command(bot: &Bot, chat_id: ChatId, message_id: MessageId, error: &Error) -> CommandResult { @@ -103,7 +101,7 @@ async fn error_command(bot: &Bot, chat_id: ChatId, message_id: MessageId, error: Ok(()) } -async fn unknown_command(bot: Bot, message: Message) -> CommandResult { +pub async fn unknown_command(bot: Bot, message: Message) -> CommandResult { log::debug!("Received an unknown command."); bot.send_message(message.chat.id, "⚠️ Comando sconosciuto.") @@ -114,21 +112,4 @@ async fn unknown_command(bot: Bot, message: Message) -> CommandResult { Ok(()) } -pub fn dispatcher(bot: Bot) -> Dispatcher { - Dispatcher::builder( - bot, - Update::filter_message() - .branch( - entry() - .filter_command::() - .endpoint(handle_command) - ) - .endpoint(unknown_command) - ) - .dependencies( - dptree::deps![] // No deps needed at the moment. - ) - .build() -} - -type CommandResult = anyhow::Result<()>; \ No newline at end of file +type CommandResult = Result<()>; \ No newline at end of file diff --git a/src/services/telegram/mod.rs b/src/services/telegram/mod.rs index 0542575c..2eedd803 100644 --- a/src/services/telegram/mod.rs +++ b/src/services/telegram/mod.rs @@ -1,7 +1,11 @@ use std::convert::Infallible; -use teloxide::Bot; -use anyhow::{Context, Result}; +use teloxide::{Bot, dptree}; +use anyhow::{Context, Error, Result}; +use regex::Regex; +use teloxide::dispatching::{DefaultKey, Dispatcher, HandlerExt, UpdateFilterExt}; +use teloxide::dptree::entry; use teloxide::requests::Requester; +use teloxide::types::{Me, Message, Update}; use super::RoyalnetService; pub(self) mod config; @@ -18,14 +22,18 @@ impl BotService { } } - async fn send_start_notification(&mut self) -> Result<()> { + async fn send_start_notification(&mut self, me: &Me) -> Result<()> { let chat_id = config::TELEGRAM_NOTIFICATION_CHATID() .context("Variabile d'ambiente TELEGRAM_NOTIFICATION_CHATID mancante.")?; + let version = crate::utils::version::VERSION; + let username = &me.username.as_ref().unwrap(); + let id = &me.user.id; + let text = format!( "💠 Servizio Telegram avviato\n\ - Royalnet v{}", - crate::utils::version::VERSION, + Royalnet v{version}\n\ + @{username} ({id})", ); self.bot.send_message(chat_id, text) @@ -40,6 +48,10 @@ impl RoyalnetService for BotService { async fn run(mut self) -> Result { log::info!("Starting Telegram service..."); + log::debug!("Getting bot information..."); + let me = self.bot.get_me().await + .context("Failed to get information about self")?; + log::debug!("Setting bot commands..."); match commands::Command::set_commands(&mut self.bot).await { Err(e) => log::warn!("Failed to set bot commands: {e}"), @@ -47,15 +59,44 @@ impl RoyalnetService for BotService { } log::debug!("Sending start notification..."); - match self.send_start_notification().await { + match self.send_start_notification(&me).await { Err(e) => log::warn!("Failed to send start notification: {e}"), _ => log::trace!("Start notification sent successfully!"), } log::debug!("Starting Telegram dispatcher..."); - commands::dispatcher(self.bot).dispatch().await; + dispatcher(self.bot, me).dispatch().await; log::error!("Telegram dispatcher has exited, bailing out..."); anyhow::bail!("Telegram dispatcher has exited.") } } + +fn dispatcher(bot: Bot, me: Me) -> Dispatcher { + let bot_name = me.user.username.unwrap(); + log::trace!("Bot name is: {bot_name:?}"); + + let regex = Regex::new(&format!(r"^/[a-z0-9_]+(?:@{bot_name})?(?:\s+.*)?$")).unwrap(); + log::trace!("Pseudo-command regex is: {regex:?}"); + + log::trace!("Building dispatcher..."); + Dispatcher::builder( + bot, + Update::filter_message() + .branch(entry() + .filter(move |message: Message| -> bool { + message.text().is_some_and(|text| regex.is_match(text)) + }) + .branch( + entry() + .filter_command::() + .endpoint(commands::Command::handle) + ) + .endpoint(commands::unknown_command) + ) + ) + .dependencies( + dptree::deps![] // No deps needed at the moment. + ) + .build() +}