From fee8178ad262d6e7a6b08e9095c1d2323459997a Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Tue, 28 Oct 2025 17:04:25 +0200 Subject: [PATCH] refactor: clippy warnings --- src/commands.rs | 5 +++++ src/download.rs | 22 +++++++--------------- src/handler.rs | 32 ++++++++++++++++++++------------ src/main.rs | 25 +++++++++---------------- src/utils.rs | 8 ++++++-- 5 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index d6064a7..aeea625 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -13,6 +13,11 @@ pub enum Command { Curse, } +/// Handle a command from the user. +/// +/// # Errors +/// +/// Returns a Teloxide error if the message fails to send. pub async fn answer(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> { match cmd { Command::Help => { diff --git a/src/download.rs b/src/download.rs index 80207e8..df41670 100644 --- a/src/download.rs +++ b/src/download.rs @@ -58,11 +58,6 @@ async fn run_command_in_tempdir(cmd: &str, args: &[&str]) -> Result Error::ytdlp_failed(stderr), _ => Error::Other(format!("{cmd} failed: {stderr}")), @@ -241,19 +236,16 @@ pub async fn process_download_result( } // deterministic ordering - media_items.sort_by(|(p1, _), (p2, _)| p1.cmp(p2)); + media_items.sort_by_key(|(_, k)| match k { + MediaKind::Video => 0, + MediaKind::Image => 1, + MediaKind::Unknown => 2, + }); info!(media_items = media_items.len(), "Sending media to chat"); - // prefer video over image - if let Some((path, MediaKind::Video)) = media_items.iter().find(|(_, k)| *k == MediaKind::Video) - { - return send_media_from_path(bot, chat_id, path.clone(), MediaKind::Video).await; - } - - if let Some((path, MediaKind::Image)) = media_items.iter().find(|(_, k)| *k == MediaKind::Image) - { - return send_media_from_path(bot, chat_id, path.clone(), MediaKind::Image).await; + if let Some((path, kind)) = media_items.first() { + return send_media_from_path(bot, chat_id, path.clone(), *kind).await; } Err(Error::NoMediaFound) diff --git a/src/handler.rs b/src/handler.rs index 82447c0..da04547 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -7,26 +7,28 @@ use std::{pin::Pin, sync::Arc}; use teloxide::{Bot, types::ChatId}; use tracing::info; +type DownloadFn = fn(&str) -> Pin> + Send>>; + #[derive(Debug, Clone)] pub struct Handler { name: &'static str, regex: Regex, - handler_fn: fn(&str) -> Pin> + Send>>, + func: DownloadFn, } impl Handler { - #[must_use] + /// Create a new handler with a regex pattern and download function. + /// + /// # Errors + /// + /// Returns `RegexError` if the regex pattern is invalid. pub fn new( name: &'static str, regex_pattern: &'static str, - handler_fn: fn(&str) -> Pin> + Send>>, + func: DownloadFn, ) -> std::result::Result { let regex = Regex::new(regex_pattern)?; - Ok(Self { - name, - regex, - handler_fn, - }) + Ok(Self { name, regex, func }) } #[inline] @@ -35,16 +37,22 @@ impl Handler { self.name } + /// Extract a URL matching this handler's regex pattern. #[must_use] - pub fn try_extract(&self, text: &str) -> Option { + pub fn try_extract<'a>(&self, text: &'a str) -> Option<&'a str> { self.regex .captures(text) - .and_then(|c| c.get(0).map(|m| m.as_str().to_owned())) + .and_then(|c| c.get(0).map(|m| m.as_str())) } - pub async fn handle(&self, bot: &Bot, chat_id: ChatId, url: String) -> Result<()> { + /// Handle a URL by downloading and sending the media. + /// + /// # Errors + /// + /// Returns `Error` if download or media processing fails. + pub async fn handle(&self, bot: &Bot, chat_id: ChatId, url: &str) -> Result<()> { info!(handler = %self.name(), url = %url, "handling url"); - let dr = (self.handler_fn)(&url).await?; + let dr = (self.func)(url).await?; process_download_result(bot, chat_id, dr).await } } diff --git a/src/main.rs b/src/main.rs index 4af31cc..ddb9970 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,10 +30,9 @@ async fn main() -> color_eyre::Result<()> { // Command::repl(bot.clone(), answer).await; teloxide::repl(bot.clone(), move |bot: Bot, msg: Message| { - // clone the handlers vector into the closure let handlers = handlers.clone(); async move { - process_message(&bot, &msg, &handlers); + process_message(&bot, &msg, &handlers).await; respond(()) } }) @@ -42,26 +41,20 @@ async fn main() -> color_eyre::Result<()> { Ok(()) } -fn process_message(bot: &Bot, msg: &Message, handlers: &[Handler]) { +async fn process_message(bot: &Bot, msg: &Message, handlers: &[Handler]) { let Some(text) = msg.text() else { return; }; for handler in handlers { if let Some(url) = handler.try_extract(text) { - handle_extracted_content(bot.clone(), msg.chat.id, handler.clone(), url); - break; + if let Err(err) = handler.handle(bot, msg.chat.id, url).await { + error!(%err, "handler failed"); + let _ = bot + .send_message(msg.chat.id, "Failed to fetch media, you foking donkey.") + .await; + } + return; } } } - -fn handle_extracted_content(bot: Bot, chat: ChatId, handler: Handler, url: String) { - tokio::spawn(async move { - if let Err(err) = handler.handle(&bot, chat, url).await { - error!(%err, "handler failed"); - let _ = bot - .send_message(chat, "Failed to fetch media, you foking donkey.") - .await; - } - }); -} diff --git a/src/utils.rs b/src/utils.rs index 0eecd7a..1a5bd6d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -121,8 +121,12 @@ pub async fn send_media_from_path( if let Some(cap) = caption_opt { request = request.caption(cap); } - if let Ok(message) = request.await { - info!(message_id = message.id.to_string(), "{} sent", kind); + match request.await { + Ok(message) => info!(message_id = message.id.to_string(), "{} sent", kind), + Err(e) => { + error!("Failed to send {}: {e}", kind.to_str()); + return Err(Error::Teloxide(e)); + } } }}; }