mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-11 04:21:12 +01:00
commit
ce2e949cb1
4 changed files with 152 additions and 44 deletions
|
@ -22,3 +22,4 @@ thiserror = "1.0.2"
|
||||||
default = []
|
default = []
|
||||||
|
|
||||||
unstable-stream = [] # add streams to public API
|
unstable-stream = [] # add streams to public API
|
||||||
|
never-type = [] # add never type (`!`) to punlic API
|
||||||
|
|
|
@ -1,32 +1,138 @@
|
||||||
use std::{fmt::Debug, future::Future, pin::Pin};
|
use std::{
|
||||||
|
pin::Pin,
|
||||||
|
future::Future,
|
||||||
|
convert::Infallible,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: shouldn't it be trait?
|
use async_trait::async_trait;
|
||||||
pub enum ErrorPolicy<'a, E> {
|
|
||||||
Ignore,
|
|
||||||
Log,
|
|
||||||
Custom(Box<dyn Fn(E) -> Pin<Box<dyn Future<Output = ()> + 'a>>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E> ErrorPolicy<'a, E>
|
/// Implementors of this trait are treated as error-handlers.
|
||||||
where
|
#[async_trait]
|
||||||
E: Debug,
|
pub trait ErrorPolicy<E> {
|
||||||
{
|
async fn handle_error(&self, error: E)
|
||||||
pub async fn handle_error(&self, error: E) {
|
|
||||||
match self {
|
|
||||||
Self::Ignore => {}
|
|
||||||
Self::Log => {
|
|
||||||
// TODO: better message
|
|
||||||
log::error!("Error in handler: {:?}", error)
|
|
||||||
}
|
|
||||||
Self::Custom(func) => func(error).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn custom<F, Fut>(f: F) -> Self
|
|
||||||
where
|
where
|
||||||
F: Fn(E) -> Fut + 'static,
|
E: 'async_trait;
|
||||||
Fut: Future<Output = ()> + 'a,
|
}
|
||||||
|
|
||||||
|
/// Error policy that silently ignores all errors
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() {
|
||||||
|
/// use telebofr::dispatching::dispatchers::filter::error_policy::{
|
||||||
|
/// ErrorPolicy,
|
||||||
|
/// Ignore,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// Ignore.handle_error(()).await;
|
||||||
|
/// Ignore.handle_error(404).await;
|
||||||
|
/// Ignore.handle_error(String::from("error")).await;
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub struct Ignore;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<E> ErrorPolicy<E> for Ignore
|
||||||
|
where
|
||||||
|
E: Send,
|
||||||
|
{
|
||||||
|
async fn handle_error(&self, _: E)
|
||||||
|
where
|
||||||
|
E: 'async_trait
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error policy that silently ignores all errors that can never happen (e.g.: [`!`] or [`Infallible`])
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
/// ```
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() {
|
||||||
|
/// use std::convert::{TryInto, Infallible};
|
||||||
|
///
|
||||||
|
/// use telebofr::dispatching::dispatchers::filter::error_policy::{
|
||||||
|
/// ErrorPolicy,
|
||||||
|
/// IgnoreSafe,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let result: Result<String, Infallible> = "str".try_into();
|
||||||
|
/// match result {
|
||||||
|
/// Ok(string) => println!("{}", string),
|
||||||
|
/// Err(inf) => IgnoreSafe.handle_error(inf).await,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// IgnoreSafe.handle_error(return).await; // return type of `return` is `!` (aka never)
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```compile_fail
|
||||||
|
/// use telebofr::dispatching::dispatchers::filter::error_policy::{
|
||||||
|
/// ErrorPolicy,
|
||||||
|
/// IgnoreSafe,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// IgnoreSafe.handle_error(0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Note
|
||||||
|
/// Never type is not stabilized yet (see [`#35121`]) so all API that uses [`!`]
|
||||||
|
/// (including `impl ErrorPolicy<!> for IgnoreSafe`) we hide under the
|
||||||
|
/// `never-type` cargo feature.
|
||||||
|
///
|
||||||
|
/// [`!`]: https://doc.rust-lang.org/std/primitive.never.html
|
||||||
|
/// [`Infallible`]: std::convert::Infallible
|
||||||
|
/// [`#35121`]: https://github.com/rust-lang/rust/issues/35121
|
||||||
|
pub struct IgnoreSafe;
|
||||||
|
|
||||||
|
#[cfg(feature = "never-type")]
|
||||||
|
#[async_trait]
|
||||||
|
impl ErrorPolicy<!> for IgnoreSafe {
|
||||||
|
async fn handle_error(&self, never: !)
|
||||||
|
where
|
||||||
|
!: 'async_trait
|
||||||
{
|
{
|
||||||
Self::Custom(Box::new(move |e| Box::pin(f(e))))
|
never
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ErrorPolicy<Infallible> for IgnoreSafe {
|
||||||
|
async fn handle_error(&self, inf: Infallible)
|
||||||
|
where
|
||||||
|
Infallible: 'async_trait
|
||||||
|
{
|
||||||
|
match inf {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of `ErrorPolicy` for `async fn`s
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// # #[tokio::main]
|
||||||
|
/// # async fn main() {
|
||||||
|
/// use telebofr::dispatching::dispatchers::filter::error_policy::ErrorPolicy;
|
||||||
|
///
|
||||||
|
/// let closure = |e: i32| async move {
|
||||||
|
/// eprintln!("Error code{}", e)
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// closure.handle_error(404).await;
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
impl<E, F, Fut> ErrorPolicy<E> for F
|
||||||
|
where
|
||||||
|
F: Fn(E) -> Fut + Sync,
|
||||||
|
Fut: Future<Output = ()> + Send,
|
||||||
|
E: Send,
|
||||||
|
{
|
||||||
|
fn handle_error<'s, 'async_trait>(&'s self, error: E) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
|
||||||
|
where
|
||||||
|
's: 'async_trait,
|
||||||
|
Self: 'async_trait,
|
||||||
|
E: 'async_trait
|
||||||
|
{
|
||||||
|
Box::pin(async move { self(error).await })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,11 +32,12 @@ type Handlers<'a, T, E> =
|
||||||
///
|
///
|
||||||
/// Simplest example:
|
/// Simplest example:
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use telebofr::Bot;
|
/// # async fn run() {
|
||||||
/// use telebofr::types::Message;
|
|
||||||
/// async fn run() {
|
|
||||||
/// use std::convert::Infallible;
|
/// use std::convert::Infallible;
|
||||||
|
///
|
||||||
/// use telebofr::{
|
/// use telebofr::{
|
||||||
|
/// Bot,
|
||||||
|
/// types::Message,
|
||||||
/// dispatching::{
|
/// dispatching::{
|
||||||
/// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher},
|
/// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher},
|
||||||
/// updater::polling,
|
/// updater::polling,
|
||||||
|
@ -51,7 +52,7 @@ type Handlers<'a, T, E> =
|
||||||
///
|
///
|
||||||
/// // create dispatching which handlers can't fail
|
/// // create dispatching which handlers can't fail
|
||||||
/// // with error policy that just ignores all errors (that can't ever happen)
|
/// // with error policy that just ignores all errors (that can't ever happen)
|
||||||
/// let mut dp = FilterDispatcher::<Infallible>::new(ErrorPolicy::Ignore)
|
/// let mut dp = FilterDispatcher::<Infallible, _>::new(|_| async { () })
|
||||||
/// // Add 'handler' that will handle all messages sent to the bot
|
/// // Add 'handler' that will handle all messages sent to the bot
|
||||||
/// .message_handler(true, |mes: Message| {
|
/// .message_handler(true, |mes: Message| {
|
||||||
/// async move { println!("New message: {:?}", mes) }
|
/// async move { println!("New message: {:?}", mes) }
|
||||||
|
@ -66,10 +67,9 @@ type Handlers<'a, T, E> =
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`std::fmt::Debug`]: std::fmt::Debug
|
/// [`std::fmt::Debug`]: std::fmt::Debug
|
||||||
/// [Custom error policy]:
|
/// [Custom error policy]: crate::dispatching::filter::error_policy::ErrorPolicy::Custom
|
||||||
/// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]:
|
/// [updater]: crate::dispatching::updater
|
||||||
/// crate::dispatching::updater
|
pub struct FilterDispatcher<'a, E, Ep> {
|
||||||
pub struct FilterDispatcher<'a, E> {
|
|
||||||
message_handlers: Handlers<'a, Message, E>,
|
message_handlers: Handlers<'a, Message, E>,
|
||||||
edited_message_handlers: Handlers<'a, Message, E>,
|
edited_message_handlers: Handlers<'a, Message, E>,
|
||||||
channel_post_handlers: Handlers<'a, Message, E>,
|
channel_post_handlers: Handlers<'a, Message, E>,
|
||||||
|
@ -77,14 +77,15 @@ pub struct FilterDispatcher<'a, E> {
|
||||||
inline_query_handlers: Handlers<'a, (), E>,
|
inline_query_handlers: Handlers<'a, (), E>,
|
||||||
chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, E>,
|
chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, E>,
|
||||||
callback_query_handlers: Handlers<'a, CallbackQuery, E>,
|
callback_query_handlers: Handlers<'a, CallbackQuery, E>,
|
||||||
error_policy: ErrorPolicy<'a, E>,
|
error_policy: Ep,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E> FilterDispatcher<'a, E>
|
impl<'a, E, Ep> FilterDispatcher<'a, E, Ep>
|
||||||
where
|
where
|
||||||
|
Ep: ErrorPolicy<E>,
|
||||||
E: std::fmt::Debug, // TODO: Is this really necessary?
|
E: std::fmt::Debug, // TODO: Is this really necessary?
|
||||||
{
|
{
|
||||||
pub fn new(error_policy: ErrorPolicy<'a, E>) -> Self {
|
pub fn new(error_policy: Ep) -> Self {
|
||||||
FilterDispatcher {
|
FilterDispatcher {
|
||||||
message_handlers: Vec::new(),
|
message_handlers: Vec::new(),
|
||||||
edited_message_handlers: Vec::new(),
|
edited_message_handlers: Vec::new(),
|
||||||
|
@ -183,7 +184,6 @@ where
|
||||||
updates
|
updates
|
||||||
.for_each(|res| {
|
.for_each(|res| {
|
||||||
async {
|
async {
|
||||||
let res = res;
|
|
||||||
let Update { kind, id } = match res {
|
let Update { kind, id } = match res {
|
||||||
Ok(upd) => upd,
|
Ok(upd) => upd,
|
||||||
_ => return, // TODO: proper error handling
|
_ => return, // TODO: proper error handling
|
||||||
|
@ -265,10 +265,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(? Send)]
|
#[async_trait(? Send)]
|
||||||
impl<'a, U, E> Dispatcher<'a, U> for FilterDispatcher<'a, E>
|
impl<'a, U, E, Ep> Dispatcher<'a, U> for FilterDispatcher<'a, E, Ep>
|
||||||
where
|
where
|
||||||
E: std::fmt::Debug,
|
E: std::fmt::Debug,
|
||||||
U: Updater + 'a,
|
U: Updater + 'a,
|
||||||
|
Ep: ErrorPolicy<E>,
|
||||||
{
|
{
|
||||||
async fn dispatch(&'a mut self, updater: U) {
|
async fn dispatch(&'a mut self, updater: U) {
|
||||||
FilterDispatcher::dispatch(self, updater).await
|
FilterDispatcher::dispatch(self, updater).await
|
||||||
|
@ -286,9 +287,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dispatching::{
|
dispatching::{
|
||||||
dispatchers::filter::{
|
dispatchers::filter::FilterDispatcher,
|
||||||
error_policy::ErrorPolicy, FilterDispatcher,
|
|
||||||
},
|
|
||||||
updater::StreamUpdater,
|
updater::StreamUpdater,
|
||||||
},
|
},
|
||||||
types::{
|
types::{
|
||||||
|
@ -302,7 +301,7 @@ mod tests {
|
||||||
let counter = &AtomicI32::new(0);
|
let counter = &AtomicI32::new(0);
|
||||||
let counter2 = &AtomicI32::new(0);
|
let counter2 = &AtomicI32::new(0);
|
||||||
|
|
||||||
let mut dp = FilterDispatcher::<Infallible>::new(ErrorPolicy::Ignore)
|
let mut dp = FilterDispatcher::<Infallible, _>::new(|_| async { () } )
|
||||||
.message_handler(true, |_mes: Message| {
|
.message_handler(true, |_mes: Message| {
|
||||||
async move {
|
async move {
|
||||||
counter.fetch_add(1, Ordering::SeqCst);
|
counter.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![cfg_attr(feature = "never-type", feature(never_type))]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate derive_more;
|
extern crate derive_more;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
Loading…
Reference in a new issue