bot: receive events from webhook

This commit is contained in:
Antoine Martin 2021-09-12 17:36:18 +02:00
parent e6926d5ba2
commit d09070dae7
5 changed files with 95 additions and 15 deletions

View file

@ -2,6 +2,7 @@ use std::{
fs::File,
io::{BufReader, BufWriter},
path::PathBuf,
sync::mpsc::Receiver,
};
use anyhow::Context;
@ -12,7 +13,7 @@ use matrix_sdk::{
};
use tracing::{debug, info};
use crate::config::ProloloConfig;
use crate::{config::ProloloConfig, webhooks::Event};
mod handlers;
use handlers::autojoin::autojoin_authorized_rooms;
@ -61,11 +62,25 @@ impl Prololo {
///
/// [`Prololo::init`] **must** be called before this function, otherwise the [`Client`] isn't
/// logged in.
pub async fn run(&self) {
pub async fn run(&self, events: Receiver<Event>) {
debug!("running...");
let client = self.client.clone();
let config = self.config.clone();
tokio::task::spawn_blocking(move || {
Self::handle_events(events, client, config);
});
self.client.sync(SyncSettings::default()).await
}
fn handle_events(events: Receiver<Event>, client: Client, config: ProloloConfig) {
loop {
let event = events.recv().unwrap();
debug!("received event: {:?}", event);
}
}
/// This loads the session information from an existing file, and tries to login with it. If no such
/// file is found, then login using username and password, and save the new session information on
/// disk.

View file

@ -4,7 +4,7 @@ use matrix_sdk::ruma::RoomId;
use serde::Deserialize;
use url::Url;
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct ProloloConfig {
/// The URL for the homeserver we should connect to
pub matrix_homeserver: Url,

View file

@ -1,6 +1,7 @@
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use std::sync::mpsc::sync_channel;
use anyhow::Context;
use clap::Clap;
@ -13,7 +14,7 @@ mod config;
use config::ProloloConfig;
mod webhooks;
use webhooks::github_webhook;
use webhooks::{github_webhook, EventSender};
#[derive(Clap)]
#[clap(version = "0.1")]
@ -33,10 +34,14 @@ async fn main() -> anyhow::Result<()> {
let config: ProloloConfig = serde_yaml::from_reader(BufReader::new(config_file))
.context("couldn't parse config file")?;
let (sender, receiver) = sync_channel(42);
let prololo = Prololo::new(config).context("failed to create prololo bot")?;
prololo.init().await.context("failed to init prololo bot")?;
tokio::spawn(async move { prololo.run().await });
tokio::spawn(async move { prololo.run(receiver).await });
let rocket = rocket::build().mount("/", routes![github_webhook]);
let rocket = rocket::build()
.mount("/", routes![github_webhook])
.manage(EventSender(sender));
rocket.launch().await.map_err(|err| anyhow::anyhow!(err))
}

View file

@ -1,27 +1,47 @@
use anyhow::anyhow;
use anyhow::{anyhow, bail};
use rocket::{
http::Status,
request::{FromRequest, Outcome},
Request,
Request, State,
};
use serde::Deserialize;
mod signing;
use signing::SignedGitHubPayload;
use tracing::{debug, info, warn};
use url::Url;
use crate::webhooks::{Event, EventSender};
const X_GITHUB_EVENT: &str = "X-GitHub-Event";
struct GitHubSecret(String);
#[rocket::post("/api/webhooks/github", data = "<payload>")]
pub fn github_webhook(event: GitHubEventType, payload: SignedGitHubPayload) -> &'static str {
pub fn github_webhook(
event: GitHubEventType,
payload: SignedGitHubPayload,
sender: &State<EventSender>,
) -> Status {
info!(
"received event {:?} with signed payload:\n{}",
event, payload.0
);
"OK"
let event = match event.parse_payload(&payload) {
Ok(event) => event,
Err(e) => {
warn!(
"couldn't parse payload for event {:?}: {}\n{}",
event, e, payload.0
);
return Status::BadRequest;
}
};
sender.0.send(Event::GitHub(event)).unwrap();
Status::Ok
}
#[derive(Debug, Deserialize)]
@ -34,6 +54,16 @@ pub enum GitHubEventType {
Unknown,
}
impl GitHubEventType {
fn parse_payload(&self, payload: &SignedGitHubPayload) -> anyhow::Result<GitHubEvent> {
Ok(match self {
Self::Create => GitHubEvent::Create(serde_json::from_str(&payload.0)?),
Self::Unknown => bail!("unknown event type"),
_ => unimplemented!(),
})
}
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for GitHubEventType {
type Error = anyhow::Error;
@ -70,16 +100,37 @@ impl<'r> FromRequest<'r> for GitHubEventType {
}
}
enum GitHubEvent {
Create { ref_type: RefType },
#[derive(Debug)]
pub enum GitHubEvent {
Create(CreateEvent),
Issues,
IssueComment,
Push,
}
#[derive(Deserialize)]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
enum RefType {
pub enum RefType {
Branch,
Tag,
}
#[derive(Debug, Deserialize)]
pub struct GitHubUser {
login: String,
}
#[derive(Debug, Deserialize)]
pub struct Repository {
name: String,
full_name: String,
html_url: Url,
}
#[derive(Debug, Deserialize)]
pub struct CreateEvent {
r#ref: String,
ref_type: RefType,
repository: Repository,
sender: GitHubUser,
}

View file

@ -1,2 +1,11 @@
use std::sync::{mpsc::SyncSender};
mod github;
pub use github::github_webhook;
pub use github::{github_webhook, GitHubEvent};
pub struct EventSender(pub SyncSender<Event>);
#[derive(Debug)]
pub enum Event {
GitHub(GitHubEvent),
}