diff --git a/Cargo.toml b/Cargo.toml index 9470edf5..7f4a5158 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,9 +25,6 @@ maintenance = { status = "actively-developed" } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[features] -webhooks = ["warp"] - [dependencies] serde_json = "1.0.44" serde = { version = "1.0.101", features = ["derive"] } @@ -47,12 +44,9 @@ async-trait = "0.1.22" futures = "0.3.1" pin-project = "0.4.6" serde_with_macros = "1.0.1" -either = "1.5.3" teloxide-macros = "0.2.1" -warp = { version = "0.2.2", features = ["tls"], optional = true } - [dev-dependencies] smart-default = "0.6.0" rand = "0.7.3" diff --git a/examples/webhook_ping_pong_bot/Cargo.toml b/examples/webhook_ping_pong_bot/Cargo.toml new file mode 100644 index 00000000..c78df1ff --- /dev/null +++ b/examples/webhook_ping_pong_bot/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "webhook_ping_pong_bot" +version = "0.1.0" +authors = ["Temirkhan Myrzamadi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4.8" +futures = "0.3.4" +tokio = "0.2.9" +pretty_env_logger = "0.4.0" + +teloxide = { path = "../../" } + +# Used to setup a webhook +warp = "0.2.2" diff --git a/examples/webhook_ping_pong_bot/src/main.rs b/examples/webhook_ping_pong_bot/src/main.rs new file mode 100644 index 00000000..2bb74d51 --- /dev/null +++ b/examples/webhook_ping_pong_bot/src/main.rs @@ -0,0 +1,85 @@ +// The version of ping-pong-bot, which uses a webhook to receive updates from +// Telegram, instead of long polling. + +use teloxide::{dispatching::update_listeners, prelude::*}; + +use std::{convert::Infallible, net::SocketAddr, sync::Arc}; +use tokio::sync::mpsc; +use warp::Filter; + +use reqwest::StatusCode; + +#[tokio::main] +async fn main() { + run().await; +} + +async fn handle_rejection( + error: warp::Rejection, +) -> Result { + log::error!("Cannot process the request due to: {:?}", error); + Ok(StatusCode::INTERNAL_SERVER_ERROR) +} + +pub async fn webhook<'a>( + bot: Arc, +) -> impl update_listeners::UpdateListener { + // You might want to specify a self-signed certificate via .certificate + // method on SetWebhook. + bot.set_webhook("Your HTTPS ngrok URL here. Get it by 'ngrok http 80'") + .send() + .await + .expect("Cannot setup a webhook"); + + let (tx, rx) = mpsc::unbounded_channel(); + + let server = warp::post() + .and(warp::body::json()) + .map(move |json: serde_json::Value| { + match serde_json::from_str::(&json.to_string()) { + Ok(update) => tx + .send(Ok(update)) + .expect("Cannot send an incoming update from the webhook"), + Err(error) => { + // In this case, please report a bug at https://github.com/teloxide/teloxide/issues !!! + log::error!( + "Cannot parse Update: {}\nError: {}", + json, + error + ); + } + } + + StatusCode::OK + }) + .recover(handle_rejection); + + let serve = warp::serve(server); + + // You might want to use serve.key_path/serve.cert_path methods here to + // setup a self-signed TLS certificate. + + tokio::spawn(serve.run("127.0.0.1:80".parse::().unwrap())); + rx +} + +async fn run() { + teloxide::enable_logging!(); + log::info!("Starting ping_pong_bot!"); + + let bot = Bot::from_env(); + + Dispatcher::new(Arc::clone(&bot)) + .messages_handler(|rx: DispatcherHandlerRx| { + rx.for_each(|message| async move { + message.answer("pong").send().await.log_on_error().await; + }) + }) + .dispatch_with_listener( + webhook(bot).await, + LoggingErrorHandler::with_custom_text( + "An error from the update listener", + ), + ) + .await; +} diff --git a/src/dispatching/update_listeners.rs b/src/dispatching/update_listeners.rs index 77d8c126..6e11ed4a 100644 --- a/src/dispatching/update_listeners.rs +++ b/src/dispatching/update_listeners.rs @@ -198,46 +198,3 @@ pub fn polling( ) .flatten() } - -#[cfg(feature = "webhooks")] -pub async fn webhook( - url: reqwest::Url, - addr: std::net::SocketAddr, - key: either::Either, - cert: either::Either, -) -> crate::prelude::ResponseResult> -where - KP: AsRef, - KB: AsRef<[u8]>, - CP: AsRef, - CB: AsRef<[u8]>, -{ - use either::Either; - use tokio::sync::mpsc; - use warp::Filter; - - let (tx, rx) = mpsc::unbounded_channel(); - - let server = warp::post().and(warp::path(url)).and(warp::body::json()).map( - move |update: Update| { - tx.send(Ok(update)).expect("Cannot send an update from webhook"); - "" - }, - ); - - let serve = warp::serve(server).tls(); - - let serve = match key { - Either::Left(path) => serve.key_path(path), - Either::Right(bytes) => serve.key(bytes), - }; - - let serve = match cert { - Either::Left(path) => serve.cert_path(path), - Either::Right(bytes) => serve.cert(bytes), - }; - - tokio::spawn(serve.run(addr)); - - Ok(rx) -}