Compare commits

...

10 Commits

Author SHA1 Message Date
Tom Alexander
ed2e5159df
Better handling of events. 2023-03-06 15:48:15 -05:00
Tom Alexander
9a27ee8d5b
Fix handling of empty responses. 2022-05-12 10:33:06 -04:00
Tom Alexander
155fb7ae00
Add todo comment. 2022-05-12 10:12:37 -04:00
Tom Alexander
1be697b8bf
Throw away results from the first poll since those are historical. 2022-05-12 10:11:19 -04:00
Tom Alexander
c8b9e73c75
Add call to create notification. 2022-05-12 09:32:26 -04:00
Tom Alexander
11ddea7f53
Parse out the title and state of the pull request. 2022-05-12 09:14:26 -04:00
Tom Alexander
51bbe22bdf
Add parsing of the URL to view the pull request. 2022-05-12 09:06:52 -04:00
Tom Alexander
f46a5f8a9c
Filtering to 'opened' pull request events. 2022-05-12 08:53:20 -04:00
Tom Alexander
be9dcee422
Move the handling of events into a struct.
I am going to start parsing fields out of the json event objects, so it makes sense to give each event its own type to avoid the verbosity of parsing the values out of the json object every time they are needed.
2022-05-12 08:37:15 -04:00
Tom Alexander
f7d2a2e57d
Filtering for pull request events. 2022-05-08 18:28:40 -04:00
8 changed files with 880 additions and 42 deletions

696
Cargo.lock generated
View File

@ -22,6 +22,99 @@ dependencies = [
"memchr",
]
[[package]]
name = "async-broadcast"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bbd92a9bd0e9c1298118ecf8a2f825e86b12c3ec9e411573e34aaf3a0c03cdd"
dependencies = [
"easy-parallel",
"event-listener",
"futures-core",
"parking_lot 0.11.2",
]
[[package]]
name = "async-channel"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319"
dependencies = [
"concurrent-queue",
"event-listener",
"futures-core",
]
[[package]]
name = "async-executor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"once_cell",
"slab",
]
[[package]]
name = "async-io"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b"
dependencies = [
"concurrent-queue",
"futures-lite",
"libc",
"log",
"once_cell",
"parking",
"polling",
"slab",
"socket2",
"waker-fn",
"winapi",
]
[[package]]
name = "async-lock"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
dependencies = [
"event-listener",
]
[[package]]
name = "async-recursion"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-task"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9"
[[package]]
name = "async-trait"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atoi"
version = "0.4.0"
@ -60,6 +153,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.9.0"
@ -87,6 +186,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cache-padded"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
[[package]]
name = "cc"
version = "1.0.73"
@ -99,6 +204,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "concurrent-queue"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
dependencies = [
"cache-padded",
]
[[package]]
name = "core-foundation"
version = "0.9.3"
@ -159,6 +273,17 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.9.0"
@ -168,12 +293,39 @@ dependencies = [
"generic-array",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "easy-parallel"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946"
[[package]]
name = "either"
version = "1.6.1"
@ -189,6 +341,27 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "enumflags2"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@ -202,6 +375,12 @@ dependencies = [
"termcolor",
]
[[package]]
name = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[package]]
name = "fastrand"
version = "1.7.0"
@ -254,6 +433,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "futures-channel"
version = "0.3.21"
@ -292,6 +477,27 @@ dependencies = [
"parking_lot 0.11.2",
]
[[package]]
name = "futures-io"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
[[package]]
name = "futures-lite"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"memchr",
"parking",
"pin-project-lite",
"waker-fn",
]
[[package]]
name = "futures-sink"
version = "0.3.21"
@ -344,6 +550,7 @@ name = "github_watcher"
version = "0.1.0"
dependencies = [
"log",
"notify-rust",
"pretty_env_logger",
"reqwest",
"serde_json",
@ -594,6 +801,28 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "mac-notification-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "297c13fc8ff9fa8b2d0e53850f80e0aa962628e865d447031ce58cdb062e5b29"
dependencies = [
"cc",
"dirs-next",
"objc-foundation",
"objc_id",
"time",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "matches"
version = "0.1.9"
@ -606,6 +835,15 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "mime"
version = "0.3.16"
@ -659,6 +897,19 @@ dependencies = [
"tempfile",
]
[[package]]
name = "nix"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
]
[[package]]
name = "nom"
version = "7.1.1"
@ -669,6 +920,20 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "notify-rust"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a995a3d2834cefa389218e7a35156e8ce544bc95f836900da01ee0b26a07e9d4"
dependencies = [
"mac-notification-sys",
"serde",
"winrt-notification",
"zbus",
"zvariant",
"zvariant_derive",
]
[[package]]
name = "ntapi"
version = "0.3.7"
@ -697,6 +962,44 @@ dependencies = [
"libc",
]
[[package]]
name = "num_threads"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
dependencies = [
"libc",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "once_cell"
version = "1.10.0"
@ -742,6 +1045,22 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "ordered-stream"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "parking"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -840,6 +1159,25 @@ version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "polling"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259"
dependencies = [
"cfg-if",
"libc",
"log",
"wepoll-ffi",
"winapi",
]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
@ -850,6 +1188,16 @@ dependencies = [
"log",
]
[[package]]
name = "proc-macro-crate"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
dependencies = [
"thiserror",
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.37"
@ -874,6 +1222,73 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core 0.6.3",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.3",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.13"
@ -883,6 +1298,17 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom",
"redox_syscall",
"thiserror",
]
[[package]]
name = "regex"
version = "1.5.5"
@ -1033,6 +1459,20 @@ name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
@ -1045,6 +1485,17 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -1057,6 +1508,21 @@ dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
"sha1_smol",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]]
name = "sha2"
version = "0.9.9"
@ -1211,6 +1677,12 @@ dependencies = [
"tokio-rustls",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stringprep"
version = "0.1.2"
@ -1221,6 +1693,27 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "strum"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.91"
@ -1232,6 +1725,16 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
dependencies = [
"rand 0.4.6",
"remove_dir_all",
]
[[package]]
name = "tempfile"
version = "3.3.0"
@ -1275,6 +1778,16 @@ dependencies = [
"syn",
]
[[package]]
name = "time"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
dependencies = [
"libc",
"num_threads",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
@ -1367,6 +1880,15 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "tower-service"
version = "0.3.1"
@ -1417,6 +1939,16 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "uds_windows"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "486992108df0fe0160680af1941fe856c521be931d5a5ecccefe0de86dc47e4a"
dependencies = [
"tempdir",
"winapi",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
@ -1480,6 +2012,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]]
name = "want"
version = "0.3.0"
@ -1597,6 +2135,15 @@ dependencies = [
"webpki",
]
[[package]]
name = "wepoll-ffi"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
dependencies = [
"cc",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -1628,6 +2175,18 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9f39345ae0c8ab072c0ac7fe8a8b411636aa34f89be19ddd0d9226544f13944"
dependencies = [
"windows_i686_gnu 0.24.0",
"windows_i686_msvc 0.24.0",
"windows_x86_64_gnu 0.24.0",
"windows_x86_64_msvc 0.24.0",
]
[[package]]
name = "windows-sys"
version = "0.34.0"
@ -1635,10 +2194,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
"windows_i686_gnu 0.34.0",
"windows_i686_msvc 0.34.0",
"windows_x86_64_gnu 0.34.0",
"windows_x86_64_msvc 0.34.0",
]
[[package]]
@ -1647,24 +2206,48 @@ version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d"
[[package]]
name = "windows_i686_gnu"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0866510a3eca9aed73a077490bbbf03e5eaac4e1fd70849d89539e5830501fd"
[[package]]
name = "windows_i686_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed"
[[package]]
name = "windows_i686_msvc"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6"
[[package]]
name = "windows_i686_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956"
[[package]]
name = "windows_x86_64_gnu"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384a173630588044205a2993b6864a2f56e5a8c1e7668c07b93ec18cf4888dc4"
[[package]]
name = "windows_x86_64_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4"
[[package]]
name = "windows_x86_64_msvc"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399"
[[package]]
name = "windows_x86_64_msvc"
version = "0.34.0"
@ -1679,3 +2262,108 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]]
name = "winrt-notification"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "007a0353840b23e0c6dc73e5b962ff58ed7f6bc9ceff3ce7fe6fbad8d496edf4"
dependencies = [
"strum",
"windows",
"xml-rs",
]
[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]]
name = "zbus"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53819092b9db813b2c6168b097b4b13ad284d81c9f2b0165a0a1b190e505a1f3"
dependencies = [
"async-broadcast",
"async-channel",
"async-executor",
"async-io",
"async-lock",
"async-recursion",
"async-task",
"async-trait",
"byteorder",
"derivative",
"enumflags2",
"event-listener",
"futures-core",
"futures-sink",
"futures-util",
"hex",
"lazy_static",
"nix",
"once_cell",
"ordered-stream",
"rand 0.8.5",
"serde",
"serde_repr",
"sha1",
"static_assertions",
"uds_windows",
"winapi",
"zbus_macros",
"zbus_names",
"zvariant",
]
[[package]]
name = "zbus_macros"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7174ebe6722c280d6d132d694bb5664ce50a788cb70eeb518e7fc1ca095a114"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"regex",
"syn",
]
[[package]]
name = "zbus_names"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1"
dependencies = [
"serde",
"static_assertions",
"zvariant",
]
[[package]]
name = "zvariant"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e18ba99d71e03af262953f476071607da0c44e225236cf9b5b9f7f11f1d0b6b0"
dependencies = [
"byteorder",
"enumflags2",
"libc",
"serde",
"static_assertions",
"zvariant_derive",
]
[[package]]
name = "zvariant_derive"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9042892ebdca35261951a83d17bcbfd4d3d528cb3bde828498a9b306b50d05c0"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]

