tgbot/handler/
webhook.rs

1use std::{io::Error as IoError, net::SocketAddr, sync::Arc};
2
3use axum::Router;
4use tokio::net::TcpListener;
5
6use crate::{handler::UpdateHandler, types::Update};
7
8/// Represents a simple webhook server for handling incoming updates from the Telegram Bot API.
9#[cfg_attr(nightly, doc(cfg(feature = "webhook")))]
10pub struct WebhookServer {
11    router: Router,
12}
13
14impl WebhookServer {
15    /// Creates a new `WebhookServer`.
16    ///
17    /// # Arguments
18    ///
19    /// * `path` - The path where the webhook server will receive incoming updates.
20    /// * `handler` - The handler for processing updates.
21    pub fn new<A, B>(path: A, handler: B) -> Self
22    where
23        A: AsRef<str>,
24        B: UpdateHandler + Send + Sync + 'static,
25    {
26        let router = Router::new()
27            .route(path.as_ref(), axum::routing::post(handle_update::<B>))
28            .layer(axum::Extension(Arc::new(handler)));
29        Self { router }
30    }
31
32    /// Runs the server
33    ///
34    /// Returns the local address that the server is bound to.
35    ///
36    /// # Arguments
37    ///
38    /// * `address` - The address to bind the server to.
39    pub async fn run<T>(self, address: T) -> Result<SocketAddr, IoError>
40    where
41        T: Into<SocketAddr>,
42    {
43        let listener = TcpListener::bind(address.into()).await?;
44        let result = listener.local_addr();
45        axum::serve(listener, self.router).await?;
46        result
47    }
48}
49
50impl From<WebhookServer> for Router {
51    fn from(value: WebhookServer) -> Self {
52        value.router
53    }
54}
55
56async fn handle_update<H>(handler: axum::Extension<Arc<H>>, axum::extract::Json(update): axum::extract::Json<Update>)
57where
58    H: UpdateHandler,
59{
60    handler.handle(update).await
61}