bot: receive events from webhook
This commit is contained in:
parent
e6926d5ba2
commit
d09070dae7
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue