Finally fix the error

This commit is contained in:
Temirkhan Myrzamadi 2020-01-29 23:43:47 +06:00
parent 27ae3e13cf
commit 6f2abd10ef
9 changed files with 215 additions and 210 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ Cargo.lock
.idea/
.vscode/
examples/target
examples/ping_pong_bot/target

View file

@ -1,28 +0,0 @@
use teloxide::{
dispatching::{
session::{SessionDispatcher, SessionHandlerCtx, SessionState},
Dispatcher,
},
requests::Request,
types::Message,
Bot,
};
#[tokio::main]
async fn main() {
Dispatcher::<(), (), _, _, ()>::new(&Bot::new(
"1061598315:AAErEDodTsrqD3UxA_EvFyEfXbKA6DT25G0",
))
.private_message_dp(SessionDispatcher::new(
|ctx: SessionHandlerCtx<Message, ()>| async move {
ctx.bot
.send_message(ctx.update.chat.id, "pong")
.send()
.await
.unwrap();
SessionState::Continue(())
},
))
.dispatch()
.await
}

View file

@ -0,0 +1,13 @@
[package]
name = "ping_pong_bot"
version = "0.1.0"
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pretty_env_logger = "0.3.1"
log = "0.4.8"
tokio = "0.2.9"
teloxide = { path = "../../" }

View file

@ -0,0 +1,21 @@
use teloxide::{
dispatching::{Dispatcher, HandlerCtx},
types::Message,
Bot,
};
use std::env;
#[tokio::main]
async fn main() {
env::set_var("RUST_LOG", "ping_pong_bot=trace");
pretty_env_logger::init();
log::info!("Starting the ping-pong bot!");
let bot = Bot::new("1061598315:AAErEDodTsrqD3UxA_EvFyEfXbKA6DT25G0");
Dispatcher::new(bot)
.message_handler(|ctx: HandlerCtx<Message>| ctx.reply("pong"))
.dispatch()
.await;
}

View file