View File

@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
log = "0.4.17"
notify-rust = "4.5.8"
pretty_env_logger = "0.4.0"
reqwest = { version = "0.11.10", features = ["json"] }
serde_json = "1.0.81"

View File

@ -1,4 +1,6 @@
use reqwest::header::HeaderValue;
use reqwest::RequestBuilder;
use reqwest::Response;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::time::{sleep, Duration};
@ -36,9 +38,26 @@ impl GithubEndpointWatcher {
})
}
pub async fn get_results(
&mut self,
) -> Result<Option<serde_json::Value>, Box<dyn std::error::Error>> {
pub async fn skip_results_before_now(&mut self) -> Result<(), Box<dyn std::error::Error>> {
// This will incur an API call to get the headers for ETAG and
// last modified at but it will throw away the results.
// TODO: Can this be done without a request? We wouldn't get
// an ETAG but we should be able to calculate our own date
// string for last modified.
let request = self.build_request()?;
self.sleep_until_next_poll().await?;
self.sleep_until_ratelimit().await?;
let request_started_at = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
info!("Hitting url {}", self.url);
let response = request.send().await?;
self.update_headers_from_response(&response, request_started_at)?;
response.error_for_status()?;
Ok(())
}
fn build_request(&mut self) -> Result<RequestBuilder, Box<dyn std::error::Error>> {
let mut request = self
.http_client
.get(&self.url)
@ -58,14 +77,16 @@ impl GithubEndpointWatcher {
);
request = request.header(reqwest::header::IF_MODIFIED_SINCE, last_modified_at);
}
self.sleep_until_next_poll().await?;
self.sleep_until_ratelimit().await?;
let request_started_at = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
info!("Hitting url {}", self.url);
let response = request.send().await?;
Ok(request)
}
fn update_headers_from_response(
&mut self,
response: &Response,
request_started_at: u64,
) -> Result<(), Box<dyn std::error::Error>> {
let headers = response.headers();
let etag = headers.get(reqwest::header::ETAG).map(|x| x.to_owned());
self.etag = headers.get(reqwest::header::ETAG).map(|x| x.to_owned());
let poll_interval = number_header(headers.get("x-poll-interval"))?;
if let Some(interval) = poll_interval {
self.previous_poll_interval = Some(interval);
@ -75,38 +96,39 @@ impl GithubEndpointWatcher {
self.ratelimit_reset = number_header(headers.get("x-ratelimit-reset"))?;
// let ratelimit_used = headers.get("x-ratelimit-used").map(|x| x.to_owned());
// let ratelimit_resource = headers.get("x-ratelimit-resource").map(|x| x.to_owned());
let last_modified_at = headers
self.last_modified_at = headers
.get(reqwest::header::LAST_MODIFIED)
.map(|x| x.to_owned());
if let reqwest::StatusCode::NOT_MODIFIED = response.status() {
self.etag = etag;
self.last_modified_at = last_modified_at;
let poll_interval_parsed: u64 = poll_interval.unwrap_or_else(|| {
let fallback_interval = self.previous_poll_interval.unwrap_or(300);
info!(
"No poll interval returned, defaulting to {} second polling.",
fallback_interval
);
let poll_interval_parsed: u64 = poll_interval.unwrap_or_else(|| {
let fallback_interval = self.previous_poll_interval.unwrap_or(300);
info!(
"No poll interval returned, defaulting to {} second polling.",
fallback_interval
});
self.next_poll_allowed = request_started_at + poll_interval_parsed;
);
fallback_interval
});
self.next_poll_allowed = request_started_at + poll_interval_parsed;
Ok(())
}
pub async fn get_results(
&mut self,
) -> Result<Option<serde_json::Value>, Box<dyn std::error::Error>> {
let request = self.build_request()?;
self.sleep_until_next_poll().await?;
self.sleep_until_ratelimit().await?;
let request_started_at = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
info!("Hitting url {}", self.url);
let response = request.send().await?;
self.update_headers_from_response(&response, request_started_at)?;
let response_status = response.status();
if let reqwest::StatusCode::NOT_MODIFIED = response_status {
return Ok(None);
} else {
let body = response.json::<serde_json::Value>().await?;
self.etag = etag;
self.last_modified_at = last_modified_at;
let poll_interval_parsed: u64 = poll_interval.unwrap_or_else(|| {
let fallback_interval = self.previous_poll_interval.unwrap_or(300);
info!(
"No poll interval returned, defaulting to {} second polling.",
fallback_interval
);
fallback_interval
});
self.next_poll_allowed = request_started_at + poll_interval_parsed;
return Ok(Some(body));
}
}

View File

@ -1,3 +1,5 @@
use crate::json_util::get_json_string;
use std::collections::HashSet;
use tokio::sync::mpsc;
use super::github_endpoint_watcher::GithubEndpointWatcher;
@ -75,8 +77,10 @@ impl<'a> GithubCtl<'a> {
let event_stream = self.event_writer.clone();
tokio::spawn(async move {
let mut already_seen_event_ids = HashSet::new();
let mut endpoint_watcher = GithubEndpointWatcher::new(username, token, url)
.expect("Failed to create endpoint watcher.");
let mut should_notify: bool = false; // Skip the first page of results because theses events already occurred in the past
loop {
let api_result = match endpoint_watcher.get_results().await {
Ok(result) => result,
@ -87,9 +91,17 @@ impl<'a> GithubCtl<'a> {
};
if let Some(serde_json::Value::Array(events)) = api_result {
for event in events {
if let Err(_) = event_stream.send(event).await {
error!("Receiver dropped.");
return;
let event_id = event
.get("id")
.map(get_json_string)
.expect("Ran into an event without a id.")
.to_owned();
if should_notify && already_seen_event_ids.insert(event_id) {
if let Err(_) = event_stream.send(event).await {
error!("Receiver dropped.");
return;
}
}
}
} else if let None = api_result {
@ -97,6 +109,7 @@ impl<'a> GithubCtl<'a> {
} else {
error!("Unsupported JSON type.");
}
should_notify = true;
}
});
}

View File

@ -1,4 +1,6 @@
mod github_endpoint_watcher;
mod githubctl;
mod pull_request_event;
pub use githubctl::GithubCtl;
pub use pull_request_event::PullRequestEvent;

View File

@ -0,0 +1,57 @@
use crate::json_util::get_json_object;
use crate::json_util::get_json_string;
pub struct PullRequestEvent<'a> {
original_event: &'a serde_json::Value,
pub action: &'a String,
pub html_url: &'a String,
pub state: &'a String,
pub title: &'a String,
}
impl<'a> PullRequestEvent<'a> {
pub fn new(original_event: &'a serde_json::Value) -> Result<Self, Box<dyn std::error::Error>> {
let payload = original_event
.get("payload")
.map(get_json_object)
.expect("Ran into a PullRequestEvent without a payload.");
let payload_action = payload
.get("action")
.map(get_json_string)
.expect("Ran into a PullRequestEvent without a payload.action.");
let payload_pull_request = payload
.get("pull_request")
.map(get_json_object)
.expect("Ran into a PullRequestEvent without a payload.pull_request.");
let payload_pull_request_html_url = payload_pull_request
.get("html_url")
.map(get_json_string)
.expect("Ran into a PullRequestEvent without a payload.pull_request.html_url.");
let payload_pull_request_state = payload_pull_request
.get("state")
.map(get_json_string)
.expect("Ran into a PullRequestEvent without a payload.pull_request.state.");
let payload_pull_request_title = payload_pull_request
.get("title")
.map(get_json_string)
.expect("Ran into a PullRequestEvent without a payload.pull_request.title.");
Ok(PullRequestEvent {
original_event,
action: payload_action,
html_url: payload_pull_request_html_url,
state: payload_pull_request_state,
title: payload_pull_request_title,
})
}
pub fn is_a(event: &'a serde_json::Value) -> Result<bool, Box<dyn std::error::Error>> {
let event_type = event.get("type").map(get_json_string);
match event_type {
Some(event_type_string) if event_type_string == "PullRequestEvent" => {
return Ok(true);
}
_ => Ok(false),
}
}
}

23
src/json_util.rs Normal file
View File

@ -0,0 +1,23 @@
use serde_json::{self, Map};
pub fn get_json_object(obj: &serde_json::Value) -> &Map<String, serde_json::Value> {
match obj {
serde_json::Value::Null => panic!("Unexpected json type"),
serde_json::Value::Bool(_) => panic!("Unexpected json type"),
serde_json::Value::Number(_) => panic!("Unexpected json type"),
serde_json::Value::String(_) => panic!("Unexpected json type"),
serde_json::Value::Array(_) => panic!("Unexpected json type"),
serde_json::Value::Object(event_object) => event_object,
}
}
pub fn get_json_string(str: &serde_json::Value) -> &String {
match str {
serde_json::Value::Null => panic!("Unexpected json type"),
serde_json::Value::Bool(_) => panic!("Unexpected json type"),
serde_json::Value::Number(_) => panic!("Unexpected json type"),
serde_json::Value::String(txt) => txt,
serde_json::Value::Array(_) => panic!("Unexpected json type"),
serde_json::Value::Object(_) => panic!("Unexpected json type"),
}
}

View File

@ -2,7 +2,10 @@
extern crate log;
mod githubctl;
mod json_util;
use githubctl::PullRequestEvent;
use notify_rust::{Hint, Notification};
use serde_json;
const USERNAME: &'static str = include_str!("../.username");
@ -17,6 +20,35 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
github.watch_repo(ORG, REPO).await?;
loop {
let event = github.get_event().await?;
println!("{}", serde_json::to_string(&event)?);
// println!("{}", serde_json::to_string(&event)?);
handle_event(event)?;
}
}
fn handle_event(json_event: serde_json::Value) -> Result<(), Box<dyn std::error::Error>> {
if PullRequestEvent::is_a(&json_event)? {
let event = PullRequestEvent::new(&json_event)?;
if event.action == "opened" {
// println!("PullRequestEvent action {}", event.action);
println!("{}", serde_json::to_string(&json_event)?);
let notification_body = format!("Pull Request opened: {}", event.title);
Notification::new()
.summary("Pull request opened.")
.body(notification_body.as_str())
// .icon("can be a full path to an image file")
.appname("github_watcher")
.hint(Hint::Category("im.received".to_owned()))
.hint(Hint::Resident(true))
.timeout(0)
.show()?
.wait_for_action(|action| match action {
"default" => info!("you clicked \"default\""),
"clicked" => info!("that was correct"),
// here "__closed" is a hard coded keyword
"__closed" => info!("the notification was closed"),
_ => info!("Unrecognized action {}", action),
});
}
}
Ok(())
}