mirror of
https://github.com/teloxide/teloxide.git
synced 2025-03-14 11:44:04 +01:00
commit
e8c58086d2
20 changed files with 201 additions and 78 deletions
|
@ -363,7 +363,7 @@ A: Most programming languages have their own implementations of Telegram bots fr
|
|||
|
||||
Q: Can I use webhooks?
|
||||
|
||||
A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [webhook_ping_pong_bot](examples/ngrok_ping_pong_bot/src/main.rs).
|
||||
A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](examples/heroku_ping_pong_bot/src/main.rs).
|
||||
|
||||
Associated links:
|
||||
- [Marvin's Marvellous Guide to All Things Webhook](https://core.telegram.org/bots/webhooks)
|
||||
|
@ -371,7 +371,7 @@ Associated links:
|
|||
|
||||
Q: Can I use different loggers?
|
||||
|
||||
A: Of course, you can. The [`enable_logging!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging.html) and [`enable_logging_with_filter!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging_with_filter.html) macros are just convenient utilities, not necessary to use them. You can setup a different logger, for example, [fern](https://crates.io/crates/fern), as usual, e.g. teloxide has no specific requirements as it depends only on [log](https://crates.io/crates/log).
|
||||
A: Yes. The [`enable_logging!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging.html) and [`enable_logging_with_filter!`](https://docs.rs/teloxide/latest/teloxide/macro.enable_logging_with_filter.html) macros are just convenient utilities, not necessary to use them. You can setup a different logger, for example, [fern](https://crates.io/crates/fern), as usual, e.g. teloxide has no specific requirements as it depends only on [log](https://crates.io/crates/log).
|
||||
|
||||
## Community bots
|
||||
Feel free to push your own bot into our collection!
|
||||
|
|
|
@ -8,9 +8,11 @@ use std::{sync::Arc, time::Duration};
|
|||
mod api;
|
||||
mod download;
|
||||
|
||||
/// A Telegram bot used to send requests.
|
||||
/// A requests sender.
|
||||
///
|
||||
/// No need to put `Bot` into `Arc`, because it's already in.
|
||||
/// No need to put it into [`Arc`], because it's already in.
|
||||
///
|
||||
/// [`Arc`]: std::sync::Arc
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Bot {
|
||||
token: Arc<str>,
|
||||
|
@ -108,6 +110,9 @@ impl Bot {
|
|||
}
|
||||
}
|
||||
|
||||
/// A builder of [`Bot`], supporting some extra settings.
|
||||
///
|
||||
/// [`Bot`] crate::Bot
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BotBuilder {
|
||||
token: Option<String>,
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use crate::{
|
||||
dispatching::{dialogue::TransitionOut, UpdateWithCx},
|
||||
types::Message,
|
||||
};
|
||||
use crate::dispatching::dialogue::{TransitionIn, TransitionOut};
|
||||
use futures::future::BoxFuture;
|
||||
|
||||
/// Represents a dialogue FSM.
|
||||
|
@ -9,6 +6,6 @@ pub trait BotDialogue: Default {
|
|||
/// Turns itself into another state, depending on the input message.
|
||||
fn dispatch(
|
||||
self,
|
||||
cx: UpdateWithCx<Message>,
|
||||
cx: TransitionIn,
|
||||
) -> BoxFuture<'static, TransitionOut<Self>>;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
/// A dispatcher of dialogues.
|
||||
///
|
||||
/// Note that `DialogueDispatcher` implements [`DispatcherHandler`], so you can
|
||||
/// just put an instance of this dispatcher into the [`Dispatcher`]'s methods.
|
||||
/// Note that it implements [`DispatcherHandler`], so you can just put an
|
||||
/// instance of this dispatcher into the [`Dispatcher`]'s methods.
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](crate::dispatching::dialogue).
|
||||
/// See the [module-level documentation](crate::dispatching::dialogue) for the
|
||||
/// design overview.
|
||||
///
|
||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
/// [`DispatcherHandler`]: crate::dispatching::DispatcherHandler
|
||||
|
|
|
@ -12,8 +12,15 @@ pub enum DialogueStage<D> {
|
|||
|
||||
/// Returns a new dialogue state.
|
||||
///
|
||||
/// Note the `Dialogue: From<State>` constraint. It means that you don't need to
|
||||
/// pass `Dialogue` -- you can just pass one of it's states. [`From`] can be
|
||||
/// conveniently derived by [derive-more].
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](crate::dispatching::dialogue).
|
||||
///
|
||||
/// [`From`]: std::convert::From
|
||||
/// [derive-more]: https://crates.io/crates/derive_more
|
||||
pub fn next<Dialogue, State>(new_state: State) -> TransitionOut<Dialogue>
|
||||
where
|
||||
Dialogue: From<State>,
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
//! Dealing with dialogues.
|
||||
//!
|
||||
//! There are four main components:
|
||||
//! There are three main components:
|
||||
//!
|
||||
//! 1. Your type `D` (typically an enumeration), implementing [`BotDialogue`].
|
||||
//! It is essentially a [FSM]: its variants are possible dialogue states and
|
||||
//! [`BotDialogue::dispatch`] is a transition function.
|
||||
//!
|
||||
//! 1. Your type `D`, which designates a dialogue state at the current
|
||||
//! moment.
|
||||
//! 2. [`Storage<D>`], which encapsulates all the dialogues.
|
||||
//! 3. Your handler, which receives an update and turns your dialogue into the
|
||||
//! next state ([`DialogueDispatcherHandlerCx<YourUpdate, D>`] ->
|
||||
//! [`DialogueStage<D>`]).
|
||||
//! 4. [`DialogueDispatcher`], which encapsulates your handler, [`Storage<D>`],
|
||||
//!
|
||||
//! 3. [`DialogueDispatcher`], which encapsulates your handler, [`Storage<D>`],
|
||||
//! and implements [`DispatcherHandler`].
|
||||
//!
|
||||
//! For example, you supply [`DialogueDispatcher`] into
|
||||
//! [`Dispatcher::messages_handler`]. Every time [`Dispatcher`] sees an incoming
|
||||
//! [`UpdateKind::Message(message)`], `message` is transferred into
|
||||
//! [`DialogueDispatcher`]. After this, following steps are executed:
|
||||
//! You pass [`DialogueDispatcher`] into [`Dispatcher`]. Every time
|
||||
//! [`Dispatcher`] sees an incoming input, it is transferred into
|
||||
//! [`DialogueDispatcher`], and the following steps are executed:
|
||||
//!
|
||||
//! 1. If a storage doesn't contain a dialogue from this chat, supply
|
||||
//! `D::default()` into you handler, otherwise, supply the saved dialogue
|
||||
|
@ -23,21 +22,102 @@
|
|||
//! from the storage, otherwise ([`DialogueStage::Next`]) force the storage to
|
||||
//! update the dialogue.
|
||||
//!
|
||||
//! Please, see [examples/dialogue_bot] as an example.
|
||||
//! To avoid boilerplate, teloxide exports these convenient things: the [`up!`]
|
||||
//! macro, the [`next`] and [`exit`] functions, and `#[derive(BotDialogue)]`.
|
||||
//! Here's how your dialogues management code skeleton should look like:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use std::convert::Infallible;
|
||||
//!
|
||||
//! use teloxide::prelude::*;
|
||||
//! use teloxide_macros::BotDialogue;
|
||||
//!
|
||||
//! struct _1State;
|
||||
//! struct _2State;
|
||||
//! struct _3State;
|
||||
//!
|
||||
//! type Out = TransitionOut<D>;
|
||||
//!
|
||||
//! async fn _1_transition(_cx: TransitionIn, _state: _1State) -> Out {
|
||||
//! todo!()
|
||||
//! }
|
||||
//! async fn _2_transition(_cx: TransitionIn, _state: _2State) -> Out {
|
||||
//! todo!()
|
||||
//! }
|
||||
//! async fn _3_transition(_cx: TransitionIn, _state: _3State) -> Out {
|
||||
//! todo!()
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(BotDialogue)]
|
||||
//! enum D {
|
||||
//! #[transition(_1_transition)]
|
||||
//! _1(_1State),
|
||||
//! #[transition(_2_transition)]
|
||||
//! _2(_2State),
|
||||
//! #[transition(_3_transition)]
|
||||
//! _3(_3State),
|
||||
//! }
|
||||
//!
|
||||
//! impl Default for D {
|
||||
//! fn default() -> Self {
|
||||
//! Self::_1(_1State)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! async fn main() {
|
||||
//! run().await;
|
||||
//! }
|
||||
//!
|
||||
//! async fn run() {
|
||||
//! teloxide::enable_logging!();
|
||||
//! log::info!("Starting dialogue_bot!");
|
||||
//!
|
||||
//! let bot = Bot::from_env();
|
||||
//!
|
||||
//! Dispatcher::new(bot)
|
||||
//! .messages_handler(DialogueDispatcher::new(
|
||||
//! |input: DialogueWithCx<Message, D, Infallible>| async move {
|
||||
//! // Unwrap without panic because of std::convert::Infallible.
|
||||
//! input
|
||||
//! .dialogue
|
||||
//! .unwrap()
|
||||
//! .dispatch(input.cx)
|
||||
//! .await
|
||||
//! .expect("Something wrong with the bot!")
|
||||
//! },
|
||||
//! ))
|
||||
//! .dispatch()
|
||||
//! .await;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! See [examples/dialogue_bot] as a real example.
|
||||
//!
|
||||
//! [`BotDialogue`]: crate::dispatching::dialogue::BotDialogue
|
||||
//! [`BotDialogue::dispatch`]:
|
||||
//! crate::dispatching::dialogue::BotDialogue::dispatch
|
||||
//! [FSM]: https://en.wikipedia.org/wiki/Finite-state_machine
|
||||
//!
|
||||
//! [`Storage<D>`]: crate::dispatching::dialogue::Storage
|
||||
//!
|
||||
//! [`DialogueStage<D>`]: crate::dispatching::dialogue::DialogueStage
|
||||
//! [`DialogueDispatcher`]: crate::dispatching::dialogue::DialogueDispatcher
|
||||
//!
|
||||
//! [`DialogueStage::Exit`]:
|
||||
//! crate::dispatching::dialogue::DialogueStage::Exit
|
||||
//! [`DialogueStage::Next`]: crate::dispatching::dialogue::DialogueStage::Next
|
||||
//!
|
||||
//! [`up!`]: crate::up
|
||||
//! [`next`]: crate::dispatching::dialogue::next
|
||||
//! [`exit`]: crate::dispatching::dialogue::exit
|
||||
//!
|
||||
//! [`DispatcherHandler`]: crate::dispatching::DispatcherHandler
|
||||
//! [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
//! [`Dispatcher::messages_handler`]:
|
||||
//! crate::dispatching::Dispatcher::messages_handler
|
||||
//! [`UpdateKind::Message(message)`]: crate::types::UpdateKind::Message
|
||||
//! [`DialogueWithCx<YourUpdate, D>`]:
|
||||
//! crate::dispatching::dialogue::DialogueWithCx
|
||||
//!
|
||||
//! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/tree/master/examples/dialogue_bot
|
||||
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
@ -116,5 +196,5 @@ macro_rules! up {
|
|||
/// An input passed into a FSM transition function.
|
||||
pub type TransitionIn = UpdateWithCx<Message>;
|
||||
|
||||
// A type returned from a FSM transition function.
|
||||
/// A type returned from a FSM transition function.
|
||||
pub type TransitionOut<D> = ResponseResult<DialogueStage<D>>;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/// Various serializers for memory storages.
|
||||
//! Various serializers for memory storages.
|
||||
|
||||
use serde::{de::DeserializeOwned, ser::Serialize};
|
||||
|
||||
/// A serializer for memory storages.
|
||||
|
|
|
@ -48,8 +48,8 @@ fn send<'a, Upd>(
|
|||
|
||||
/// One dispatcher to rule them all.
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](crate::dispatching).
|
||||
/// See the [module-level documentation](crate::dispatching) for the design
|
||||
/// overview.
|
||||
pub struct Dispatcher {
|
||||
bot: Bot,
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ use futures::future::BoxFuture;
|
|||
|
||||
/// An asynchronous handler of a stream of updates used in [`Dispatcher`].
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](crate::dispatching).
|
||||
/// See the [module-level documentation](crate::dispatching) for the design
|
||||
/// overview.
|
||||
///
|
||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
pub trait DispatcherHandler<Upd> {
|
||||
|
|
|
@ -5,6 +5,9 @@ use futures::{stream::BoxStream, Stream, StreamExt};
|
|||
|
||||
/// An extension trait to be used with [`DispatcherHandlerRx`].
|
||||
///
|
||||
/// See the [module-level documentation](crate::dispatching) for the design
|
||||
/// overview.
|
||||
///
|
||||
/// [`DispatcherHandlerRx`]: crate::dispatching::DispatcherHandlerRx
|
||||
pub trait DispatcherHandlerRxExt {
|
||||
/// Extracts only text messages from this stream of arbitrary messages.
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
//! Updates dispatching.
|
||||
//!
|
||||
//! The key type here is [`Dispatcher`]. It encapsulates [`Bot`] and handlers
|
||||
//! for [the 11 update kinds].
|
||||
//! for [all the update kinds].
|
||||
//!
|
||||
//! You can register a maximum of 11 handlers for [the 11 update kinds]. Every
|
||||
//! handler accept [`tokio::sync::mpsc::UnboundedReceiver`] (the RX halve of an
|
||||
//! asynchronous unbounded MPSC channel). Inside a body of your handler, you
|
||||
//! typically asynchronously concurrently iterate through updates like this:
|
||||
//! Every handler accept [`tokio::sync::mpsc::UnboundedReceiver`] (the RX halve
|
||||
//! of an asynchronous channel). Inside a body of your handler, you typically
|
||||
//! asynchronously concurrently iterate through updates like this:
|
||||
//!
|
||||
//! ```
|
||||
//! use teloxide::prelude::*;
|
||||
|
@ -29,12 +28,11 @@
|
|||
//! [`tokio::sync::mpsc::UnboundedReceiver`] and return `Future<Output = ()`
|
||||
//! as a handler.
|
||||
//!
|
||||
//! Since they implement [`DispatcherHandler`] too!
|
||||
//! Since they implement [`DispatcherHandler`] too.
|
||||
//!
|
||||
//! # Examples
|
||||
//! ### The ping-pong bot
|
||||
//! This bot has a single message handler, which answers "pong" to each incoming
|
||||
//! message:
|
||||
//! # The ping-pong bot
|
||||
//! This bot has a single handler of messages, which answers "pong" to each
|
||||
//! incoming message:
|
||||
//!
|
||||
//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/ping_pong_bot/src/main.rs))
|
||||
//! ```no_run
|
||||
|
@ -67,7 +65,7 @@
|
|||
//! [See more examples](https://github.com/teloxide/teloxide/tree/master/examples).
|
||||
//!
|
||||
//! [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
//! [the 11 update kinds]: crate::types::UpdateKind
|
||||
//! [all the update kinds]: crate::types::UpdateKind
|
||||
//! [`Update`]: crate::types::Update
|
||||
//! [`ErrorHandler`]: crate::dispatching::ErrorHandler
|
||||
//! [`DispatcherHandler`]: crate::dispatching::DispatcherHandler
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
//! updates `0..=N`.
|
||||
//!
|
||||
//! # Webhooks
|
||||
//! See the [README FAQ about webhooks](https://github.com/teloxide/teloxide/blob/master/README.md#can-i-use-webhooks).
|
||||
//! See the [README FAQ about webhooks](https://github.com/teloxide/teloxide/blob/master/README.md#faq).
|
||||
//!
|
||||
//! [`UpdateListener`]: UpdateListener
|
||||
//! [`polling_default`]: polling_default
|
||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
|||
|
||||
/// A [`Dispatcher`]'s handler's context of a bot and an update.
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](crate::dispatching).
|
||||
/// See the [module-level documentation](crate::dispatching) for the design
|
||||
/// overview.
|
||||
///
|
||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
#[derive(Debug)]
|
||||
|
@ -32,6 +32,7 @@ where
|
|||
}
|
||||
|
||||
impl UpdateWithCx<Message> {
|
||||
/// A shortcut for `.answer(text).send().await`.
|
||||
pub async fn answer_str<T>(&self, text: T) -> ResponseResult<Message>
|
||||
where
|
||||
T: Into<String>,
|
||||
|
|
|
@ -3,7 +3,7 @@ use reqwest::StatusCode;
|
|||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
|
||||
/// An error occurred after downloading a file.
|
||||
/// An error caused by downloading a file.
|
||||
#[derive(Debug, Error, From)]
|
||||
pub enum DownloadError {
|
||||
#[error("A network error: {0}")]
|
||||
|
@ -13,7 +13,7 @@ pub enum DownloadError {
|
|||
Io(#[source] std::io::Error),
|
||||
}
|
||||
|
||||
/// An error occurred after making a request to Telegram.
|
||||
/// An error caused by sending a request to Telegram.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RequestError {
|
||||
#[error("A Telegram's error #{status_code}: {kind:?}")]
|
||||
|
@ -36,9 +36,13 @@ pub enum RequestError {
|
|||
InvalidJson(#[source] serde_json::Error),
|
||||
}
|
||||
|
||||
/// A kind of a API error returned from Telegram. If you receive Unknown value,
|
||||
/// please [open the issue](https://github.com/teloxide/teloxide/issues/new) with description
|
||||
/// of error.
|
||||
/// A kind of an API error.
|
||||
///
|
||||
/// If you receive [`ApiErrorKind::Unknown`], please [open an issue] with
|
||||
/// the description of the error.
|
||||
///
|
||||
/// [`ApiErrorKind::Unknown`]: crate::ApiErrorKind::Unknown
|
||||
/// [open an issue]: https://github.com/teloxide/teloxide/issues/new
|
||||
#[derive(Debug, Deserialize, PartialEq, Hash, Eq, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum ApiErrorKind {
|
||||
|
@ -46,7 +50,7 @@ pub enum ApiErrorKind {
|
|||
Unknown(String),
|
||||
}
|
||||
|
||||
/// A kind of a known API error returned from Telegram.
|
||||
/// A kind of a known API error.
|
||||
#[derive(Debug, Deserialize, PartialEq, Copy, Hash, Eq, Clone)]
|
||||
pub enum KnownApiErrorKind {
|
||||
/// Occurs when the bot tries to send message to user who blocked the bot.
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#![forbid(unsafe_code)]
|
||||
|
||||
pub use bot::{Bot, BotBuilder};
|
||||
pub use errors::{ApiErrorKind, DownloadError, RequestError};
|
||||
pub use errors::{
|
||||
ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError,
|
||||
};
|
||||
|
||||
mod errors;
|
||||
mod net;
|
||||
|
|
|
@ -10,8 +10,11 @@ use crate::{
|
|||
/// Once the user has confirmed their payment and shipping details, the Bot API
|
||||
/// sends the final confirmation in the form of an [`Update`] with the field
|
||||
/// `pre_checkout_query`. Use this method to respond to such pre-checkout
|
||||
/// queries. Note: The Bot API must receive an answer within 10 seconds after
|
||||
/// the pre-checkout query was sent.
|
||||
/// queries.
|
||||
///
|
||||
/// # Note
|
||||
/// The Bot API must receive an answer within 10 seconds after the pre-checkout
|
||||
/// query was sent.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#answerprecheckoutquery).
|
||||
///
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
/// [The official docs](https://core.telegram.org/bots/api#callbackgame).
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A placeholder, currently holds no information. Use [@Botfather] to set up
|
||||
/// your game.
|
||||
/// A placeholder, currently holds no information.
|
||||
///
|
||||
/// Use [@Botfather] to set up your game.
|
||||
///
|
||||
/// [@Botfather]: https://t.me/botfather
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
|
|
|
@ -46,7 +46,9 @@ pub enum PassportElementErrorKind {
|
|||
}
|
||||
|
||||
/// Represents an issue in one of the data fields that was provided by the
|
||||
/// user. The error is considered resolved when the field's value changes.
|
||||
/// user.
|
||||
///
|
||||
/// The error is considered resolved when the field's value changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrordatafield).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -61,9 +63,10 @@ pub struct PassportElementErrorDataField {
|
|||
pub data_hash: String,
|
||||
}
|
||||
|
||||
/// Represents an issue with the front side of a document. The error is
|
||||
/// considered resolved when the file with the front side of the document
|
||||
/// changes.
|
||||
/// Represents an issue with the front side of a document.
|
||||
///
|
||||
/// The error is considered resolved when the file with the front side of the
|
||||
/// document changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfrontside).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -76,9 +79,10 @@ pub struct PassportElementErrorFrontSide {
|
|||
pub file_hash: String,
|
||||
}
|
||||
|
||||
/// Represents an issue with the reverse side of a document. The error is
|
||||
/// considered resolved when the file with reverse side of the document
|
||||
/// changes.
|
||||
/// Represents an issue with the reverse side of a document.
|
||||
///
|
||||
/// The error is considered resolved when the file with reverse side of the
|
||||
/// document changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorreverseside).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -91,8 +95,9 @@ pub struct PassportElementErrorReverseSide {
|
|||
pub file_hash: String,
|
||||
}
|
||||
|
||||
//// Represents an issue with the selfie with a document. The error is
|
||||
//// considered resolved when the file with the selfie changes.
|
||||
//// Represents an issue with the selfie with a document.
|
||||
//
|
||||
/// The error is considered resolved when the file with the selfie changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorselfie).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -104,8 +109,10 @@ pub struct PassportElementErrorSelfie {
|
|||
pub file_hash: String,
|
||||
}
|
||||
|
||||
/// Represents an issue with a document scan. The error is considered
|
||||
/// resolved when the file with the document scan changes.
|
||||
/// Represents an issue with a document scan.
|
||||
///
|
||||
/// The error is considered resolved when the file with the document scan
|
||||
/// changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfile).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -117,8 +124,10 @@ pub struct PassportElementErrorFile {
|
|||
pub file_hash: String,
|
||||
}
|
||||
|
||||
/// Represents an issue with a list of scans. The error is considered
|
||||
/// resolved when the list of files containing the scans changes.
|
||||
/// Represents an issue with a list of scans.
|
||||
///
|
||||
/// The error is considered resolved when the list of files containing the scans
|
||||
/// changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorfiles).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -131,8 +140,9 @@ pub struct PassportElementErrorFiles {
|
|||
}
|
||||
|
||||
/// Represents an issue with one of the files that constitute the
|
||||
/// translation of a document. The error is considered resolved when the
|
||||
/// file changes.
|
||||
/// translation of a document.
|
||||
///
|
||||
/// The error is considered resolved when the file changes.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrortranslationfile).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -145,8 +155,9 @@ pub struct PassportElementErrorTranslationFile {
|
|||
pub file_hash: String,
|
||||
}
|
||||
|
||||
/// Represents an issue with the translated version of a document. The
|
||||
/// error is considered resolved when a file with the document translation
|
||||
/// Represents an issue with the translated version of a document.
|
||||
///
|
||||
/// The error is considered resolved when a file with the document translation
|
||||
/// change.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrortranslationfiles).
|
||||
|
@ -159,8 +170,9 @@ pub struct PassportElementErrorTranslationFiles {
|
|||
pub file_hashes: Vec<String>,
|
||||
}
|
||||
|
||||
/// Represents an issue in an unspecified place. The error is considered
|
||||
/// resolved when new data is added.
|
||||
/// Represents an issue in an unspecified place.
|
||||
///
|
||||
/// The error is considered resolved when new data is added.
|
||||
///
|
||||
/// [The official docs](https://core.telegram.org/bots/api#passportelementerrorunspecified).
|
||||
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/// Constructs a client from the `TELOXIDE_PROXY` environmental variable.
|
||||
///
|
||||
/// This function passes the value of `TELOXIDE_PROXY` into
|
||||
/// [`reqwest::Proxy::all`], if it exists, otherwise returns the default
|
||||
/// client.
|
||||
///
|
||||
/// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all
|
||||
pub fn client_from_env() -> reqwest::Client {
|
||||
use reqwest::{Client, Proxy};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! Some useful utilities.
|
||||
|
||||
pub mod client_from_env;
|
||||
mod client_from_env;
|
||||
pub mod command;
|
||||
pub mod html;
|
||||
pub mod markdown;
|
||||
|
||||
pub use client_from_env::client_from_env;
|
||||
|
|
Loading…
Add table
Reference in a new issue