Skip to main content

rustigram_bot/
handler.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
4
5use async_trait::async_trait;
6
7use crate::context::Context;
8use crate::error::BotResult;
9
10/// Type alias for the boxed future returned by handlers.
11pub type HandlerFuture = Pin<Box<dyn Future<Output = BotResult<()>> + Send>>;
12
13/// Core trait for all update handlers.
14///
15/// Implementors receive a [`Context`] and return a future resolving to
16/// `BotResult<()>`.
17///
18/// The return value does not influence routing. The dispatcher runs only the
19/// first route whose filter matches, and an `Err` is logged rather than
20/// propagated or passed to another handler — so returning an error reports a
21/// failure, it does not hand control anywhere else.
22#[async_trait]
23pub trait Handler: Send + Sync + 'static {
24    /// Processes an incoming update.
25    async fn handle(&self, ctx: Context) -> BotResult<()>;
26}
27
28/// A boxed, type-erased handler.
29pub type BoxHandler = Arc<dyn Handler>;
30
31/// Wraps an async function (or closure) as a [`Handler`].
32pub struct HandlerFn<F> {
33    f: F,
34}
35
36impl<F, Fut> HandlerFn<F>
37where
38    F: Fn(Context) -> Fut + Send + Sync + 'static,
39    Fut: Future<Output = BotResult<()>> + Send + 'static,
40{
41    /// Creates a new `HandlerFn` from a function or closure.
42    pub fn new(f: F) -> Self {
43        Self { f }
44    }
45}
46
47#[async_trait]
48impl<F, Fut> Handler for HandlerFn<F>
49where
50    F: Fn(Context) -> Fut + Send + Sync + 'static,
51    Fut: Future<Output = BotResult<()>> + Send + 'static,
52{
53    async fn handle(&self, ctx: Context) -> BotResult<()> {
54        (self.f)(ctx).await
55    }
56}
57
58/// Creates a [`BoxHandler`] from any async function or closure.
59///
60/// # Example
61///
62/// ```rust,ignore
63/// use rustigram_bot::{handler_fn, Context, BotResult};
64///
65/// let h = handler_fn(|ctx: Context| async move {
66///     if let Some(r) = ctx.reply("pong") { r.await?; }
67///     Ok(())
68/// });
69/// ```
70pub fn handler_fn<F, Fut>(f: F) -> BoxHandler
71where
72    F: Fn(Context) -> Fut + Send + Sync + 'static,
73    Fut: Future<Output = BotResult<()>> + Send + 'static,
74{
75    Arc::new(HandlerFn::new(f))
76}
77
78/// A handler that logs any error from the wrapped handler and swallows it.
79pub struct LoggingHandler {
80    inner: BoxHandler,
81}
82
83impl LoggingHandler {
84    /// Wraps a handler so its errors are logged with the update ID and then
85    /// discarded, leaving the outer result `Ok`.
86    pub fn wrap(inner: BoxHandler) -> BoxHandler {
87        Arc::new(Self { inner })
88    }
89}
90
91#[async_trait]
92impl Handler for LoggingHandler {
93    async fn handle(&self, ctx: Context) -> BotResult<()> {
94        let update_id = ctx.update_id();
95        if let Err(e) = self.inner.handle(ctx).await {
96            tracing::error!("Handler error on update {}: {}", update_id, e);
97        }
98        Ok(())
99    }
100}
101
102// Arc<dyn Handler> itself implements Handler so BoxHandler can be passed
103// directly to DispatcherBuilder::on() without unwrapping.
104#[async_trait]
105impl Handler for std::sync::Arc<dyn Handler> {
106    async fn handle(&self, ctx: Context) -> BotResult<()> {
107        (**self).handle(ctx).await
108    }
109}