@ -1,82 +1,72 @@
use crate::{
dispatching::{
error_handlers,
session::{SessionDispatcher, SessionHandlerCtx, SessionState},
update_listeners,
update_listeners::UpdateListener,
error_handlers, update_listeners, update_listeners::UpdateListener,
AsyncHandler,
},
requests::{Request, ResponseResult},
types::{
CallbackQuery, ChatKind, ChosenInlineResult, InlineQuery, Message,
Poll, PreCheckoutQuery, ShippingQuery, UpdateKind,
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PreCheckoutQuery, ShippingQuery, UpdateKind,
},
Bot,
};
use futures::StreamExt;
use std::fmt::Debug;
use std::{fmt::Debug, sync::Arc};
pub struct BasicHandlerCtx<'a, Upd> {
pub bot: &'a Bot,
/// A dispatcher's handler's context of a bot and an update.
pub struct HandlerCtx<Upd> {
pub bot: Arc<Bot>,
pub update: Upd,
}
/// The main dispatcher that joins all the parts together.
pub struct Dispatcher<'a, Session1, Session2, H1, H2, HandlerE> {
bot: &'a Bot,
impl HandlerCtx<Message> {
pub fn chat_id(&self) -> i64 {
self.update.chat_id()
}
pub async fn reply<T>(self, text: T) -> ResponseResult<()>
where
T: Into<String>,
{
self.bot
.send_message(self.chat_id(), text)
.send()
.await
.map(|_| ())
}
}
type H<'a, Upd, HandlerE> =
Option<Box<dyn AsyncHandler<HandlerCtx<Upd>, Result<(), HandlerE>> + 'a>>;
/// The main dispatcher to rule them all.
pub struct Dispatcher<'a, HandlerE> {
bot: Arc<Bot>,
handlers_error_handler: Box<dyn AsyncHandler<HandlerE, ()> + 'a>,
private_message_dp: Option<SessionDispatcher<'a, Session1, H1>>,
private_edited_message_dp: Option<SessionDispatcher<'a, Session2, H2>>,
message_handler:
Option<Box<dyn AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a>>,
edited_message_handler:
Option<Box<dyn AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a>>,
channel_post_handler:
Option<Box<dyn AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a>>,
edited_channel_post_handler:
Option<Box<dyn AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a>>,
inline_query_handler: Option<
Box<dyn AsyncHandler<BasicHandlerCtx<'a, InlineQuery>, ()> + 'a>,
>,
chosen_inline_result_handler: Option<
Box<dyn AsyncHandler<BasicHandlerCtx<'a, ChosenInlineResult>, ()> + 'a>,
>,
callback_query_handler: Option<
Box<dyn AsyncHandler<BasicHandlerCtx<'a, CallbackQuery>, ()> + 'a>,
>,
shipping_query_handler: Option<
Box<dyn AsyncHandler<BasicHandlerCtx<'a, ShippingQuery>, ()> + 'a>,
>,
pre_checkout_query_handler: Option<
Box<dyn AsyncHandler<BasicHandlerCtx<'a, PreCheckoutQuery>, ()> + 'a>,
>,
poll_handler:
Option<Box<dyn AsyncHandler<BasicHandlerCtx<'a, Poll>, ()> + 'a>>,
message_handler: H<'a, Message, HandlerE>,
edited_message_handler: H<'a, Message, HandlerE>,
channel_post_handler: H<'a, Message, HandlerE>,
edited_channel_post_handler: H<'a, Message, HandlerE>,
inline_query_handler: H<'a, InlineQuery, HandlerE>,
chosen_inline_result_handler: H<'a, ChosenInlineResult, HandlerE>,
callback_query_handler: H<'a, CallbackQuery, HandlerE>,
shipping_query_handler: H<'a, ShippingQuery, HandlerE>,
pre_checkout_query_handler: H<'a, PreCheckoutQuery, HandlerE>,
poll_handler: H<'a, Poll, HandlerE>,
}
impl<'a, Session1, Session2, H1, H2, HandlerE>
Dispatcher<'a, Session1, Session2, H1, H2, HandlerE>
impl<'a, HandlerE> Dispatcher<'a, HandlerE>
where
Session1: Default + 'a,
Session2: Default + 'a,
H1: AsyncHandler<
SessionHandlerCtx<'a, Message, Session1>,
SessionState<Session1>,
> + 'a,
H2: AsyncHandler<
SessionHandlerCtx<'a, Message, Session2>,
SessionState<Session2>,
> + 'a,
HandlerE: Debug + 'a,
{
pub fn new(bot: &'a Bot) -> Self {
/// Constructs a new dispatcher with this `bot`.
#[must_use]
pub fn new(bot: Bot) -> Self {
Self {
bot,
bot: Arc::new(bot),
handlers_error_handler: Box::new(error_handlers::Log),
private_message_dp: None,
private_edited_message_dp: None,
message_handler: None,
edited_message_handler: None,
channel_post_handler: None,
@ -90,6 +80,7 @@ where
}
}
#[must_use]
pub fn handlers_error_handler<T>(mut self, val: T) -> Self
where
T: AsyncHandler<HandlerE, ()> + 'a,
@ -98,110 +89,109 @@ where
self
}
pub fn private_message_dp(
mut self,
dp: SessionDispatcher<'a, Session1, H1>,
) -> Self {
self.private_message_dp = Some(dp);
self
}
pub fn private_edited_message_dp(
mut self,
dp: SessionDispatcher<'a, Session2, H2>,
) -> Self {
self.private_edited_message_dp = Some(dp);
self
}
#[must_use]
pub fn message_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a,
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.message_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn edited_message_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a,
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.edited_message_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn channel_post_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a,
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.channel_post_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn edited_channel_post_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, Message>, ()> + 'a,
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.edited_channel_post_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn inline_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, InlineQuery>, ()> + 'a,
H: AsyncHandler<HandlerCtx<InlineQuery>, Result<(), HandlerE>> + 'a,
{
self.inline_query_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn chosen_inline_result_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, ChosenInlineResult>, ()> + 'a,
H: AsyncHandler<HandlerCtx<ChosenInlineResult>, Result<(), HandlerE>>
+ 'a,
{
self.chosen_inline_result_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn callback_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, CallbackQuery>, ()> + 'a,
H: AsyncHandler<HandlerCtx<CallbackQuery>, Result<(), HandlerE>> + 'a,
{
self.callback_query_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn shipping_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, ShippingQuery>, ()> + 'a,
H: AsyncHandler<HandlerCtx<ShippingQuery>, Result<(), HandlerE>> + 'a,
{
self.shipping_query_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn pre_checkout_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, PreCheckoutQuery>, ()> + 'a,
H: AsyncHandler<HandlerCtx<PreCheckoutQuery>, Result<(), HandlerE>>
+ 'a,
{
self.pre_checkout_query_handler = Some(Box::new(h));
self
}
#[must_use]
pub fn poll_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<BasicHandlerCtx<'a, Poll>, ()> + 'a,
H: AsyncHandler<HandlerCtx<Poll>, Result<(), HandlerE>> + 'a,
{
self.poll_handler = Some(Box::new(h));
self
}
pub async fn dispatch(&'a mut self) {
/// Starts your bot.
pub async fn dispatch(&'a self) {
self.dispatch_with_listener(
update_listeners::polling_default(self.bot),
update_listeners::polling_default(Arc::clone(&self.bot)),
&error_handlers::Log,
)
.await;
}
/// Starts your bot with custom `update_listener` and
/// `update_listener_error_handler`.
pub async fn dispatch_with_listener<UListener, ListenerE, Eh>(
&'a self,
update_listener: UListener,
@ -224,51 +214,31 @@ where
};
match update.kind {
UpdateKind::Message(message) => match message.chat.kind {
ChatKind::Private { .. } => {
if let Some(private_message_dp) =
&self.private_message_dp
{
private_message_dp
.dispatch(self.bot, message)
.await;
}
}
_ => {
if let Some(message_handler) = &self.message_handler
{
message_handler
.handle(BasicHandlerCtx {
bot: self.bot,
UpdateKind::Message(message) => {
if let Some(message_handler) = &self.message_handler {
if let Err(error) = message_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: message,
})
.await
}
}
},
UpdateKind::EditedMessage(message) => {
match message.chat.kind {
ChatKind::Private { .. } => {
if let Some(private_edited_message_dp) =
&self.private_edited_message_dp
{
private_edited_message_dp
.dispatch(self.bot, message)
.await;
self.handlers_error_handler.handle(error).await;
}
}
_ => {
}
UpdateKind::EditedMessage(message) => {
if let Some(edited_message_handler) =
&self.edited_message_handler
{
edited_message_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = edited_message_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: message,
})
.await
}
{
self.handlers_error_handler.handle(error).await;
}
}
}
@ -276,94 +246,118 @@ where
if let Some(channel_post_handler) =
&self.channel_post_handler
{
channel_post_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = channel_post_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: post,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::EditedChannelPost(post) => {
if let Some(edited_channel_post_handler) =
&self.edited_channel_post_handler
{
edited_channel_post_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = edited_channel_post_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: post,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::InlineQuery(query) => {
if let Some(inline_query_handler) =
&self.inline_query_handler
{
inline_query_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = inline_query_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: query,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::ChosenInlineResult(result) => {
if let Some(chosen_inline_result_handler) =
&self.chosen_inline_result_handler
{
chosen_inline_result_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = chosen_inline_result_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: result,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::CallbackQuery(query) => {
if let Some(callback_query_handler) =
&self.callback_query_handler
{
callback_query_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = callback_query_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: query,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::ShippingQuery(query) => {
if let Some(shipping_query_handler) =
&self.shipping_query_handler
{
shipping_query_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = shipping_query_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: query,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::PreCheckoutQuery(query) => {
if let Some(pre_checkout_query_handler) =
&self.pre_checkout_query_handler
{
pre_checkout_query_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = pre_checkout_query_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: query,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
UpdateKind::Poll(poll) => {
if let Some(poll_handler) = &self.poll_handler {
poll_handler
.handle(BasicHandlerCtx {
bot: self.bot,
if let Err(error) = poll_handler
.handle(HandlerCtx {
bot: Arc::clone(&self.bot),
update: poll,
})
.await;
.await
{
self.handlers_error_handler.handle(error).await;
}
}
}
}

View file

@ -1,4 +1,4 @@
//! Handlers of errors.
//! Commonly used handlers of errors.
use crate::dispatching::AsyncHandler;
use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
@ -9,11 +9,11 @@ use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use teloxide::dispatching::error_handlers::{ErrorHandler, Ignore};
/// use teloxide::dispatching::{error_handlers::Ignore, AsyncHandler};
///
/// Ignore.handle_error(()).await;
/// Ignore.handle_error(404).await;
/// Ignore.handle_error(String::from("error")).await;
/// Ignore.handle(()).await;
/// Ignore.handle(404).await;
/// Ignore.handle(String::from("error")).await;
/// # }
/// ```
pub struct Ignore;
@ -36,15 +36,15 @@ impl<E> AsyncHandler<E, ()> for Ignore {
/// # async fn main_() {
/// use std::convert::{Infallible, TryInto};
///
/// use teloxide::dispatching::error_handlers::{ErrorHandler, IgnoreSafe};
/// use teloxide::dispatching::{AsyncHandler, error_handlers::IgnoreSafe};
///
/// let result: Result<String, Infallible> = "str".try_into();
/// match result {
/// Ok(string) => println!("{}", string),
/// Err(inf) => IgnoreSafe.handle_error(inf).await,
/// Err(inf) => IgnoreSafe.handle(inf).await,
/// }
///
/// IgnoreSafe.handle_error(return;).await; // return type of `return` is `!` (aka never)
/// IgnoreSafe.handle(return).await; // return type of `return` is `!` (aka never)
/// # }
/// ```
///
@ -79,11 +79,11 @@ impl AsyncHandler<Infallible, ()> for IgnoreSafe {
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use teloxide::dispatching::error_handlers::{ErrorHandler, Log};
/// use teloxide::dispatching::{error_handlers::Log, AsyncHandler};
///
/// Log.handle_error(()).await;
/// Log.handle_error(404).await;
/// Log.handle_error(String::from("error")).await;
/// Log.handle(()).await;
/// Log.handle(404).await;
/// Log.handle(String::from("error")).await;
/// # }
/// ```
pub struct Log;

View file

@ -20,11 +20,11 @@
//! 3. If a handler has returned [`SessionState::Terminate`], remove the
//! session from a storage, otherwise force the storage to update the session.
//!
//! [`Storage`]: crate::dispatching::Storage
//! [`SessionDispatcher`]: crate::dispatching::SessionDispatcher
//! [`Storage`]: crate::dispatching::session::Storage
//! [`SessionDispatcher`]: crate::dispatching::session::SessionDispatcher
//! [`dispatch(Bot, Upd)`]:
//! crate::dispatching::SessionDispatcher::dispatch
//! [`SessionState::Terminate`]: crate::dispatching::SessionState::Terminate
//! crate::dispatching::session::SessionDispatcher::dispatch
//! [`SessionState::Terminate`]: crate::dispatching::session::SessionState::Terminate
// TODO: examples
@ -62,7 +62,7 @@ where
/// Creates a dispatcher with the specified `handler` and [`InMemStorage`]
/// (a default storage).
///
/// [`InMemStorage`]: crate::dispatching::InMemStorage
/// [`InMemStorage`]: crate::dispatching::session::InMemStorage
#[must_use]
pub fn new(handler: H) -> Self {
Self {

View file

@ -108,7 +108,7 @@ use crate::{
types::{AllowedUpdate, Update},
RequestError,
};
use std::{convert::TryInto, time::Duration};
use std::{convert::TryInto, sync::Arc, time::Duration};
/// A generic update listener.
pub trait UpdateListener<E>: Stream<Item = Result<Update, E>> {
@ -119,7 +119,7 @@ impl<S, E> UpdateListener<E> for S where S: Stream<Item = Result<Update, E>> {}
/// Returns a long polling update listener with the default configuration.
///
/// See also: [`polling`](polling).
pub fn polling_default(bot: &Bot) -> impl UpdateListener<RequestError> + '_ {
pub fn polling_default(bot: Arc<Bot>) -> impl UpdateListener<RequestError> {
polling(bot, None, None, None)
}
@ -136,11 +136,11 @@ pub fn polling_default(bot: &Bot) -> impl UpdateListener<RequestError> + '_ {
///
/// [`GetUpdates`]: crate::requests::GetUpdates
pub fn polling(
bot: &Bot,
bot: Arc<Bot>,
timeout: Option<Duration>,
limit: Option<u8>,
allowed_updates: Option<Vec<AllowedUpdate>>,
) -> impl UpdateListener<RequestError> + '_ {
) -> impl UpdateListener<RequestError> {
let timeout =
timeout.map(|t| t.as_secs().try_into().expect("timeout is too big"));

View file

@ -356,6 +356,10 @@ mod getters {
}
}
pub fn chat_id(&self) -> i64 {
self.chat.id
}
/// NOTE: this is getter for both `forward_from` and
/// `forward_sender_name`
pub fn forward_from(&self) -> Option<&ForwardedFrom> {
@ -727,21 +731,21 @@ mod getters {
}
}
pub fn migrate_to_chat_id(&self) -> Option<&i64> {
pub fn migrate_to_chat_id(&self) -> Option<i64> {
match &self.kind {
Migrate {
migrate_to_chat_id, ..
} => Some(migrate_to_chat_id),
} => Some(*migrate_to_chat_id),
_ => None,
}
}
pub fn migrate_from_chat_id(&self) -> Option<&i64> {
pub fn migrate_from_chat_id(&self) -> Option<i64> {
match &self.kind {
Migrate {
migrate_from_chat_id,
..
} => Some(migrate_from_chat_id),
} => Some(*migrate_from_chat_id),
_ => None,
}
}