Index: Cargo.lock ================================================================== --- Cargo.lock +++ Cargo.lock @@ -67,19 +67,19 @@ name = "async-global-executor" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-executor 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-io 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-io 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "async-io" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -117,11 +117,11 @@ name = "async-std" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "async-global-executor 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "async-io 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-io 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "async-mutex 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "blocking 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures-core 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -134,11 +134,11 @@ "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-futures 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "async-task" version = "4.0.3" @@ -481,21 +481,21 @@ "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "darling_macro" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "derive_builder" version = "0.9.0" @@ -503,11 +503,11 @@ dependencies = [ "darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "derive_builder_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "derive_builder_core" version = "0.9.0" @@ -514,11 +514,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "darling 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "digest" version = "0.9.0" @@ -577,11 +577,11 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fastrand" @@ -730,11 +730,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-sink" version = "0.3.8" @@ -806,13 +806,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures-core 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "h2" version = "0.1.26" @@ -1065,14 +1065,14 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "js-sys" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1550,21 +1550,21 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pin-project-internal" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pin-project-lite" version = "0.1.11" @@ -1867,11 +1867,11 @@ "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rsstg" -version = "0.1.9" +version = "0.1.11" dependencies = [ "anyhow 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1994,11 +1994,11 @@ version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" version = "1.0.59" @@ -2162,11 +2162,11 @@ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "sqlx-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "sqlx-rt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sqlx-rt" @@ -2210,11 +2210,11 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2225,11 +2225,11 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tap" @@ -2290,11 +2290,11 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" version = "1.0.1" @@ -2404,11 +2404,11 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" version = "0.1.12" @@ -2528,11 +2528,11 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tracing-core" version = "0.1.17" @@ -2698,75 +2698,75 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasm-bindgen" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "web-sys" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wepoll-sys" version = "3.0.1" @@ -2847,11 +2847,11 @@ "checksum anyhow 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" "checksum arrayvec 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" "checksum async-channel 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" "checksum async-executor 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" "checksum async-global-executor 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "73079b49cd26b8fd5a15f68fc7707fc78698dc2a3d61430f2a7a9430230dfa04" -"checksum async-io 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "458c8f66c246624e7cf87c01451f3392ab77d66a0f105a49d9353b30ea97ced8" +"checksum async-io 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" "checksum async-mutex 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" "checksum async-native-tls 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" "checksum async-std 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7e82538bc65a25dbdff70e4c5439d52f068048ab97cdea0acd73f131594caa1" "checksum async-task 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" "checksum atoi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5c897df197d57c25b37df9d8fa2f93ddbfeee9ebd2264350ac79c8ec4b795885" @@ -2956,11 +2956,11 @@ "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum indexmap 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" "checksum instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum js-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" +"checksum js-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum kv-log-macro 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lexical-core 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" "checksum libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" @@ -3083,11 +3083,11 @@ "checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" "checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" "checksum subtle 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" -"checksum syn 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "6c1e438504729046a5cfae47f97c30d6d083c7d91d94603efdae3477fc070d4c" +"checksum syn 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "8833e20724c24de12bbaba5ad230ea61c3eafb05b881c7c9d3cfe8638b187e68" "checksum synstructure 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" "checksum tap 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e" "checksum telegram-bot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc9552e972bcb551705fcad45bd0b86eca12a22379db36cdfa6d053e1a19b2de" "checksum telegram-bot-raw 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e4fc120e2b85d639fc932a4aa7c1b6a5f1189fb86948d7a02037d1d8f1ef559" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" @@ -3137,17 +3137,17 @@ "checksum waker-fn 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" "checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" -"checksum wasm-bindgen-backend 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" -"checksum wasm-bindgen-futures 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" -"checksum wasm-bindgen-macro 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" -"checksum wasm-bindgen-macro-support 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" -"checksum wasm-bindgen-shared 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" -"checksum web-sys 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" +"checksum wasm-bindgen 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" +"checksum wasm-bindgen-backend 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" +"checksum wasm-bindgen-futures 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" +"checksum wasm-bindgen-macro 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" +"checksum wasm-bindgen-macro-support 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" +"checksum wasm-bindgen-shared 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" +"checksum web-sys 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" "checksum wepoll-sys 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" "checksum whoami 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7884773ab69074615cb8f8425d0e53f11710786158704fca70f53e71b0e05504" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "rsstg" -version = "0.1.10" +version = "0.1.11" authors = ["arcade"] edition = "2018" [dependencies] chrono = "*" Index: rsstg.sql ================================================================== --- rsstg.sql +++ rsstg.sql @@ -1,17 +1,12 @@ create table rsstg_updates (owner integer, update jsonb); create unique index rsstg_updates__id on rsstg_updates(update->>'update_id'); --- create table rsstg_users (id integer); -create table rsstg_channel ( - channel_id bigint primary key, - username text not null); -create unique index rsstg_channel__username on rsstg_channel(username); - create table rsstg_source ( source_id serial, + channel text not null, channel_id integer not null, url text not null, last_scrape not null timestamptz default now(), enabled boolean not null default false, iv_hash text, @@ -23,11 +18,11 @@ create table rsstg_post ( source_id integer not null, date int not null, url text not null, hour smallint not null generated always as (extract('hour' from posted)) stored, - FOREIGN KEY (source_id) REFERENCES rsstg_source(source_id) + FOREIGN KEY (source_id) REFERENCES rsstg_source(source_id) on delete cascade, ); create unique index rsstg_post__url on rsstg_post(url); create index rsstg_post__hour on rsstg_post(hour); create index rsstg_post__posted_hour on rsstg_post(posted,hour); Index: src/main.rs ================================================================== --- src/main.rs +++ src/main.rs @@ -18,11 +18,11 @@ use sqlx::Done; // .rows_affected() #[macro_use] extern crate lazy_static; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; #[derive(Clone)] struct Core { owner: i64, api_key: String, @@ -50,11 +50,11 @@ .connect_lazy(&settings.get_str("pg")?)?, }; let clone = core.clone(); tokio::spawn(async move { if let Err(err) = &clone.autofetch().await { - if let Err(err) = clone.debug(&format!("{:?}", err)) { + if let Err(err) = clone.debug(&format!("πŸ›‘ {:?}", err)) { eprintln!("Autofetch error: {}", err); }; } }); Ok(core) @@ -71,16 +71,16 @@ async fn check(&self, id: &i32, owner: S, real: bool) -> Result<()> where S: Into { let owner: i64 = owner.into(); let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Query queue fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("Query queue fetch conn:\n{:?}", &self.pool))?; let row = sqlx::query("select source_id, channel_id, url, iv_hash, owner from rsstg_source where source_id = $1 and owner = $2") .bind(id) .bind(owner) .fetch_one(&mut conn).await - .with_context(|| format!("πŸ›‘ Query source:\n{:?}", &self.pool))?; + .with_context(|| format!("Query source:\n{:?}", &self.pool))?; drop(conn); let channel_id: i64 = row.try_get("channel_id")?; let destination = match real { true => UserId::new(channel_id), false => UserId::new(row.try_get("owner")?), @@ -88,11 +88,11 @@ let url: &str = row.try_get("url")?; let mut this_fetch: Option> = None; let iv_hash: Option<&str> = row.try_get("iv_hash")?; let mut posts: BTreeMap, String> = BTreeMap::new(); let feed = rss::Channel::from_url(url) - .with_context(|| format!("πŸ›‘ Problem opening feed url:\n{}", &url))?; + .with_context(|| format!("Problem opening feed url:\n{}", &url))?; for item in feed.items() { let date = match item.pub_date() { Some(feed_date) => DateTime::parse_from_rfc2822(feed_date), None => DateTime::parse_from_rfc3339(&item.dublin_core_ext().unwrap().dates()[0]), }?; @@ -99,118 +99,174 @@ let url = item.link().unwrap().to_string(); posts.insert(date.clone(), url.clone()); }; for (date, url) in posts.iter() { let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Check post fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("Check post fetch conn:\n{:?}", &self.pool))?; let row = sqlx::query("select exists(select true from rsstg_post where url = $1 and source_id = $2) as exists;") .bind(&url) .bind(id) .fetch_one(&mut conn).await - .with_context(|| format!("πŸ›‘ Check post:\n{:?}", &conn))?; + .with_context(|| format!("Check post:\n{:?}", &conn))?; let exists: bool = row.try_get("exists")?; if ! exists { if this_fetch == None || *date > this_fetch.unwrap() { this_fetch = Some(*date); }; self.tg.send( match iv_hash { Some(x) => SendMessage::new(destination, format!(" {0}", url, x)), None => SendMessage::new(destination, format!("{}", url)), }.parse_mode(types::ParseMode::Html)).await - .context("πŸ›‘ Can't post message:")?; + .context("Can't post message:")?; sqlx::query("insert into rsstg_post (source_id, posted, url) values ($1, $2, $3);") .bind(id) .bind(date) .bind(url) .execute(&mut conn).await - .with_context(|| format!("πŸ›‘Record post:\n{:?}", &conn))?; + .with_context(|| format!("Record post:\n{:?}", &conn))?; drop(conn); tokio::time::delay_for(std::time::Duration::new(4, 0)).await; }; }; posts.clear(); let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Update scrape fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("Update scrape fetch conn:\n{:?}", &self.pool))?; sqlx::query("update rsstg_source set last_scrape = now() where source_id = $1;") .bind(id) .execute(&mut conn).await - .with_context(|| format!("πŸ›‘ Update scrape:\n{:?}", &conn))?; + .with_context(|| format!("Update scrape:\n{:?}", &conn))?; Ok(()) } - async fn clean(&self, source_id: &i32, id: S) -> Result + async fn delete(&self, source_id: &i32, owner: S) -> Result + where S: Into { + let owner: i64 = owner.into(); + let mut conn = self.pool.acquire().await + .with_context(|| format!("Delete fetch conn:\n{:?}", &self.pool))?; + match sqlx::query("delete from rsstg_source where source_id = $1 and owner = $2;") + .bind(source_id) + .bind(owner) + .execute(&mut conn).await + .with_context(|| format!("Delete source rule:\n{:?}", &self.pool))? + .rows_affected() { + 0 => { Ok("No data found found\\.".to_string()) }, + x => { Ok(format!("{} sources removed\\.", x)) }, + } + } + + async fn clean(&self, source_id: &i32, owner: S) -> Result where S: Into { - let id: i64 = id.into(); + let owner: i64 = owner.into(); let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Clean fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("Clean fetch conn:\n{:?}", &self.pool))?; match sqlx::query("delete from rsstg_post p using rsstg_source s where p.source_id = $1 and owner = $2 and p.source_id = s.source_id;") .bind(source_id) - .bind(id) + .bind(owner) .execute(&mut conn).await - .with_context(|| format!("πŸ›‘ Clean seen posts:\n{:?}", &self.pool))? + .with_context(|| format!("Clean seen posts:\n{:?}", &self.pool))? .rows_affected() { 0 => { Ok("No data found found\\.".to_string()) }, x => { Ok(format!("{} posts purged\\.", x)) }, } } - async fn enable(&self, source_id: &i32, id: S) -> Result<&str> + async fn enable(&self, source_id: &i32, owner: S) -> Result<&str> where S: Into { - let id: i64 = id.into(); + let owner: i64 = owner.into(); let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Enable fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("Enable fetch conn:\n{:?}", &self.pool))?; match sqlx::query("update rsstg_source set enabled = true where source_id = $1 and owner = $2") .bind(source_id) - .bind(id) + .bind(owner) + .execute(&mut conn).await + .with_context(|| format!("Enable source:\n{:?}", &self.pool))? + .rows_affected() { + 1 => { Ok("Source disabled\\.") }, + 0 => { Ok("Source not found\\.") }, + _ => { Err(anyhow!("Database error.")) }, + } + } + + async fn disable(&self, source_id: &i32, owner: S) -> Result<&str> + where S: Into { + let owner: i64 = owner.into(); + let mut conn = self.pool.acquire().await + .with_context(|| format!("Disable fetch conn:\n{:?}", &self.pool))?; + match sqlx::query("update rsstg_source set enabled = false where source_id = $1 and owner = $2") + .bind(source_id) + .bind(owner) .execute(&mut conn).await - .with_context(|| format!("πŸ›‘ Enable source:\n{:?}", &self.pool))? + .with_context(|| format!("Disable source:\n{:?}", &self.pool))? .rows_affected() { 1 => { Ok("Source disabled\\.") }, 0 => { Ok("Source not found\\.") }, _ => { Err(anyhow!("Database error.")) }, } } - async fn disable(&self, source_id: &i32, id: S) -> Result<&str> + async fn update(&self, update: Option, channel: &str, channel_id: i64, url: &str, iv_hash: Option<&str>, owner: S) -> Result where S: Into { - let id: i64 = id.into(); + let owner: i64 = owner.into(); let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Disable fetch conn:\n{:?}", &self.pool))?; - match sqlx::query("update rsstg_source set enabled = false where source_id = $1 and owner = $2") - .bind(source_id) - .bind(id) - .execute(&mut conn).await - .with_context(|| format!("πŸ›‘ Disable source:\n{:?}", &self.pool))? - .rows_affected() { - 1 => { Ok("Source disabled\\.") }, - 0 => { Ok("Source not found\\.") }, - _ => { Err(anyhow!("Database error.")) }, - } + .with_context(|| format!("Update fetch conn:\n{:?}", &self.pool))?; + + match match update { + Some(id) => { + sqlx::query("update rsstg_source set channel_id = $2, url = $3, iv_hash = $4, owner = $5, channel = $6 where source_id = $1").bind(id) + }, + None => { + sqlx::query("insert into rsstg_source (channel_id, url, iv_hash, owner, channel) values ($1, $2, $3, $4, $5)") + }, + } + .bind(channel_id) + .bind(url) + .bind(iv_hash) + .bind(owner) + .bind(channel) + .execute(&mut conn).await { + Ok(_) => return Ok(String::from("Channel added\\.")), + Err(sqlx::Error::Database(err)) => { + match err.downcast::().routine() { + Some("_bt_check_unique", ) => { + return Ok("Duplicate key\\.".to_string()) + }, + Some(_) => { + return Ok("Database error\\.".to_string()) + }, + None => { + return Ok("No database error extracted\\.".to_string()) + }, + }; + }, + Err(err) => { + bail!("Sorry, unknown error:\n{:#?}\n", err); + }, + }; } async fn autofetch(&self) -> Result<()> { let mut delay = chrono::Duration::minutes(5); let mut now; loop { let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ Autofetch fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("Autofetch fetch conn:\n{:?}", &self.pool))?; now = chrono::Local::now(); - let mut queue = sqlx::query("select source_id, next_fetch, owner from rsstg_order natural left join rsstg_source natural left join rsstg_channel where next_fetch < now();") + let mut queue = sqlx::query("select source_id, next_fetch, owner from rsstg_order natural left join rsstg_source where next_fetch < now();") .fetch_all(&mut conn).await?; for row in queue.iter() { let source_id: i32 = row.try_get("source_id")?; let owner: i64 = row.try_get("owner")?; let next_fetch: DateTime = row.try_get("next_fetch")?; if next_fetch < now { sqlx::query("update rsstg_source set last_scrape = now() + interval '1 hour' where source_id = $1;") .bind(source_id) .execute(&mut conn).await - .with_context(|| format!("πŸ›‘ Lock source:\n\n{:?}", &self.pool))?; + .with_context(|| format!(" Lock source:\n\n{:?}", &self.pool))?; let clone = self.clone(); tokio::spawn(async move { if let Err(err) = clone.check(&source_id, owner, true).await { - if let Err(err) = clone.debug(&format!("{:?}", err)) { + if let Err(err) = clone.debug(&format!("πŸ›‘ {:?}", err)) { eprintln!("Check error: {}", err); }; }; }); } else { @@ -223,22 +279,23 @@ tokio::time::delay_for(delay.to_std()?).await; delay = chrono::Duration::minutes(5); } } - async fn list(&self, id: telegram_bot::UserId) -> Result> { - let id = i64::from(id); + async fn list(&self, owner: S) -> Result> + where S: Into { + let owner = owner.into(); let mut reply = vec![]; let mut conn = self.pool.acquire().await - .with_context(|| format!("πŸ›‘ List fetch conn:\n{:?}", &self.pool))?; + .with_context(|| format!("List fetch conn:\n{:?}", &self.pool))?; reply.push("Channels:".to_string()); - let rows = sqlx::query("select source_id, username, enabled, url, iv_hash from rsstg_source left join rsstg_channel using (channel_id) where owner = $1 order by source_id") - .bind(id) + let rows = sqlx::query("select source_id, channel, enabled, url, iv_hash from rsstg_source where owner = $1 order by source_id") + .bind(owner) .fetch_all(&mut conn).await?; for row in rows.iter() { let source_id: i32 = row.try_get("source_id")?; - let username: &str = row.try_get("username")?; + let username: &str = row.try_get("channel")?; let enabled: bool = row.try_get("enabled")?; let url: &str = row.try_get("url")?; let iv_hash: Option<&str> = row.try_get("iv_hash")?; reply.push(format!("\n\\#️⃣ {} \\*️⃣ `{}` {}\nπŸ”— `{}`", source_id, username, match enabled { @@ -262,11 +319,11 @@ let mut stream = core.stream(); while let Some(update) = stream.next().await { if let Err(err) = handle(update?, &core).await { - core.debug(&format!("{:?}", err))?; + core.debug(&format!("πŸ›‘ {:?}", err))?; }; } Ok(()) } @@ -300,138 +357,51 @@ }, // add "/add" | "/update" => { - let mut source_id: i32 = 0; - if cmd == "/update" { - source_id = words.next().unwrap().parse::()?; - } - let (channel, url, iv_hash) = (words.next().unwrap(), words.next().unwrap(), words.next()); - let ok_link = RE_LINK.is_match(&url); - let ok_hash = match iv_hash { - Some(hash) => RE_IV_HASH.is_match(&hash), - None => true, - }; - if ! ok_link { - reply.push("Link should be link to atom/rss feed, something like \"https://domain/path\"\\.".to_string()); - core.debug(&format!("Url: {:?}", &url))?; - } - if ! ok_hash { - reply.push("IV hash should be 14 hex digits.".to_string()); - core.debug(&format!("IV: {:?}", &iv_hash))?; - } - if ok_link && ok_hash { - let chan: Option = match sqlx::query("select channel_id from rsstg_channel where username = $1") - .bind(channel) - .fetch_one(&core.pool).await { - Ok(chan) => Some(chan.try_get("channel_id")?), - Err(sqlx::Error::RowNotFound) => { - let chan_id = i64::from(core.tg.send(telegram_bot::GetChat::new(telegram_bot::types::ChatRef::ChannelUsername(channel.to_string()))).await?.id()); - sqlx::query("insert into rsstg_channel (channel_id, username) values ($1, $2);") - .bind(chan_id) - .bind(channel) - .execute(&core.pool).await?; - Some(chan_id) - }, - Err(err) => { - reply.push("Sorry, unknown error\\.".to_string()); - core.debug(&format!("Sorry, unknown error:\n{:#?}\n", err))?; - None - }, - }; - if let Some(chan) = chan { - match if cmd == "/update" { - sqlx::query("update rsstg_source set channel_id = $2, url = $3, iv_hash = $4, owner = $4 where source_id = $1").bind(source_id) - } else { - sqlx::query("insert into rsstg_source (channel_id, url, iv_hash, owner) values ($1, $2, $3, $4)") - } - .bind(chan) - .bind(url) - .bind(iv_hash) - .bind(i64::from(message.from.id)) - .execute(&core.pool).await { - Ok(_) => reply.push("Channel added\\.".to_string()), - Err(sqlx::Error::Database(err)) => { - match err.downcast::().routine() { - Some("_bt_check_unique", ) => { - reply.push("Duplicate key\\.".to_string()); - }, - Some(_) => { - reply.push("Database error\\.".to_string()); - }, - None => { - reply.push("No database error extracted\\.".to_string()); - }, - }; - }, - Err(err) => { - reply.push("Sorry, unknown error\\.".to_string()); - core.debug(&format!("Sorry, unknown error:\n{:#?}\n", err))?; - }, - }; - }; - }; - }, - -// addchan - - "/addchan" => { - let channel = words.next().unwrap(); - if ! RE_USERNAME.is_match(&channel) { - reply.push("Usernames should be something like \"@\\[a\\-zA\\-Z]\\[a\\-zA\\-Z0\\-9\\_]+\", aren't they?".to_string()); - } else { - let chan: Option = match sqlx::query("select channel_id from rsstg_channel where username = $1") - .bind(channel) - .fetch_one(&core.pool).await { - Ok(chan) => Some(chan.try_get("channel_id")?), - Err(sqlx::Error::RowNotFound) => None, - Err(err) => { - reply.push("Sorry, unknown error\\.".to_string()); - core.debug(&format!("Sorry, unknown error:\n{:#?}", err))?; - None - }, - }; - match chan { - Some(chan) => { - let new_chan = core.tg.send(telegram_bot::GetChat::new(telegram_bot::types::ChatId::new(chan))).await?; - if i64::from(new_chan.id()) == chan { - reply.push("I already know that channel\\.".to_string()); - } else { - reply.push("Hmm, channel has changed… I'll fix it later\\.".to_string()); - }; - }, - None => { - match core.tg.send(telegram_bot::GetChatAdministrators::new(telegram_bot::types::ChatRef::ChannelUsername(channel.to_string()))).await { - Ok(chan_adm) => { - let (mut me, mut user) = (false, false); - for admin in &chan_adm { - if admin.user.id == core.my.id { - me = true; - }; - if admin.user.id == message.from.id { - user = true; - }; - }; - if ! me { reply.push("I need to be admin on that channel\\.".to_string()); }; - if ! user { reply.push("You should be admin on that channel\\.".to_string()); }; - if me && user { - let chan_id = core.tg.send(telegram_bot::GetChat::new(telegram_bot::types::ChatRef::ChannelUsername(channel.to_string()))).await?; - sqlx::query("insert into rsstg_channel (channel_id, username) values ($1, $2);") - .bind(i64::from(chan_id.id())) - .bind(channel) - .execute(&core.pool).await?; - reply.push("Good, I know that channel now\\.\n".to_string()); - }; - }, - Err(_) => { - reply.push("Sorry, I have no access to that chat\\.".to_string()); - }, - }; - }, - }; - }; + let mut source_id: Option = None; + let at_least = "Requires at least 3 parameters."; + if cmd == "/update" { + let first_word = words.next() + .context(at_least)?; + source_id = Some(first_word.parse::() + .with_context(|| format!("I need a number, but got {}.", first_word))?); + } + let (channel, url, iv_hash) = ( + words.next().context(at_least)?, + words.next().context(at_least)?, + words.next()); + if ! RE_USERNAME.is_match(&channel) { + reply.push("Usernames should be something like \"@\\[a\\-zA\\-Z]\\[a\\-zA\\-Z0\\-9\\_]+\", aren't they?".to_string()); + bail!("Wrong username {:?}.", &channel); + } + if ! RE_LINK.is_match(&url) { + reply.push("Link should be link to atom/rss feed, something like \"https://domain/path\"\\.".to_string()); + bail!("Url: {:?}", &url); + } + if let Some(hash) = iv_hash { + if ! RE_IV_HASH.is_match(&hash) { + reply.push("IV hash should be 14 hex digits.".to_string()); + bail!("IV: {:?}", &iv_hash); + }; + }; + let channel_id = i64::from(core.tg.send(telegram_bot::GetChat::new(telegram_bot::types::ChatRef::ChannelUsername(channel.to_string()))).await?.id()); + let chan_adm = core.tg.send(telegram_bot::GetChatAdministrators::new(telegram_bot::types::ChatRef::ChannelUsername(channel.to_string()))).await + .context("Sorry, I have no access to that chat\\.")?; + let (mut me, mut user) = (false, false); + for admin in chan_adm { + if admin.user.id == core.my.id { + me = true; + }; + if admin.user.id == message.from.id { + user = true; + }; + }; + if ! me { bail!("I need to be admin on that channel\\."); }; + if ! user { bail!("You should be admin on that channel\\."); }; + reply.push(core.update(source_id, channel, channel_id, url, iv_hash, message.from.id).await?); }, // check "/check" => { @@ -439,11 +409,11 @@ Err(err) => { reply.push(format!("I need a number\\.\n{}", &err)); }, Ok(number) => { core.check(&number, message.from.id, false).await - .context("πŸ›‘ Channel check failed.")?; + .context("Channel check failed.")?; }, }; }, // clean @@ -471,10 +441,24 @@ let result = core.enable(&number, message.from.id).await?; reply.push(result.to_string()); }, }; }, + +// delete + + "/delete" => { + match &words.next().unwrap().parse::() { + Err(err) => { + reply.push(format!("I need a number\\.\n{}", &err)); + }, + Ok(number) => { + let result = core.delete(&number, message.from.id).await?; + reply.push(result.to_string()); + }, + }; + }, // disable "/disable" => { match &words.next().unwrap().parse::() {