* Revise Postgres to use `simple_query`

* Fix bug in logging `ENV` config errors

* Improve parsing of values from Postgres

* Finish Postgres changes
This commit is contained in:
Daniel Sockwell 2020-04-23 12:04:30 -04:00 committed by GitHub
parent 016f49a2d8
commit 91186fb9f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 425 additions and 145 deletions

79
Cargo.lock generated
View File

@ -37,6 +37,16 @@ dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "async-trait"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
@ -130,7 +140,7 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -406,7 +416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "flodgatt"
version = "0.8.5"
version = "0.9.0"
dependencies = [
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -414,7 +424,7 @@ dependencies = [
"hashbrown 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres-openssl 0.2.0-rc.1 (git+https://github.com/sfackler/rust-postgres.git)",
"pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -710,7 +720,7 @@ dependencies = [
"h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@ -756,11 +766,10 @@ dependencies = [
[[package]]
name = "iovec"
version = "0.1.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -908,7 +917,7 @@ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -923,7 +932,7 @@ name = "mio-uds"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1159,7 +1168,7 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.1.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -1174,15 +1183,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "postgres"
version = "0.17.0"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-postgres 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-postgres 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1235,7 +1244,7 @@ dependencies = [
[[package]]
name = "postgres-types"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1325,7 +1334,7 @@ name = "r2d2_postgres"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"postgres 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1870,16 +1879,18 @@ dependencies = [
[[package]]
name = "tokio"
version = "0.2.4"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project-lite 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1966,9 +1977,10 @@ dependencies = [
[[package]]
name = "tokio-postgres"
version = "0.5.1"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"async-trait 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1977,11 +1989,11 @@ dependencies = [
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project-lite 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres-protocol 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres-types 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"postgres-types 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2018,7 +2030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2080,7 +2092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2092,15 +2104,15 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.2.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project-lite 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2332,6 +2344,7 @@ dependencies = [
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum async-trait 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "da71fef07bc806586090247e971229289f64c210a278ee5ae419314eb386b31d"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
@ -2412,7 +2425,7 @@ dependencies = [
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
"checksum input_buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e1b822cc844905551931d6f81608ed5f50a79c1078a4e2b4d42dbc7c1eedfbf"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
@ -2460,14 +2473,14 @@ dependencies = [
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
"checksum phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
"checksum pin-project-lite 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e8822eb8bb72452f038ebf6048efa02c3fe22bf83f76519c9583e47fc194a422"
"checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af"
"checksum postgres 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96dd5c8eddec65a5497798ebde2e5c74a93ef8b66782c1b09eeab9bb8538aebc"
"checksum postgres 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18741b59a558e4dfdb9c968e8126dccbefd6a16bf54e3bc5668d420b4c4ed71b"
"checksum postgres-openssl 0.2.0-rc.1 (git+https://github.com/sfackler/rust-postgres.git)" = "<none>"
"checksum postgres-protocol 0.4.1 (git+https://github.com/sfackler/rust-postgres.git)" = "<none>"
"checksum postgres-protocol 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a30f0e172ae0fb0653dbf777ad10a74b8e58d6de95a892f2e1d3e94a9df9a844"
"checksum postgres-types 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1dd99401779ab03bc3872f196fb02c420e76f416c850be494a6f2d67287ad"
"checksum postgres-types 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e634590e8812c500088d88db721195979223dabb05149f43cb50931d0ff5865d"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61"
"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
@ -2543,7 +2556,7 @@ dependencies = [
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20"
"checksum tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "cec6c34409089be085de9403ba2010b80e36938c9ca992c4f67f407bb13db0b1"
"checksum tokio 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bcced6bb623d4bff3739c176c415f13c418f426395c169c9c3cd9a492c715b16"
"checksum tokio 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "34ef16d072d2b6dc8b4a56c70f5c5ced1a37752116f8e7c1e80c659aa7cb6713"
"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e"
@ -2551,7 +2564,7 @@ dependencies = [
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
"checksum tokio-openssl 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771d6246b170ae108d67d9963c23f31a579016c016d73bd4bd7d6ef0252afda7"
"checksum tokio-postgres 0.4.0-rc.3 (git+https://github.com/sfackler/rust-postgres.git)" = "<none>"
"checksum tokio-postgres 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c03cb0c66092269a9b280e9e4956cb23ce00b8a6b1b393f7700f7732ac4bf133"
"checksum tokio-postgres 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "524da2f17264514c854ac770177bdb810f0db7e706ae69f143d6e6828e3c4fe3"
"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce"
"checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a"
"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
@ -2560,7 +2573,7 @@ dependencies = [
"checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3"
"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92"
"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
"checksum tokio-util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930"
"checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum tungstenite 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "577caf571708961603baf59d2e148d12931e0da2e4bb6c5b471dd4a524fef3aa"
"checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"

View File

@ -1,7 +1,7 @@
[package]
name = "flodgatt"
description = "A blazingly fast drop-in replacement for the Mastodon streaming api server"
version = "0.8.5"
version = "0.9.0"
authors = ["Daniel Long Sockwell <daniel@codesections.com", "Julian Laubstein <contact@julianlaubstein.de>"]
edition = "2018"

View File

@ -26,13 +26,25 @@ pub fn merge_dotenv() -> Result<()> {
let res = dotenv::from_filename(env_file);
if let Ok(log_level) = env::var("RUST_LOG") {
if res.is_err() && ["warn", "info", "trace", "debug"].contains(&log_level.as_str()) {
eprintln!(
" WARN: could not load environmental variables from {:?}\n\
{:8}Are you in the right directory? Proceeding with variables from the environment.",
env::current_dir().unwrap_or_else(|_|"./".into()).join(env_file), ""
if ["warn", "info", "trace", "debug"].contains(&log_level.as_str()) {
let env_file = env::current_dir()
.unwrap_or_else(|_| "./".into())
.join(env_file);
);
match res {
Err(dotenv::Error::LineParse(msg, line)) => eprintln!(
" ERROR: could not parse environmental file at {:?}\n\
{:8}could not parse line {}, `{}`",
env_file, "", line, msg
),
Err(dotenv::Error::Io(_)) => eprintln!(
" WARN: could not load environmental variables from {:?}\n\
{:8}Are you in the right directory? Proceeding with variables from the environment.",
env_file, ""
),
Err(_) => eprintln!(" ERROR: could not load environmental file at {:?}", env_file),
Ok(_) => ()
}
}
}
Ok(())

View File

@ -20,7 +20,7 @@ from_env_var!(
from_env_var!(
/// How frequently to poll Redis
let name = RedisInterval;
let default: Duration = Duration::from_millis(100);
let default: Duration = Duration::from_millis(10);
let (env_var, allowed_values) = ("REDIS_FREQ", "a number of milliseconds");
let from_str = |s| s.parse().map(Duration::from_millis).ok();
);

View File

@ -17,6 +17,7 @@ use crate::config::Postgres;
use warp::filters::BoxedFilter;
use warp::http::StatusCode;
use warp::path;
use warp::reply;
use warp::{Filter, Rejection};
#[cfg(test)]
@ -54,7 +55,7 @@ macro_rules! parse_sse_query {
};
}
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Handler {
pg_conn: PgPool,
}
@ -118,14 +119,23 @@ impl Handler {
}
pub fn err(r: Rejection) -> std::result::Result<impl warp::Reply, warp::Rejection> {
let json_err = match r.cause() {
Some(text) if text.to_string() == "Missing request header 'authorization'" => {
warp::reply::json(&"Error: Missing access token".to_string())
}
Some(text) => warp::reply::json(&text.to_string()),
None => warp::reply::json(&"Error: Nonexistant endpoint".to_string()),
use StatusCode as Code;
let (msg, code) = match &r.cause().map(|s| s.to_string()).as_deref() {
Some(PgPool::BAD_TOKEN) => (PgPool::BAD_TOKEN, Code::UNAUTHORIZED),
Some(PgPool::PG_NULL) => (PgPool::PG_NULL, Code::BAD_REQUEST),
Some(PgPool::MISSING_HASHTAG) => (PgPool::MISSING_HASHTAG, Code::BAD_REQUEST),
Some(PgPool::SERVER_ERR) | Some(_) => (PgPool::SERVER_ERR, Code::INTERNAL_SERVER_ERROR),
None if r.is_not_found() => return Err(r),
None => (PgPool::SERVER_ERR, Code::INTERNAL_SERVER_ERROR),
};
Ok(warp::reply::with_status(json_err, StatusCode::UNAUTHORIZED))
if code == Code::INTERNAL_SERVER_ERROR {
log::error!("Internal error: {:?}", &r);
} else {
log::info!("Request rejected: {} - {:?}", code, &r);
};
Ok(reply::with_status(reply::json(&msg), code))
}
}

View File

@ -1,4 +1,5 @@
use std::fmt;
#[derive(Debug)]
pub enum Error {
PgPool(r2d2::Error),
@ -28,7 +29,7 @@ impl From<postgres::Error> for Error {
Self::Pg(e)
}
}
// TODO make Timeline & TimelineErr their own top-level module
#[derive(Debug)]
pub enum Timeline {
MissingHashtag,

View File

@ -4,12 +4,14 @@ use super::timeline::{Scope, UserData};
use crate::config;
use crate::Id;
use ::postgres;
use ::postgres::{self, SimpleQueryMessage};
use hashbrown::HashSet;
use r2d2_postgres::PostgresConnectionManager;
use std::convert::TryFrom;
#[allow(deprecated)] // one fn is deprecated, not whole module
use warp::reject;
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct PgPool {
conn: r2d2::Pool<PostgresConnectionManager<postgres::NoTls>>,
whitelist_mode: bool,
@ -19,6 +21,11 @@ type Result<T> = std::result::Result<T, err::Error>;
type Rejectable<T> = std::result::Result<T, warp::Rejection>;
impl PgPool {
pub(crate) const BAD_TOKEN: &'static str = "Error: Missing access token";
pub(crate) const SERVER_ERR: &'static str = "Error: Internal server error";
pub(crate) const PG_NULL: &'static str = "Error: Unexpected null from Postgres";
pub(crate) const MISSING_HASHTAG: &'static str = "Error: Hashtag does not exist";
pub(crate) fn new(pg_cfg: &config::Postgres, whitelist_mode: bool) -> Result<Self> {
let mut cfg = postgres::Config::new();
cfg.user(&pg_cfg.user)
@ -32,70 +39,93 @@ impl PgPool {
cfg.connect(postgres::NoTls)?; // Test connection, letting us immediately exit with an error
// when Postgres isn't running instead of timing out below
let manager = PostgresConnectionManager::new(cfg, postgres::NoTls);
let pool = r2d2::Pool::builder().max_size(10).build(manager)?;
Ok(Self {
conn: pool,
conn: r2d2::Pool::builder().max_size(10).build(manager)?,
whitelist_mode,
})
}
fn is_safe(txt: &str) -> bool {
txt.chars()
.all(|c| c.is_alphanumeric() || c == '_' || c == '-')
}
pub(crate) fn select_user(self, token: &Option<String>) -> Rejectable<UserData> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
let mut conn = self.conn.get().map_err(reject::custom)?;
if let Some(token) = token {
let query_rows = conn
.query("
if !Self::is_safe(token) {
Err(reject::custom(Self::BAD_TOKEN))?;
};
let rows = conn
.simple_query(&format!("
SELECT oauth_access_tokens.resource_owner_id, users.account_id, users.chosen_languages, oauth_access_tokens.scopes
FROM oauth_access_tokens
INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id
WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL
LIMIT 1",
&[&token.to_owned()],
).map_err(warp::reject::custom)?;
WHERE oauth_access_tokens.token='{}' AND oauth_access_tokens.revoked_at IS NULL
LIMIT 1", &token.to_owned())
).map_err(reject::custom)?;
if let Some(result_columns) = query_rows.get(0) {
let id = Id(result_columns.get(1));
let allowed_langs = result_columns
.try_get::<_, Vec<_>>(2)
.unwrap_or_default()
.into_iter()
.collect();
let row = match rows.get(0) {
Some(postgres::SimpleQueryMessage::Row(row)) => row,
_ => Err(reject::custom(Self::PG_NULL))?, // Wildcard required by #[non_exhaustive]
};
let mut scopes: HashSet<Scope> = result_columns
.get::<_, String>(3)
.split(' ')
.filter_map(|scope| Scope::try_from(scope).ok())
.collect();
// We don't need to separately track read auth - it's just all three others
if scopes.contains(&Scope::Read) {
scopes = vec![Scope::Statuses, Scope::Notifications, Scope::Lists]
.into_iter()
let id = Id(get_col_or_reject(row, 1)?.parse().map_err(reject::custom)?);
let allowed_langs: HashSet<_> = row
.try_get(2)
.map_err(reject::custom)? // looks like `Some("{en,eo,es}")`
.map_or_else(HashSet::new, |str| {
str.trim_start_matches('{')
.trim_end_matches('}')
.split(',')
.map(String::from)
.collect()
}
});
Ok(UserData {
id,
allowed_langs,
scopes,
})
} else {
Err(warp::reject::custom("Error: Invalid access token"))
let mut scopes: HashSet<Scope> = get_col_or_reject(row, 3)?
.split(' ')
.filter_map(|scope| Scope::try_from(scope).ok())
.collect();
// We don't need to separately track read auth - it's just all three others
if scopes.contains(&Scope::Read) {
scopes = vec![Scope::Statuses, Scope::Notifications, Scope::Lists]
.into_iter()
.collect()
}
Ok(UserData {
id,
allowed_langs,
scopes,
})
} else if self.whitelist_mode {
Err(warp::reject::custom("Error: Invalid access token"))
Err(reject::custom(Self::BAD_TOKEN))
} else {
Ok(UserData::public())
}
}
pub(crate) fn select_hashtag_id(self, tag_name: &str) -> Rejectable<i64> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query("SELECT id FROM tags WHERE name = $1 LIMIT 1", &[&tag_name])
.map_err(warp::reject::custom)?
.get(0)
.map(|row| row.get(0))
.ok_or_else(|| warp::reject::custom("Error: Hashtag does not exist."))
if !Self::is_safe(tag_name) {
Err(reject::custom(Self::MISSING_HASHTAG))?;
};
let mut conn = self.conn.get().map_err(reject::custom)?;
let rows = conn
.simple_query(&format!(
"SELECT id FROM tags WHERE name='{}' LIMIT 1",
&tag_name
))
.map_err(reject::custom)?;
match rows.get(0).ok_or_else(|| reject::custom(Self::PG_NULL))? {
SimpleQueryMessage::Row(row) => get_col_or_reject(row, 0),
_ => Err(reject::custom(Self::MISSING_HASHTAG))?,
}
.map(|s| s.parse().map_err(reject::custom))?
}
/// Query Postgres for everyone the user has blocked or muted
@ -103,16 +133,21 @@ LIMIT 1",
/// **NOTE**: because we check this when the user connects, it will not include any blocks
/// the user adds until they refresh/reconnect.
pub(crate) fn select_blocked_users(self, user_id: Id) -> Rejectable<HashSet<Id>> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query(
"SELECT target_account_id FROM blocks WHERE account_id = $1
UNION SELECT target_account_id FROM mutes WHERE account_id = $1",
&[&*user_id],
)
.map_err(warp::reject::custom)?
let mut conn = self.conn.get().map_err(reject::custom)?;
conn.simple_query(&format!(
"SELECT target_account_id FROM blocks WHERE account_id = {0}
UNION SELECT target_account_id FROM mutes WHERE account_id = {0}",
&*user_id
))
.map_err(reject::custom)?
.iter()
.map(|row| Ok(Id(row.get(0))))
.collect()
.try_fold(HashSet::new(), |mut set, row| match row {
SimpleQueryMessage::Row(row) => {
set.insert(get_col_or_reject(row, 0)?.parse().map_err(reject::custom)?);
Ok(set)
}
_ => Ok(set),
})
}
/// Query Postgres for everyone who has blocked the user
@ -120,15 +155,20 @@ LIMIT 1",
/// **NOTE**: because we check this when the user connects, it will not include any blocks
/// the user adds until they refresh/reconnect.
pub(crate) fn select_blocking_users(self, user_id: Id) -> Rejectable<HashSet<Id>> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query(
"SELECT account_id FROM blocks WHERE target_account_id = $1",
&[&*user_id],
)
.map_err(warp::reject::custom)?
let mut conn = self.conn.get().map_err(reject::custom)?;
conn.simple_query(&format!(
"SELECT account_id FROM blocks WHERE target_account_id = {}",
&*user_id
))
.map_err(reject::custom)?
.iter()
.map(|row| Ok(Id(row.get(0))))
.collect()
.try_fold(HashSet::new(), |mut set, row| match row {
SimpleQueryMessage::Row(row) => {
set.insert(get_col_or_reject(row, 0)?.parse().map_err(reject::custom)?);
Ok(set)
}
_ => Ok(set),
})
}
/// Query Postgres for all current domain blocks
@ -136,27 +176,45 @@ LIMIT 1",
/// **NOTE**: because we check this when the user connects, it will not include any blocks
/// the user adds until they refresh/reconnect.
pub(crate) fn select_blocked_domains(self, user_id: Id) -> Rejectable<HashSet<String>> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query(
"SELECT domain FROM account_domain_blocks WHERE account_id = $1",
&[&*user_id],
)
.map_err(warp::reject::custom)?
let mut conn = self.conn.get().map_err(reject::custom)?;
conn.simple_query(&format!(
"SELECT domain FROM account_domain_blocks WHERE account_id = {}",
&*user_id,
))
.map_err(reject::custom)?
.iter()
.map(|row| Ok(row.get(0)))
.collect()
.try_fold(HashSet::new(), |mut set, row| match row {
SimpleQueryMessage::Row(row) => {
set.insert(get_col_or_reject(row, 0)?.to_string());
Ok(set)
}
_ => Ok(set),
})
}
/// Test whether a user owns a list
pub(crate) fn user_owns_list(self, user_id: Id, list_id: i64) -> Rejectable<bool> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
// For the Postgres query, `id` = list number; `account_id` = user.id
let rows = &conn
.query(
"SELECT id, account_id FROM lists WHERE id = $1 LIMIT 1",
&[&list_id],
)
.map_err(warp::reject::custom)?;
Ok(rows.get(0).map_or(false, |row| Id(row.get(1)) == user_id))
let mut conn = self.conn.get().map_err(reject::custom)?;
let rows = conn
.simple_query(&format!(
"SELECT id, account_id FROM lists WHERE id={} LIMIT 1",
&list_id,
))
.map_err(reject::custom)?;
match rows.get(0).ok_or_else(|| reject::custom(Self::PG_NULL))? {
SimpleQueryMessage::Row(row) => {
Ok(Id(get_col_or_reject(row, 1)?.parse().map_err(reject::custom)?) == user_id)
}
_ => Err(reject::custom(Self::MISSING_HASHTAG))?,
}
}
}
fn get_col_or_reject(row: &postgres::row::SimpleQueryRow, col: usize) -> Rejectable<&str> {
Ok(row
.try_get(col)
.map_err(reject::custom)?
.ok_or(reject::custom(PgPool::PG_NULL))?)
}

View File

@ -0,0 +1,169 @@
//! Postgres queries
use super::err;
use super::timeline::{Scope, UserData};
use crate::config;
use crate::event::Id;
use ::postgres;
use hashbrown::HashSet;
use r2d2_postgres::PostgresConnectionManager;
use std::convert::TryFrom;
#[derive(Clone, Debug)]
pub struct PgPool {
conn: r2d2::Pool<PostgresConnectionManager<postgres::NoTls>>,
whitelist_mode: bool,
}
type Result<T> = std::result::Result<T, err::RequestErr>;
type Rejectable<T> = std::result::Result<T, warp::Rejection>;
impl PgPool {
pub(crate) fn new(pg_cfg: &config::Postgres, whitelist_mode: bool) -> Result<Self> {
let mut cfg = postgres::Config::new();
log::info!(
"Connecting to postgres.\nuser: {:?}, password: {:?}",
&pg_cfg.user,
&pg_cfg.password
);
cfg.user(&pg_cfg.user)
.host(&*pg_cfg.host.to_string())
.port(*pg_cfg.port)
.dbname(&pg_cfg.database);
if let Some(password) = &*pg_cfg.password {
cfg.password(password);
};
cfg.connect(postgres::NoTls)?; // Test connection, letting us immediately exit with an error
// when Postgres isn't running instead of timing out below
let manager = PostgresConnectionManager::new(cfg, postgres::NoTls);
let pool = r2d2::Pool::builder().max_size(10).build(manager)?;
Ok(Self {
conn: pool,
whitelist_mode,
})
}
pub(crate) fn select_user(self, token: &Option<String>) -> Rejectable<UserData> {
log::info!("Running `select_user`");
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
log::info!(" got conn");
if let Some(token) = token {
let query_rows = conn
.query("
SELECT oauth_access_tokens.resource_owner_id, users.account_id, users.chosen_languages, oauth_access_tokens.scopes
FROM oauth_access_tokens
INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id
WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL
LIMIT 1",
&[&token.to_owned()],
).map_err(warp::reject::custom)?;
log::info!(" got rows");
if let Some(result_columns) = query_rows.get(0) {
let id = Id(result_columns.get(1));
log::info!(" got id: {:?}", id);
let allowed_langs = result_columns
.try_get::<_, Vec<_>>(2)
.unwrap_or_default()
.into_iter()
.collect();
let mut scopes: HashSet<Scope> = result_columns
.get::<_, String>(3)
.split(' ')
.filter_map(|scope| Scope::try_from(scope).ok())
.collect();
// We don't need to separately track read auth - it's just all three others
if scopes.contains(&Scope::Read) {
scopes = vec![Scope::Statuses, Scope::Notifications, Scope::Lists]
.into_iter()
.collect()
}
Ok(UserData {
id,
allowed_langs,
scopes,
})
} else {
Err(warp::reject::custom("Error: Invalid access token"))
}
} else if self.whitelist_mode {
Err(warp::reject::custom("Error: Invalid access token"))
} else {
Ok(UserData::public())
}
}
pub(crate) fn select_hashtag_id(self, tag_name: &str) -> Rejectable<i64> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query("SELECT id FROM tags WHERE name = $1 LIMIT 1", &[&tag_name])
.map_err(warp::reject::custom)?
.get(0)
.map(|row| row.get(0))
.ok_or_else(|| warp::reject::custom("Error: Hashtag does not exist."))
}
/// Query Postgres for everyone the user has blocked or muted
///
/// **NOTE**: because we check this when the user connects, it will not include any blocks
/// the user adds until they refresh/reconnect.
pub(crate) fn select_blocked_users(self, user_id: Id) -> Rejectable<HashSet<Id>> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query(
"SELECT target_account_id FROM blocks WHERE account_id = $1
UNION SELECT target_account_id FROM mutes WHERE account_id = $1",
&[&*user_id],
)
.map_err(warp::reject::custom)?
.iter()
.map(|row| Ok(Id(row.get(0))))
.collect()
}
/// Query Postgres for everyone who has blocked the user
///
/// **NOTE**: because we check this when the user connects, it will not include any blocks
/// the user adds until they refresh/reconnect.
pub(crate) fn select_blocking_users(self, user_id: Id) -> Rejectable<HashSet<Id>> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query(
"SELECT account_id FROM blocks WHERE target_account_id = $1",
&[&*user_id],
)
.map_err(warp::reject::custom)?
.iter()
.map(|row| Ok(Id(row.get(0))))
.collect()
}
/// Query Postgres for all current domain blocks
///
/// **NOTE**: because we check this when the user connects, it will not include any blocks
/// the user adds until they refresh/reconnect.
pub(crate) fn select_blocked_domains(self, user_id: Id) -> Rejectable<HashSet<String>> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
conn.query(
"SELECT domain FROM account_domain_blocks WHERE account_id = $1",
&[&*user_id],
)
.map_err(warp::reject::custom)?
.iter()
.map(|row| Ok(row.get(0)))
.collect()
}
/// Test whether a user owns a list
pub(crate) fn user_owns_list(self, user_id: Id, list_id: i64) -> Rejectable<bool> {
let mut conn = self.conn.get().map_err(warp::reject::custom)?;
// For the Postgres query, `id` = list number; `account_id` = user.id
let rows = &conn
.query(
"SELECT id, account_id FROM lists WHERE id = $1 LIMIT 1",
&[&list_id],
)
.map_err(warp::reject::custom)?;
Ok(rows.get(0).map_or(false, |row| Id(row.get(1)) == user_id))
}
}

View File

@ -53,6 +53,7 @@ impl TryFrom<&str> for Scope {
}
}
#[derive(Debug, Clone)]
pub(crate) struct UserData {
pub(crate) id: Id,
pub(crate) allowed_langs: HashSet<String>,

View File

@ -29,9 +29,9 @@ impl RedisCmd {
.concat(),
[
b"*3\r\n$3\r\nSET\r\n$",
tl.len().to_string().as_bytes(),
b"\r\n",
tl.as_bytes(),
(tl.len() + "subscribed:".len()).to_string().as_bytes(),
b"\r\nsubscribed:",
tl.to_string().as_bytes(),
b"\r\n$1\r\n1\r\n",
]
.concat(),
@ -47,9 +47,9 @@ impl RedisCmd {
.concat(),
[
b"*3\r\n$3\r\nSET\r\n$",
tl.len().to_string().as_bytes(),
b"\r\n",
tl.as_bytes(),
(tl.len() + "subscribed:".len()).to_string().as_bytes(),
b"\r\nsubscribed:",
tl.to_string().as_bytes(),
b"\r\n$1\r\n0\r\n",
]
.concat(),

View File

@ -63,7 +63,7 @@ impl RedisConn {
}
}
Err(e) if matches!(e.kind(), io::ErrorKind::WouldBlock) => {
return Ok(Async::NotReady);
break;
}
Err(e) => break log::error!("{}", e),
};
@ -96,19 +96,18 @@ impl RedisConn {
}
Some(_non_matching_namespace) => (Ok(Ready(None)), msg.leftover_input),
},
Ok(NonMsg(leftover)) => (Ok(Ready(None)), leftover),
Err(RedisParseErr::Incomplete) => (Ok(NotReady), input),
Err(other_parse_err) => (Err(ManagerErr::RedisParseErr(other_parse_err)), input),
};
self.cursor = [leftover.as_bytes(), invalid_bytes]
.concat()
.bytes()
.fold(0, |acc, cur| {
// TODO - make clearer and comment side-effect
self.redis_input[acc] = cur.expect("TODO");
acc + 1
});
// Store leftover in same buffer and set cursor to start after leftover next time
self.cursor = 0;
for byte in [leftover.as_bytes(), invalid_bytes].concat().iter() {
self.redis_input[self.cursor] = *byte;
self.cursor += 1;
}
res
}
@ -123,6 +122,12 @@ impl RedisConn {
let (primary_cmd, secondary_cmd) = cmd.into_sendable(&tl);
self.primary.write_all(&primary_cmd)?;
// We also need to set a key to tell the Puma server that we've subscribed
// or unsubscribed to the channel because it stops publishing updates when it
// thinks no one is subscribed. (Documented in [PR
// #3278](https://github.com/tootsuite/mastodon/pull/3278))
// Question: why can't the Puma server just use NUMSUB for this?
self.secondary.write_all(&secondary_cmd)?;
Ok(())
}

View File

@ -53,6 +53,7 @@ impl Ws {
let incoming_events = self.ws_rx.clone().map_err(|_| ());
incoming_events.for_each(move |(tl, event)| {
//TODO log::info!("{:?}, {:?}", &tl, &event);
if matches!(event, Event::Ping) {
self.send_msg(&event)?
} else if target_timeline == tl {
@ -67,20 +68,30 @@ impl Ws {
}
fn send_or_filter(&mut self, tl: Timeline, event: &Event, update: &impl Payload) -> Result<()> {
let blocks = &self.subscription.blocks;
let allowed_langs = &self.subscription.allowed_langs;
let (blocks, allowed_langs) = (&self.subscription.blocks, &self.subscription.allowed_langs);
const SKIP: Result<()> = Ok(());
match tl {
tl if tl.is_public()
&& !update.language_unset()
&& !allowed_langs.is_empty()
&& !allowed_langs.contains(&update.language()) =>
{
log::info!("{:?} msg skipped - disallowed language", tl);
SKIP
}
tl if !blocks.blocked_users.is_disjoint(&update.involved_users()) => {
log::info!("{:?} msg skipped - involves blocked user", tl);
SKIP
}
tl if blocks.blocking_users.contains(update.author()) => {
log::info!("{:?} msg skipped - from blocking user", tl);
SKIP
}
tl if blocks.blocked_domains.contains(update.sent_from()) => {
log::info!("{:?} msg skipped - from blocked domain", tl);
SKIP
}
_ if !blocks.blocked_users.is_disjoint(&update.involved_users()) => SKIP,
_ if blocks.blocking_users.contains(update.author()) => SKIP,
_ if blocks.blocked_domains.contains(update.sent_from()) => SKIP,
_ => Ok(self.send_msg(&event)?),
}
}