diff --git a/Cargo.lock b/Cargo.lock index 9d2a812..9a78a5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -165,6 +175,7 @@ dependencies = [ "blocking", "futures-lite", "once_cell", + "tokio", ] [[package]] @@ -271,6 +282,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ + "async-attributes", "async-channel", "async-global-executor", "async-io", @@ -959,6 +971,7 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" name = "gitea-bot" version = "0.1.0" dependencies = [ + "async-std", "dotenvy_macro", "femme", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 31347e1..01f3517 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ teloxide = "0.12.2" teloxide-core = "0.9.1" tide = "0.16.0" tokio = { version = "1.29.1", features = [ "full" ] } +async-std = { version = "1", features = ["attributes", "tokio1"] } diff --git a/src/main.rs b/src/main.rs index 0c65fc4..fcf6350 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,12 +7,10 @@ use gitea::PullWh; use log; use teloxide_core::{prelude::*, types::{Recipient, Chat}}; use teloxide::Bot; -use tide::{Server, Request}; -use tokio::{fs, join, sync::Mutex}; +use tide::{Server, Request, Response}; mod gitea; -const POLL_TIME: &str = dotenvy_macro::dotenv!("POLL_TIME", "Poll time is not set!"); const CHAT_ID: &str = dotenvy_macro::dotenv!("CHAT_ID", "Chat ID is not set!"); const TG_KEY: &str = dotenvy_macro::dotenv!("TG_KEY", "Telegram key is not set!"); const GITEA_URL: &str = dotenvy_macro::dotenv!("GITEA_URL", "Gitea url is not set!"); @@ -33,7 +31,13 @@ async fn start_tg() -> (Bot, Chat) { log::info!("Logged in to telegram as \"{}\"", me.first_name); let chat = bot.get_chat(Recipient::Id(ChatId(CHAT_ID.parse::().unwrap()))).await.unwrap(); - log::info!("Using chat {}", chat.title().unwrap()); + log::info!("Using chat {}", { + if chat.is_group() { + chat.title().unwrap() + } else { + chat.first_name().unwrap() + } + }); (bot, chat) } @@ -49,21 +53,47 @@ async fn start_http(state: SharedState) -> Server { async fn webhook(mut req: Request) -> tide::Result { let body = req.body_string().await.unwrap(); - let serialized = serde_json::from_str::(body.as_str()); + let pr = serde_json::from_str::(body.as_str()); - if serialized.is_err() { - return Ok(format!("Bad serialization: {}", serialized.unwrap_err().to_string()).into()); + if pr.is_err() { + return Ok(format!("Bad serialization: {}", pr.unwrap_err().to_string()).into()); } + let pr = pr.unwrap(); + let secret = req.header("Authorization"); - if secret.is_some() { - // let secret = secret.unwrap().to_string(); - // if ! secret.ends_with(WH_SECRET) - // return Ok(secret.unwrap().as_str().into()); + if secret.is_none() { + return Ok( + Response::builder(401) + // { error: "bad auth" } + .body("{\"error\":\"bad auth\"}") + .content_type("application/json") + .build() + ) + } + let secret = secret.unwrap().get(0).unwrap().to_string(); + + if secret != "Bearer ".to_string() + WH_SECRET { + println!("{} != {}", secret, "Bearer ".to_string() + WH_SECRET); + return Ok( + Response::builder(401) + .body("{\"error\":\"bad auth\"}") + .content_type("application/json") + .build() + ) } - Ok(req.body_string().await.unwrap().into()) - // Ok("()".into()) + let state = req.state().clone(); + + state.bot.send_message(state.chat.id, format!("New PR\n{} ({}#{}) by {}\n{}", pr.pull_request.title, pr.pull_request.head.repo.name, pr.pull_request.number, pr.pull_request.user.login, pr.pull_request.url)).await.unwrap(); + state.bot.send_message(state.chat.id, "апрувните пж @bleki42 @balistiktw @x3paerz").await.unwrap(); + + Ok( + Response::builder(200) + .body("{ \"status\": \"sent\" }") + .content_type("application/json") + .build() + ) } #[tokio::main] @@ -80,31 +110,8 @@ async fn main() { let (bot, chat) = start_tg().await; let http = start_http(SharedState { bot, chat }).await; + log::info!("Listening for webhooks on {}", WH_LISTEN_URL); + http.listen(WH_LISTEN_URL.clone()).await.unwrap(); - let time = POLL_TIME.parse::().unwrap(); - - log::info!("Starting listening for updates ({})", time); - - #[allow(dead_code, unreachable_code)] - loop { - - break; - - let (new_prs, new_data): (Vec, Vec) = (vec![], vec![]); - log::debug!("Found {} new PRs", new_prs.len()); - - if new_prs.len() != 0 { - let prs = new_data; - let data = serde_json::to_string_pretty(&prs).unwrap(); - fs::write(".pr-cache", data).await.unwrap(); - - for pr in new_prs.iter() { - log::info!("Sending message about {} ({})", pr.title, pr.url); - bot.send_message(chat.id, format!("New PR\n{} ({}#{}) by {}\n{}", pr.title, pr.head.repo.name, pr.number, pr.user.login, pr.url)).await.unwrap(); - bot.send_message(chat.id, "апрувните пж @bleki42 @balistiktw @x3paerz").await.unwrap(); - } - } - } - }