From b8004a803ac7d063d95f4209ac63f5cd83a84f69 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 9 Jun 2022 18:00:15 +0400 Subject: [PATCH] use built-in webhook support in heroku example Former-commit-id: 0b582882eb3bf9cd14a268cd8c7a3623a1ca7cf9 --- Cargo.toml | 5 +- examples/heroku_ping_pong.rs | 94 +++++++++--------------------------- 2 files changed, 27 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2fc06eb3..94be4d36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,6 @@ once_cell = "1.9.0" serde = "1" serde_json = "1" tokio = { version = "1.8", features = ["fs", "rt-multi-thread", "macros"] } -warp = "0.3.0" reqwest = "0.10.4" chrono = "0.4" tokio-stream = "0.1" @@ -153,6 +152,10 @@ required-features = ["macros"] name = "ngrok_ping_pong" required-features = ["webhooks-axum"] +[[example]] +name = "heroku_ping_pong" +required-features = ["webhooks-axum"] + [[example]] name = "purchase" required-features = ["macros"] diff --git a/examples/heroku_ping_pong.rs b/examples/heroku_ping_pong.rs index 6374ed78..72ff8034 100644 --- a/examples/heroku_ping_pong.rs +++ b/examples/heroku_ping_pong.rs @@ -16,25 +16,12 @@ // heroku buildpacks:set emk/rust // ``` // -// [1] https://github.com/emk/heroku-buildpack-rust +// [1]: https://github.com/emk/heroku-buildpack-rust -// TODO: use built-in webhook support +use std::env; -use teloxide::{ - dispatching::{ - stop_token::AsyncStopToken, - update_listeners::{self, StatefulListener}, - }, - prelude::*, - types::Update, -}; - -use std::{convert::Infallible, env, net::SocketAddr}; -use tokio::sync::mpsc; -use tokio_stream::wrappers::UnboundedReceiverStream; -use warp::Filter; - -use reqwest::{StatusCode, Url}; +use teloxide::{dispatching::update_listeners::webhooks, prelude::*}; +use url::Url; #[tokio::main] async fn main() { @@ -42,66 +29,31 @@ async fn main() { log::info!("Starting Heroku ping-pong bot..."); let bot = Bot::from_env().auto_send(); + let token = bot.inner().token(); + + // Heroku auto defines a port value + let port: u16 = env::var("PORT") + .expect("PORT env variable is not set") + .parse() + .expect("PORT env variable value is not an integer"); + + let addr = ([127, 0, 0, 1], port).into(); + + // Heroku host example: "heroku-ping-pong-bot.herokuapp.com" + let host = env::var("HOST").expect("HOST env variable is not set"); + let url = Url::parse(&format!("https://{host}/webhooks/{token}")).unwrap(); + + let listener = webhooks::axum(bot.clone(), webhooks::Options::new(addr, url)) + .await + .expect("Couldn't setup webhook"); teloxide::repl_with_listener( - bot.clone(), + bot, |msg: Message, bot: AutoSend| async move { bot.send_message(msg.chat.id, "pong").await?; respond(()) }, - webhook(bot).await, + listener, ) .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(bot: AutoSend) -> impl update_listeners::UpdateListener { - // Heroku auto defines a port value - let teloxide_token = env::var("TELOXIDE_TOKEN").expect("TELOXIDE_TOKEN env variable missing"); - let port: u16 = env::var("PORT") - .expect("PORT env variable missing") - .parse() - .expect("PORT value to be integer"); - // Heroku host example .: "heroku-ping-pong-bot.herokuapp.com" - let host = env::var("HOST").expect("have HOST env variable"); - let path = format!("bot{teloxide_token}"); - let url = Url::parse(&format!("https://{host}/{path}")).unwrap(); - - bot.set_webhook(url).await.expect("Cannot setup a webhook"); - - let (tx, rx) = mpsc::unbounded_channel(); - - let server = warp::post() - .and(warp::path(path)) - .and(warp::body::json()) - .map(move |update: Update| { - tx.send(Ok(update)).expect("Cannot send an incoming update from the webhook"); - - StatusCode::OK - }) - .recover(handle_rejection); - - let (stop_token, stop_flag) = AsyncStopToken::new_pair(); - - let addr = format!("0.0.0.0:{port}").parse::().unwrap(); - let server = warp::serve(server); - let (_addr, fut) = server.bind_with_graceful_shutdown(addr, stop_flag); - - // You might want to use serve.key_path/serve.cert_path methods here to - // setup a self-signed TLS certificate. - - tokio::spawn(fut); - let stream = UnboundedReceiverStream::new(rx); - - fn streamf(state: &mut (S, T)) -> &mut S { - &mut state.0 - } - - StatefulListener::new((stream, stop_token), streamf, |state: &mut (_, AsyncStopToken)| { - state.1.clone() - }) -}