浏览代码

Add logic for recording notifications

This does not actually connect to webhooks yet
Mark Rousskov 5 年之前
父节点
当前提交
af3a2f04cf
共有 5 个文件被更改,包括 141 次插入13 次删除
  1. 32 0
      Cargo.lock
  2. 2 1
      Cargo.toml
  3. 70 0
      src/db.rs
  4. 23 0
      src/db/notifications.rs
  5. 14 12
      src/main.rs

+ 32 - 0
Cargo.lock

@@ -120,6 +120,16 @@ name = "cfg-if"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "chrono"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "cloudabi"
 version = "0.0.3"
@@ -671,6 +681,23 @@ dependencies = [
  "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "num-integer"
+version = "0.1.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.3.1"
@@ -832,6 +859,7 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "postgres-protocol 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1272,6 +1300,7 @@ name = "triagebot"
 version = "0.1.0"
 dependencies = [
  "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "dotenv 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1563,6 +1592,7 @@ dependencies = [
 "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
 "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
 "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
 "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
@@ -1627,6 +1657,8 @@ dependencies = [
 "checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
 "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
+"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
 "checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
 "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
 "checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585"

+ 2 - 1
Cargo.toml

@@ -27,7 +27,8 @@ futures = { version = "0.3", default-features = false, features = ["std"] }
 uuid = { version = "0.8", features = ["v4"] }
 url = "2.1.0"
 once_cell = "1"
-tokio-postgres = "0.5"
+chrono = "0.4"
+tokio-postgres = { version = "0.5", features = ["with-chrono-0_4"] }
 postgres-native-tls = "0.3"
 native-tls = "0.2"
 

+ 70 - 0
src/db.rs

@@ -0,0 +1,70 @@
+use anyhow::Context as _;
+use tokio_postgres::Client as DbClient;
+
+pub mod notifications;
+
+pub async fn run_migrations(client: &DbClient) -> anyhow::Result<()> {
+    client
+        .execute(
+            "CREATE TABLE IF NOT EXISTS database_versions (
+                zero INTEGER PRIMARY KEY,
+                migration_counter INTEGER
+            );",
+            &[],
+        )
+        .await
+        .context("creating database versioning table")?;
+
+    client
+        .execute(
+            "INSERT INTO database_versions (zero, migration_counter)
+        VALUES (0, 0)
+        ON CONFLICT DO NOTHING",
+            &[],
+        )
+        .await
+        .context("inserting initial database_versions")?;
+
+    let migration_idx: i32 = client
+        .query_one("SELECT migration_counter FROM database_versions", &[])
+        .await
+        .context("getting migration counter")?
+        .get(0);
+    let migration_idx = migration_idx as usize;
+
+    for (idx, migration) in MIGRATIONS.iter().enumerate() {
+        if idx >= migration_idx {
+            client
+                .execute(*migration, &[])
+                .await
+                .with_context(|| format!("executing {}th migration", idx))?;
+            client
+                .execute(
+                    "UPDATE database_versions SET migration_counter = $1",
+                    &[&(idx as i32 + 1)],
+                )
+                .await
+                .with_context(|| format!("updating migration counter to {}", idx))?;
+        }
+    }
+
+    Ok(())
+}
+
+static MIGRATIONS: &[&str] = &[
+    "
+CREATE TABLE notifications (
+    notification_id BIGSERIAL PRIMARY KEY,
+    user_id INTEGER,
+    origin_url TEXT NOT NULL,
+    origin_html TEXT,
+    time TIMESTAMP WITH TIME ZONE
+);
+",
+    "
+CREATE TABLE users (
+    user_id INTEGER PRIMARY KEY,
+    username TEXT NOT NULL
+);
+",
+];

+ 23 - 0
src/db/notifications.rs

@@ -0,0 +1,23 @@
+use chrono::{DateTime, FixedOffset};
+use tokio_postgres::Client as DbClient;
+
+pub struct Notification {
+    pub user_id: i32,
+    pub username: String,
+    pub origin_url: String,
+    pub origin_html: String,
+    pub time: DateTime<FixedOffset>,
+}
+
+pub async fn record_ping(db: &DbClient, notification: &Notification) -> anyhow::Result<()> {
+    db.execute(
+        "INSERT INTO users (user_id, username) VALUES ($1, $2) ON CONFLICT DO NOTHING",
+        &[&notification.user_id, &notification.username],
+    )
+    .await?;
+
+    db.execute("INSERT INTO notifications (user_id, origin_url, origin_html, time) VALUES ($1, $2, $3, $4)",
+        &[&notification.user_id, &notification.origin_url, &notification.origin_html, &notification.time]).await?;
+
+    Ok(())
+}

+ 14 - 12
src/main.rs

@@ -10,6 +10,7 @@ use std::{env, net::SocketAddr, sync::Arc};
 use triagebot::{github, handlers::Context, payload, EventName};
 use uuid::Uuid;
 
+mod db;
 mod logger;
 
 async fn serve_req(req: Request<Body>, ctx: Arc<Context>) -> Result<Response<Body>, hyper::Error> {
@@ -160,17 +161,17 @@ async fn connect_to_db(client: Client) -> anyhow::Result<tokio_postgres::Client>
     }
 }
 
-async fn run_server(addr: SocketAddr) {
+async fn run_server(addr: SocketAddr) -> anyhow::Result<()> {
     log::info!("Listening on http://{}", addr);
 
     let client = Client::new();
-    let db_client = match connect_to_db(client.clone()).await {
-        Ok(v) => v,
-        Err(e) => {
-            eprintln!("failed to connect to db: {}", e);
-            return;
-        }
-    };
+    let db_client = connect_to_db(client.clone())
+        .await
+        .context("open database connection")?;
+
+    db::run_migrations(&db_client)
+        .await
+        .context("database migrations")?;
 
     let gh = github::GithubClient::new(
         client.clone(),
@@ -203,9 +204,8 @@ async fn run_server(addr: SocketAddr) {
     });
     let serve_future = Server::bind(&addr).serve(svc);
 
-    if let Err(e) = serve_future.await {
-        eprintln!("server error: {}", e);
-    }
+    serve_future.await?;
+    Ok(())
 }
 
 #[tokio::main]
@@ -218,5 +218,7 @@ async fn main() {
         .map(|p| p.parse::<u16>().expect("parsed PORT"))
         .unwrap_or(8000);
     let addr = ([0, 0, 0, 0], port).into();
-    run_server(addr).await;
+    if let Err(e) = run_server(addr).await {
+        eprintln!("Failed to run server: {}", e);
+    }
 }