Write documentation for webhooks

This commit is contained in:
Maybe Waffle 2022-03-25 18:29:19 +04:00
parent e951af7abe
commit 4abafbcacc
3 changed files with 92 additions and 7 deletions

View file

@ -1,18 +1,20 @@
//! Receiving updates from Telegram.
//!
//! The key trait here is [`UpdateListener`]. You can get its implementation
//! using one these functions:
//! from:
//!
//! - [`polling_default`], which returns a default long polling listener.
//! - [`polling`], which returns a long polling listener with your
//! - [`polling_default`] function, which returns a default long polling
//! listener.
//! - [`polling`] function, which returns a long polling listener with your
//! configuration.
//! - Various functions in the [`webhooks`] module that return webhook listeners
//!
//! And then you can extract updates from it or pass them directly to a
//! [`Dispatcher`].
//!
//! Telegram supports two ways of [getting updates]: [long polling] and
//! [webhooks]. Currently, only the former one is implemented (see [`polling()`]
//! and [`polling_default`]). See also [README FAQ about webhooks](https://github.com/teloxide/teloxide/blob/master/README.md#faq).
//! [webhooks]. For the former see [`polling`] and [`polling_default`], for the
//! latter see the [`webhooks`] module.
//!
//! [`UpdateListener`]: UpdateListener
//! [`polling_default`]: polling_default
@ -23,6 +25,8 @@
//! [long polling]: https://en.wikipedia.org/wiki/Push_technology#Long_polling
//! [webhooks]: https://en.wikipedia.org/wiki/Webhook
/// Implementations of webhook update listeners - an alternative (to
/// [`fn@polling`]) way of receiving updates from telegram.
#[cfg(any(feature = "webhooks-axum"))]
pub mod webhooks;

View file

@ -1,3 +1,4 @@
//!
use std::net::SocketAddr;
use crate::{requests::Requester, types::InputFile};
@ -62,6 +63,9 @@ pub use self::axum::{axum, axum_no_setup, axum_to_router};
#[cfg(feature = "webhooks-axum")]
mod axum;
/// Calls `set_webhook` with arguments from `options`.
///
/// Note: this takes out `certificate`.
async fn setup_webhook<R>(bot: R, options: &mut Options) -> Result<(), R::Err>
where
R: Requester,
@ -80,6 +84,16 @@ where
Ok(())
}
/// Returns first (`.0`) field from a tuple as a `&mut` reference.
///
/// This hack is needed because there isn't currently a way to easily force a
/// closure to be higher-ranked (`for<'a> &'a mut _ -> &'a mut _`) which causes
/// problems when using [`StatefulListener`] to implement update listener.
///
/// This could be probably removed once [rfc#3216] is implemented.
///
/// [`StatefulListener`]:
/// [rfc#3216]: https://github.com/rust-lang/rfcs/pull/3216
fn tuple_first_mut<A, B>(tuple: &mut (A, B)) -> &mut A {
&mut tuple.0
}

View file

@ -11,7 +11,16 @@ use crate::{
requests::Requester,
};
/// Webhook implementation based on the [axum] framework.
/// Webhook implementation based on the [mod@axum] framework.
///
/// This function does all the work necessary for webhook to work, it:
/// - Calls [`set_webhook`], so telegram starts sending updates our way
/// - Spawns [mod@axum] server listening for updates
/// - When the update listener is [`stop`]ped, calls [`delete_webhook`]
///
/// [`set_webhook`]: crate::payloads::SetWebhook
/// [`delete_webhook`]: crate::payloads::DeleteWebhook
/// [`stop`]: StopToken::stop
///
/// ## Panics
///
@ -19,9 +28,14 @@ use crate::{
///
/// [address]: Options.address
///
/// ## Errors
/// ## Fails
///
/// If `set_webhook()` fails.
///
/// ## See also
///
/// [`axum_to_router`] and [`axum_no_setup`] for lower-level versions of this
/// function.
pub async fn axum<R>(
bot: R,
options: Options,
@ -50,6 +64,47 @@ where
Ok(update_listener)
}
/// Webhook implementation based on the [mod@axum] framework that can reuse
/// existing [mod@axum] server.
///
/// This function does most of the work necessary for webhook to work, it:
/// - Calls [`set_webhook`], so telegram starts sending updates our way
/// - When the update listener is [`stop`]ped, calls [`delete_webhook`]
///
/// The only missing part is running [mod@axum] server with a returned
/// [`axum::Router`].
///
/// This function is intended to be used in cases when you already have an
/// [mod@axum] server running and can reuse it for webhooks.
///
/// **Note**: in order for webhooks to work, you need to use returned
/// [`axum::Router`] in an [mod@axum] server that is bound to
/// [`options.address`].
///
/// It may also be desired to use [`with_graceful_shutdown`] with the returned
/// future in order to shutdown the server with the [`stop`] of the listener.
///
/// [`set_webhook`]: crate::payloads::SetWebhook
/// [`delete_webhook`]: crate::payloads::DeleteWebhook
/// [`stop`]: StopToken::stop
/// [`options.address`]: Options.address
/// [`with_graceful_shutdown`]: axum::Server::with_graceful_shutdown
///
/// ## Returns
///
/// A update listener, stop-future, axum router triplet on success.
///
/// The "stop-future" is resolved after [`stop`] is called on the stop token of
/// the returned update listener.
///
/// ## Fails
///
/// If `set_webhook()` fails.
///
/// ## See also
///
/// [`fn@axum`] for higher-level and [`axum_no_setup`] for lower-level
/// versions of this function.
pub async fn axum_to_router<R>(
bot: R,
mut options: Options,
@ -85,6 +140,13 @@ where
Ok((listener, stop_flag, router))
}
/// Webhook implementation based on the [mod@axum] framework that doesn't
/// perform any setup work.
///
/// ## See also
///
/// [`fn@axum`] and [`axum_to_router`] for higher-level versions of this
/// function.
pub fn axum_no_setup(
options: Options,
) -> (
@ -110,6 +172,10 @@ pub fn axum_no_setup(
let (tx, rx): (Sender, _) = mpsc::unbounded_channel();
async fn telegram_request(input: String, tx: Extension<Sender>) -> impl IntoResponse {
// FIXME: this should probably start returning an error response after `.stop()`
// is called to account for cases when update listener is stopped without
// stopping the server
match serde_json::from_str(&input) {
Ok(update) => {
tx.send(Ok(update)).expect("Cannot send an incoming update from the webhook")
@ -139,6 +205,7 @@ pub fn axum_no_setup(
let stream = UnboundedReceiverStream::new(rx);
// FIXME: this should support `hint_allowed_updates()`
let listener = update_listeners::StatefulListener::new(
(stream, stop_token),
tuple_first_mut,