basic tide webhook

This commit is contained in:
b1ek 2023-08-05 14:23:24 +10:00
parent 04f662fefc
commit fc1577c238
Signed by: blek
GPG Key ID: 14546221E3595D0C
5 changed files with 1188 additions and 69 deletions

1138
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,12 @@ edition = "2021"
[dependencies] [dependencies]
dotenvy_macro = "0.15.7" dotenvy_macro = "0.15.7"
femme = "2.2.1" femme = "2.2.1"
lazy_static = "1.4.0"
log = "0.4.19" log = "0.4.19"
reqwest = "0.11.18" reqwest = "0.11.18"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.104" serde_json = "1.0.104"
teloxide = "0.12.2" teloxide = "0.12.2"
teloxide-core = "0.9.1" teloxide-core = "0.9.1"
tide = "0.16.0"
tokio = { version = "1.29.1", features = [ "full" ] } tokio = { version = "1.29.1", features = [ "full" ] }

View File

@ -1,11 +1,5 @@
use crate::{GITEA_KEY, gitea::{User, Repo, Pull}}; use crate::gitea::{User, Repo, Pull};
macro_rules! gitea_api {
($path: expr) => {
format!("{}{}?token={}", dotenvy_macro::dotenv!("GITEA_URL", "Gitea url is not set!"), $path, GITEA_KEY)
};
}
pub async fn get_user() -> User { pub async fn get_user() -> User {
let user = reqwest::get(gitea_api!("/api/v1/user")).await.unwrap(); let user = reqwest::get(gitea_api!("/api/v1/user")).await.unwrap();

View File

@ -40,4 +40,13 @@ pub struct Pull {
pub head: Branch, pub head: Branch,
pub merge_base: String, pub merge_base: String,
pub user: User pub user: User
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PullWh {
pub action: String,
pub number: i64,
pub sender: User,
pub repository: Repo,
pub pull_request: Pull
} }

View File

@ -1,21 +1,71 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![feature(new_uninit)]
use std::{path::Path, thread, time::Duration}; use std::mem::MaybeUninit;
use gitea::PullWh;
use log; use log;
use teloxide_core::{prelude::*, types::Recipient}; use teloxide_core::{prelude::*, types::{Recipient, Chat}};
use teloxide::Bot; use teloxide::Bot;
use tokio::fs; use tide::{Server, Request};
use tokio::{fs, join, sync::Mutex};
mod gitea; mod gitea;
mod api;
const POLL_TIME: &str = dotenvy_macro::dotenv!("POLL_TIME", "Poll time is not set!"); 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 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 TG_KEY: &str = dotenvy_macro::dotenv!("TG_KEY", "Telegram key is not set!");
const GITEA_KEY: &str = dotenvy_macro::dotenv!("GITEA_KEY", "Gitea key is not set!");
const GITEA_URL: &str = dotenvy_macro::dotenv!("GITEA_URL", "Gitea url is not set!"); const GITEA_URL: &str = dotenvy_macro::dotenv!("GITEA_URL", "Gitea url is not set!");
const WH_SECRET: &str = dotenvy_macro::dotenv!("WH_SECRET", "Webhook secret is not set!");
const WH_LISTEN_URL: &str = dotenvy_macro::dotenv!("WH_URL", "Webhook listen URL is not set!");
#[derive(Debug, Clone)]
struct SharedState {
bot: Bot,
chat: Chat
}
async fn start_tg() -> (Bot, Chat) {
log::info!("Starting up telegram bot...");
let bot = Bot::new(TG_KEY);
let me = bot.get_me().await.unwrap();
log::info!("Logged in to telegram as \"{}\"", me.first_name);
let chat = bot.get_chat(Recipient::Id(ChatId(CHAT_ID.parse::<i64>().unwrap()))).await.unwrap();
log::info!("Using chat {}", chat.title().unwrap());
(bot, chat)
}
async fn start_http(state: SharedState) -> Server<SharedState> {
let mut app = tide::with_state(state);
app.at("/pull_wh").post(webhook);
app
}
async fn webhook(mut req: Request<SharedState>) -> tide::Result {
let body = req.body_string().await.unwrap();
let serialized = serde_json::from_str::<gitea::PullWh>(body.as_str());
if serialized.is_err() {
return Ok(format!("Bad serialization: {}", serialized.unwrap_err().to_string()).into());
}
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());
}
Ok(req.body_string().await.unwrap().into())
// Ok("()".into())
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -27,45 +77,25 @@ async fn main() {
log::info!("Running in production"); log::info!("Running in production");
} }
log::info!("Gitea URL: {}", GITEA_URL); let (bot, chat) = start_tg().await;
let http = start_http(SharedState { bot, chat }).await;
let user = api::get_user().await; http.listen(WH_LISTEN_URL.clone()).await.unwrap();
log::info!("Logged into gitea as user \"{}\"", user.full_name);
let repos = api::get_org_repos("Tochka".into()).await;
log::info!("Found {} repositories", repos.len());
let repos = api::filter_repos(repos);
log::info!("Only {} repositories are useful", repos.len());
if !Path::new(".pr-cache").exists() {
let prs = api::get_all_prs(repos.clone()).await;
let data = serde_json::to_string_pretty(&prs).unwrap();
fs::write(".pr-cache", data).await.unwrap();
}
let mut prs = serde_json::from_str::<Vec<gitea::Pull>>(String::from_utf8(fs::read(".pr-cache").await.unwrap()).unwrap().as_str()).unwrap();
log::info!("Got {} PRs", prs.len());
log::info!("Starting up telegram bot...");
let bot = Bot::new(TG_KEY);
let me = bot.get_me().await.unwrap();
log::info!("Logged in to telegram as \"{}\"", me.first_name);
let chat = bot.get_chat(Recipient::Id(ChatId(CHAT_ID.parse::<i64>().unwrap()))).await.unwrap();
log::info!("Using chat {}", chat.title().unwrap());
let time = POLL_TIME.parse::<u64>().unwrap(); let time = POLL_TIME.parse::<u64>().unwrap();
log::info!("Starting polling SCM for updates ({})", time); log::info!("Starting listening for updates ({})", time);
#[allow(dead_code, unreachable_code)]
loop { loop {
let (new_prs, new_data) = api::get_new_prs(prs.clone(), repos.clone()).await;
break;
let (new_prs, new_data): (Vec<gitea::Pull>, Vec<gitea::Pull>) = (vec![], vec![]);
log::debug!("Found {} new PRs", new_prs.len()); log::debug!("Found {} new PRs", new_prs.len());
thread::sleep(Duration::from_millis(time));
if new_prs.len() != 0 { if new_prs.len() != 0 {
prs = new_data; let prs = new_data;
let data = serde_json::to_string_pretty(&prs).unwrap(); let data = serde_json::to_string_pretty(&prs).unwrap();
fs::write(".pr-cache", data).await.unwrap(); fs::write(".pr-cache", data).await.unwrap();