mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-23 06:51:01 +01:00
commit
ce2e949cb1
4 changed files with 152 additions and 44 deletions
|
@ -22,3 +22,4 @@ thiserror = "1.0.2"
|
|||
default = []
|
||||
|
||||
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?
|
||||
pub enum ErrorPolicy<'a, E> {
|
||||
Ignore,
|
||||
Log,
|
||||
Custom(Box<dyn Fn(E) -> Pin<Box<dyn Future<Output = ()> + 'a>>>),
|
||||
}
|
||||
use async_trait::async_trait;
|
||||
|
||||
impl<'a, E> ErrorPolicy<'a, E>
|
||||
where
|
||||
E: Debug,
|
||||
{
|
||||
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
|
||||
/// Implementors of this trait are treated as error-handlers.
|
||||
#[async_trait]
|
||||
pub trait ErrorPolicy<E> {
|
||||
async fn handle_error(&self, error: E)
|
||||
where
|
||||
F: Fn(E) -> Fut + 'static,
|
||||
Fut: Future<Output = ()> + 'a,
|
||||
E: 'async_trait;
|
||||
}
|
||||
|
||||
/// 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:
|
||||
/// ```no_run
|
||||
/// # use telebofr::Bot;
|
||||
/// use telebofr::types::Message;
|
||||
/// async fn run() {
|
||||
/// # async fn run() {
|
||||
/// use std::convert::Infallible;
|
||||
///
|
||||
/// use telebofr::{
|
||||
/// Bot,
|
||||
/// types::Message,
|
||||
/// dispatching::{
|
||||
/// dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher},
|
||||
/// updater::polling,
|
||||
|
@ -51,7 +52,7 @@ type Handlers<'a, T, E> =
|
|||
///
|
||||
/// // create dispatching which handlers can't fail
|
||||
/// // 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
|
||||
/// .message_handler(true, |mes: Message| {
|
||||
/// async move { println!("New message: {:?}", mes) }
|
||||
|
@ -66,10 +67,9 @@ type Handlers<'a, T, E> =
|
|||
/// ```
|
||||
///
|
||||
/// [`std::fmt::Debug`]: std::fmt::Debug
|
||||
/// [Custom error policy]:
|
||||
/// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]:
|
||||
/// crate::dispatching::updater
|
||||
pub struct FilterDispatcher<'a, E> {
|
||||
/// [Custom error policy]: crate::dispatching::filter::error_policy::ErrorPolicy::Custom
|
||||
/// [updater]: crate::dispatching::updater
|
||||
pub struct FilterDispatcher<'a, E, Ep> {
|
||||
message_handlers: Handlers<'a, Message, E>,
|
||||
edited_message_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>,
|
||||
chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, 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
|
||||
Ep: ErrorPolicy<E>,
|
||||
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 {
|
||||
message_handlers: Vec::new(),
|
||||
edited_message_handlers: Vec::new(),
|
||||
|
@ -183,7 +184,6 @@ where
|
|||
updates
|
||||
.for_each(|res| {
|
||||
async {
|
||||
let res = res;
|
||||
let Update { kind, id } = match res {
|
||||
Ok(upd) => upd,
|
||||
_ => return, // TODO: proper error handling
|
||||
|
@ -265,10 +265,11 @@ where
|
|||
}
|
||||
|
||||
#[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
|
||||
E: std::fmt::Debug,
|
||||
U: Updater + 'a,
|
||||
Ep: ErrorPolicy<E>,
|
||||
{
|
||||
async fn dispatch(&'a mut self, updater: U) {
|
||||
FilterDispatcher::dispatch(self, updater).await
|
||||
|
@ -286,9 +287,7 @@ mod tests {
|
|||
|
||||
use crate::{
|
||||
dispatching::{
|
||||
dispatchers::filter::{
|
||||
error_policy::ErrorPolicy, FilterDispatcher,
|
||||
},
|
||||
dispatchers::filter::FilterDispatcher,
|
||||
updater::StreamUpdater,
|
||||
},
|
||||
types::{
|
||||
|
@ -302,7 +301,7 @@ mod tests {
|
|||
let counter = &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| {
|
||||
async move {
|
||||
counter.fetch_add(1, Ordering::SeqCst);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg_attr(feature = "never-type", feature(never_type))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
#[macro_use]
|
||||
|
|
Loading…
Reference in a new issue