From 757a768bb68dee7c2e01ffc45cc181347213c03a Mon Sep 17 00:00:00 2001 From: JasterV Date: Sat, 28 Aug 2021 15:22:43 +0200 Subject: [PATCH] webhook setup --- Cargo.lock | 303 +++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 7 +- Dockerfile | 13 --- Procfile | 1 + heroku.yml | 7 -- src/main.rs | 17 ++- src/webhook.rs | 71 ++++++++++++ 7 files changed, 377 insertions(+), 42 deletions(-) delete mode 100644 Dockerfile create mode 100644 Procfile delete mode 100644 heroku.yml create mode 100644 src/webhook.rs diff --git a/Cargo.lock b/Cargo.lock index e6c62a7..935efa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,12 +63,37 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + [[package]] name = "bumpalo" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.0.1" @@ -137,6 +162,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-epoch" version = "0.8.2" @@ -221,6 +255,15 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -392,6 +435,27 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -400,7 +464,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -414,12 +478,16 @@ dependencies = [ "lazy_static", "log", "pretty_env_logger", - "rand", + "rand 0.8.4", + "reqwest", "serde", + "serde_json", "teloxide", "thiserror", "tokio", + "tokio-stream", "url", + "warp", ] [[package]] @@ -447,6 +515,31 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "headers" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" +dependencies = [ + "base64", + "bitflags", + "bytes", + "headers-core", + "http", + "mime", + "sha-1", + "time", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -563,6 +656,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "input_buffer" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" +dependencies = [ + "bytes", +] + [[package]] name = "ipnet" version = "2.3.1" @@ -679,6 +781,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "multipart" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" +dependencies = [ + "buf_redux", + "httparse", + "log", + "mime", + "mime_guess", + "quick-error", + "rand 0.7.3", + "safemem", + "tempfile", + "twoway", +] + [[package]] name = "native-tls" version = "0.2.8" @@ -747,6 +867,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.36" @@ -909,6 +1035,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + [[package]] name = "rand" version = "0.8.4" @@ -916,9 +1055,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -928,7 +1077,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -937,7 +1095,16 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom", + "getrandom 0.2.3", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -946,7 +1113,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core", + "rand_core 0.6.3", ] [[package]] @@ -1041,6 +1208,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "schannel" version = "0.1.19" @@ -1051,6 +1224,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + [[package]] name = "scopeguard" version = "1.1.0" @@ -1153,6 +1332,19 @@ dependencies = [ "syn", ] +[[package]] +name = "sha-1" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1272,7 +1464,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand", + "rand 0.8.4", "redox_syscall 0.2.10", "remove_dir_all", "winapi", @@ -1314,7 +1506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -1384,6 +1576,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b" +dependencies = [ + "futures-util", + "log", + "pin-project", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.6.7" @@ -1411,6 +1616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ "cfg-if 1.0.0", + "log", "pin-project-lite", "tracing-core", ] @@ -1430,6 +1636,40 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +[[package]] +name = "tungstenite" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "input_buffer", + "log", + "rand 0.8.4", + "sha-1", + "url", + "utf-8", +] + +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + [[package]] name = "ucd-trie" version = "0.1.3" @@ -1479,13 +1719,19 @@ dependencies = [ "serde", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom", + "getrandom 0.2.3", ] [[package]] @@ -1510,6 +1756,41 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multipart", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 89b35e9..a324b23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,9 @@ rand = "0.8.4" async-trait = "0.1.51" lazy_static = "1.4.0" dashmap = "4.0.2" -url = "2.2.2" \ No newline at end of file +url = "2.2.2" +tokio-stream = "0.1.4" +# Used to setup a webhook +warp = "0.3.0" +reqwest = "0.11.4" +serde_json = "1.0.50" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index fb1c36a..0000000 --- a/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.54.0 as build - -WORKDIR /app -COPY . . -RUN cargo build --release -RUN mkdir -p /build-out -RUN cp target/release/gofish /build-out/ - -# Ubuntu 18.04 -FROM ubuntu:18.04 as production - -RUN apt-get update && apt-get -y install ca-certificates libssl-dev && rm -rf /var/lib/apt/lists/* -COPY --from=build /build-out/* / \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..628a517 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: ./target/release/gofish diff --git a/heroku.yml b/heroku.yml deleted file mode 100644 index 22d0c6a..0000000 --- a/heroku.yml +++ /dev/null @@ -1,7 +0,0 @@ -build: - docker: - web: - dockerfile: Dockerfile - target: production -run: - web: ./gofish \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 84a297a..f8ca641 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod command; mod entities; mod errors; mod templates; +mod webhook; use crate::actors::run_async_actor; use actors::game::{ @@ -18,10 +19,10 @@ use anyhow::Result; use command::Command; use dashmap::DashMap; use dotenv; -use std::{str::FromStr, sync::Arc}; +use std::sync::Arc; use teloxide::{prelude::*, types::Me, utils::command::BotCommand}; use tokio::sync::{mpsc::Sender, oneshot}; -use url::Url; +use webhook::webhook; lazy_static! { static ref SENDERS: Arc>> = Arc::new(DashMap::new()); @@ -29,23 +30,19 @@ lazy_static! { #[tokio::main] async fn main() { - dotenv::dotenv().ok(); - teloxide::enable_logging!(); run().await; } async fn run() { + dotenv::dotenv().ok(); + teloxide::enable_logging!(); log::info!("Starting bot..."); - let webhook_url = std::env::var("WEBHOOK_URL").expect("WEBHOOK_URL not found"); let bot = Bot::from_env().auto_send(); let Me { user: bot_user, .. } = bot.get_me().await.unwrap(); let bot_name = bot_user.username.expect("Bots must have usernames"); - bot.set_webhook(Url::from_str(&webhook_url).expect("Invalid webhook url")) - .send() - .await - .unwrap(); log::info!("listening..."); - teloxide::commands_repl(bot, bot_name, execute).await; + let cloned_bot = bot.clone(); + teloxide::commands_repl_with_listener(bot, bot_name, execute, webhook(cloned_bot).await).await } async fn execute(cx: Cx, command: Command) -> Result<()> { diff --git a/src/webhook.rs b/src/webhook.rs new file mode 100644 index 0000000..82c042c --- /dev/null +++ b/src/webhook.rs @@ -0,0 +1,71 @@ +use reqwest::{StatusCode, Url}; +use std::{convert::Infallible, env, net::SocketAddr}; +use teloxide::{ + dispatching::{ + stop_token::AsyncStopToken, + update_listeners::{self, StatefulListener}, + }, + prelude::*, + types::Update, +}; +use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; +use warp::Filter; + +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 |json: serde_json::Value| { + if let Ok(update) = Update::try_parse(&json) { + 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(), + ) +}