diff --git a/.cargo/config b/.cargo/config index 5dbf2c8..bff29e6 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,2 @@ [build] -# rustflags = ["--cfg", "tokio_unstable"] +rustflags = ["--cfg", "tokio_unstable"] diff --git a/.drone.yml b/.drone.yml index a486d75..d1c5c83 100644 --- a/.drone.yml +++ b/.drone.yml @@ -22,7 +22,7 @@ steps: pull: always commands: - rustup component add clippy - - cargo clippy -- -D warnings + - cargo clippy --no-deps -- -D warnings trigger: event: diff --git a/Cargo.lock b/Cargo.lock index 0a02148..3dd5d19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "activitystreams" -version = "0.7.0-alpha.24" +version = "0.7.0-alpha.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e673a517c3cd11c3b1870be31f2c95580e30f9ca79e89082ba94325097ed9c4" +checksum = "9c140d4bd704e9acd758c4392e222af44c66d1a29165937c9b33c7df7b697678" dependencies = [ "activitystreams-kinds", "iri-string", @@ -43,7 +43,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes", "futures-core", "futures-sink", @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.3.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" +checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" dependencies = [ "actix-codec", "actix-rt", @@ -66,8 +66,8 @@ dependencies = [ "actix-tls", "actix-utils", "ahash 0.8.3", - "base64 0.21.2", - "bitflags", + "base64 0.21.3", + "bitflags 2.4.0", "brotli", "bytes", "bytestring", @@ -95,12 +95,12 @@ dependencies = [ [[package]] name = "actix-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.31", ] [[package]] @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "actix-macros", "futures-core", @@ -129,9 +129,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" dependencies = [ "actix-rt", "actix-service", @@ -139,8 +139,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "num_cpus", - "socket2", + "socket2 0.5.3", "tokio", "tracing", ] @@ -158,20 +157,22 @@ dependencies = [ [[package]] name = "actix-tls" -version = "3.0.3" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fde0cf292f7cdc7f070803cb9a0d45c018441321a78b1042ffbbb81ec333297" +checksum = "72616e7fbec0aa99c6f3164677fa48ff5a60036d0799c98cab894a44f3e0efc3" dependencies = [ - "actix-codec", "actix-rt", "actix-service", "actix-utils", "futures-core", - "http", - "log", + "impl-more", "pin-project-lite", - "tokio-rustls 0.23.4", + "rustls", + "rustls-webpki", + "tokio", + "tokio-rustls", "tokio-util", + "tracing", "webpki-roots", ] @@ -187,9 +188,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.3.1" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" +checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" dependencies = [ "actix-codec", "actix-http", @@ -199,7 +200,7 @@ dependencies = [ "actix-service", "actix-tls", "actix-utils", - "ahash 0.7.6", + "ahash 0.8.3", "bytes", "bytestring", "cfg-if", @@ -207,7 +208,6 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "http", "itoa", "language-tags", "log", @@ -219,25 +219,33 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.5.3", "time", "url", ] [[package]] name = "actix-webfinger" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e64f0f9b28305d38058daaff76a608684a43cbf67e9a9289bdd124a2a45b5e" +checksum = "74a22b44deff50693521b489885151fd65a2a596f7aef6d8c0753485b8915082" dependencies = [ "actix-rt", "actix-web", - "awc", "serde", "serde_derive", "thiserror", ] +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -278,9 +286,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -300,6 +308,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "ammonia" version = "3.3.0" @@ -313,32 +327,25 @@ dependencies = [ "url", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -360,9 +367,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys", @@ -370,13 +377,13 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "ap-relay" -version = "0.3.85" +version = "0.3.104" dependencies = [ "activitystreams", "activitystreams-ext", @@ -385,17 +392,17 @@ dependencies = [ "actix-webfinger", "ammonia", "anyhow", - "awc", "background-jobs", - "base64 0.21.2", + "base64 0.21.3", "bcrypt", "clap", "config", "console-subscriber", "dashmap", "dotenv", - "futures-util", + "flume", "http-signature-normalization-actix", + "http-signature-normalization-reqwest", "lru", "metrics", "metrics-exporter-prometheus", @@ -407,22 +414,26 @@ dependencies = [ "pin-project-lite", "quanta", "rand", + "reqwest", + "reqwest-middleware", + "reqwest-tracing", + "ring", "rsa", "rsa-magic-public-key", "ructe", - "rustls 0.20.8", + "rustls", "rustls-pemfile", "serde", "serde_json", "sled", + "streem", "teloxide", "thiserror", "time", "tokio", - "toml 0.7.4", + "toml 0.7.8", "tracing", "tracing-actix-web", - "tracing-awc", "tracing-error", "tracing-futures", "tracing-log", @@ -450,37 +461,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -489,49 +478,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "awc" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ef547a81796eb2dfe9b345aba34c2e08391a0502493711395b36dd64052b69" -dependencies = [ - "actix-codec", - "actix-http", - "actix-rt", - "actix-service", - "actix-tls", - "actix-utils", - "ahash 0.7.6", - "base64 0.21.2", - "bytes", - "cfg-if", - "derive_more", - "futures-core", - "futures-util", - "h2", - "http", - "itoa", - "log", - "mime", - "percent-encoding", - "pin-project-lite", - "rand", - "rustls 0.20.8", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", -] - [[package]] name = "axum" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -618,6 +573,21 @@ dependencies = [ "uuid", ] +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -626,9 +596,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "base64ct" @@ -638,11 +608,11 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bcrypt" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9df288bec72232f78c1ec5fe4e8f1d108aa0265476e93097593c803c8c02062a" +checksum = "28d1c9c15093eb224f0baa400f38fcd713fc1391a6f1c389d886beef146d60a3" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "blowfish", "getrandom", "subtle", @@ -655,6 +625,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.4" @@ -715,9 +691,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" @@ -730,9 +706,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -742,11 +721,10 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ - "android-tzdata", "num-traits", ] @@ -762,45 +740,43 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.6" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6320c6d1c98b6981da7bb2dcecbd0be9dc98d42165fa8326b21000f7dbfde6d0" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.5" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "colorchoice" @@ -835,15 +811,15 @@ checksum = "c2895653b4d9f1538a83970077cb01dfc77a4810524e51a110944688e916b18e" dependencies = [ "prost", "prost-types", - "tonic 0.9.2", + "tonic", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ab2224a0311582eb03adba4caaf18644f7b1f10a760803a803b9b605187fc7" +checksum = "d4cf42660ac07fcebed809cfe561dd8730bcd35b075215e6479c516bcd0d11cb" dependencies = [ "console-api", "crossbeam-channel", @@ -857,7 +833,7 @@ dependencies = [ "thread_local", "tokio", "tokio-stream", - "tonic 0.9.2", + "tonic", "tracing", "tracing-core", "tracing-subscriber", @@ -865,9 +841,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "convert_case" @@ -877,9 +853,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -942,7 +918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "874c6e2d19f8d4a285083b11a3241bfbe01ac3ed85f26e1e6b34888d960552bd" dependencies = [ "derive_more", - "indexmap", + "indexmap 1.9.3", "nom", ] @@ -983,12 +959,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.0", "lock_api", "once_cell", "parking_lot_core 0.9.8", @@ -996,15 +972,24 @@ dependencies = [ [[package]] name = "der" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", "pem-rfc7468", "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +dependencies = [ + "serde", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1052,15 +1037,15 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -1071,6 +1056,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "erasable" version = "1.2.1" @@ -1081,27 +1072,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -1110,23 +1080,32 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1218,7 +1197,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -1277,15 +1256,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] -name = "h2" -version = "0.3.19" +name = "gimli" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "h2" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -1293,7 +1280,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1311,13 +1298,23 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" dependencies = [ "ahash 0.8.3", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash 0.8.3", + "allocator-api2", +] + [[package]] name = "hdrhistogram" version = "7.5.2" @@ -1339,18 +1336,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "html5ever" @@ -1399,18 +1387,18 @@ dependencies = [ [[package]] name = "http-signature-normalization-actix" -version = "0.8.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dc95d9ca3b4e2f93a97e5ccf9f26992c69a272e0abad8807180f0a9e9b59e31" +checksum = "c8d7de237db731e75fbfa0ebeeb70e366f5f9cdcf45af4a41eca8516b80162ca" dependencies = [ "actix-http", "actix-rt", "actix-web", - "awc", "base64 0.13.1", - "futures-util", + "futures-core", "http-signature-normalization", - "sha2", + "ring", + "streem", "thiserror", "tokio", "tracing", @@ -1418,6 +1406,22 @@ dependencies = [ "tracing-futures", ] +[[package]] +name = "http-signature-normalization-reqwest" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cfb84663420ec12c4422820bfdf5e8e5e57467892587f43ac432e73ebce880" +dependencies = [ + "async-trait", + "base64 0.13.1", + "http-signature-normalization", + "httpdate", + "reqwest", + "reqwest-middleware", + "ring", + "thiserror", +] + [[package]] name = "httparse" version = "1.8.0" @@ -1426,9 +1430,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -1438,9 +1442,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -1453,7 +1457,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1462,15 +1466,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", - "rustls 0.21.2", + "rustls", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", ] [[package]] @@ -1501,6 +1506,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "impl-more" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" + [[package]] name = "indexmap" version = "1.9.3" @@ -1511,6 +1522,16 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "inout" version = "0.1.3" @@ -1529,22 +1550,11 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys", -] - [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "iri-string" @@ -1556,18 +1566,6 @@ dependencies = [ "serde", ] -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys", -] - [[package]] name = "itertools" version = "0.9.0" @@ -1587,10 +1585,19 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.6" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" @@ -1624,14 +1631,14 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin", + "spin 0.5.2", ] [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libm" @@ -1645,12 +1652,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "local-channel" version = "0.1.3" @@ -1681,17 +1682,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.14.0", ] [[package]] @@ -1735,14 +1736,14 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" [[package]] name = "md5" @@ -1752,9 +1753,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "memoffset" @@ -1767,9 +1768,9 @@ dependencies = [ [[package]] name = "metrics" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa8ebbd1a9e57bbab77b9facae7f5136aea44c356943bf9a198f647da64285d6" +checksum = "fde3af1a009ed76a778cb84fdef9e7dbbdf5775ae3e4cc1f434a6a307f6f76c5" dependencies = [ "ahash 0.8.3", "metrics-macros", @@ -1782,9 +1783,9 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a4964177ddfdab1e3a2b37aec7cf320e14169abb0ed73999f558136409178d5" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "hyper", - "indexmap", + "indexmap 1.9.3", "ipnet", "metrics", "metrics-util", @@ -1801,20 +1802,20 @@ checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "metrics-util" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111cb375987443c3de8d503580b536f77dc8416d32db62d9456db5d93bd7ac47" +checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick 1.0.5", "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.13.2", - "indexmap", + "hashbrown 0.13.1", + "indexmap 1.9.3", "metrics", "num_cpus", "ordered-float", @@ -1890,6 +1891,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + [[package]] name = "never" version = "0.1.0" @@ -1933,9 +1943,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -1944,9 +1954,9 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ "byteorder", "lazy_static", @@ -1995,9 +2005,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", "libm", @@ -2005,14 +2015,23 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -2021,9 +2040,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opentelemetry" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" +checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" dependencies = [ "opentelemetry_api", "opentelemetry_sdk", @@ -2031,45 +2050,54 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af72d59a4484654ea8eb183fea5ae4eb6a41d7ac3e3bae5f4d2a282a3a7d3ca" +checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275" dependencies = [ "async-trait", - "futures", - "futures-util", + "futures-core", "http", - "opentelemetry", "opentelemetry-proto", + "opentelemetry-semantic-conventions", + "opentelemetry_api", + "opentelemetry_sdk", "prost", "thiserror", "tokio", - "tonic 0.8.3", + "tonic", ] [[package]] name = "opentelemetry-proto" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045f8eea8c0fa19f7d48e7bc3128a39c2e5c533d5c61298c548dfefc1064474c" +checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" dependencies = [ - "futures", - "futures-util", - "opentelemetry", + "opentelemetry_api", + "opentelemetry_sdk", "prost", - "tonic 0.8.3", + "tonic", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" +dependencies = [ + "opentelemetry", ] [[package]] name = "opentelemetry_api" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" +checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b" dependencies = [ - "fnv", "futures-channel", "futures-util", - "indexmap", + "indexmap 1.9.3", + "js-sys", "once_cell", "pin-project-lite", "thiserror", @@ -2078,21 +2106,22 @@ dependencies = [ [[package]] name = "opentelemetry_sdk" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" +checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026" dependencies = [ "async-trait", "crossbeam-channel", - "dashmap", - "fnv", "futures-channel", "futures-executor", "futures-util", "once_cell", "opentelemetry_api", + "ordered-float", "percent-encoding", "rand", + "regex", + "serde_json", "thiserror", "tokio", "tokio-stream", @@ -2100,9 +2129,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "3.7.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc2dbde8f8a79f2102cc474ceb0ad68e3b80b85289ea62389b60e66777e4213" +checksum = "2a54938017eacd63036332b4ae5c8a49fc8c0c1d6d629893057e4f13609edd06" dependencies = [ "num-traits", ] @@ -2184,9 +2213,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pathdiff" @@ -2211,19 +2240,20 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.0" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" +checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.0" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" +checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" dependencies = [ "pest", "pest_generator", @@ -2231,22 +2261,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.0" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" +checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "pest_meta" -version = "2.7.0" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" +checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" dependencies = [ "once_cell", "pest", @@ -2293,29 +2323,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -2346,9 +2376,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.3.3" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" [[package]] name = "ppv-lite86" @@ -2388,9 +2418,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -2445,9 +2475,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -2498,7 +2528,7 @@ version = "10.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2516,7 +2546,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2525,18 +2555,19 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.8.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ - "aho-corasick 1.0.2", + "aho-corasick 1.0.5", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.8", + "regex-syntax 0.7.5", ] [[package]] @@ -2548,6 +2579,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick 1.0.5", + "memchr", + "regex-syntax 0.7.5", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -2556,17 +2598,17 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "bytes", "encoding_rs", "futures-core", @@ -2584,13 +2626,13 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.2", + "rustls", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", "tokio-util", "tower-service", "url", @@ -2602,6 +2644,37 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest-middleware" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff44108c7925d082f2861e683a88618b68235ad9cdc60d64d9d1188efc951cdb" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror", +] + +[[package]] +name = "reqwest-tracing" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b1e66540e0cac90acadaf7109bf99c90d95abcc94b4c096bfa16a2d7aa7a71" +dependencies = [ + "anyhow", + "async-trait", + "getrandom", + "matchit", + "reqwest", + "reqwest-middleware", + "task-local-extensions", + "tracing", +] + [[package]] name = "ring" version = "0.16.20" @@ -2611,7 +2684,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -2624,7 +2697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" dependencies = [ "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "serde", ] @@ -2644,7 +2717,6 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core", - "sha2", "signature", "spki", "subtle", @@ -2657,7 +2729,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ca6a6947c6fe6454c93c3bb65b92f9680e6f9e906e75e30631110f2227344c" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "num-bigint-dig", "rsa", "thiserror", @@ -2665,9 +2737,9 @@ dependencies = [ [[package]] name = "rsass" -version = "0.27.0" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a43695dd28122f6c684273de89796a56a98e02e9694b8ab57b160fdc6e6d69af" +checksum = "0e5c4ce6e9720b51f90dbd5f38c011d0e409fab722ee6b9bb15f5e5550500353" dependencies = [ "arc-swap", "fastrand", @@ -2682,13 +2754,13 @@ dependencies = [ [[package]] name = "ructe" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c86c1631418815c5947a34be5872806586c65398754ec91cc2df35a8e26ba8" +checksum = "9b0a930679d54e46fa4e66be3d9a333026da04d2b659e42aab4dfd1586452815" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "bytecount", - "itertools 0.10.5", + "itertools 0.11.0", "md5", "mime", "nom", @@ -2705,6 +2777,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -2720,37 +2798,11 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.37.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", "ring", @@ -2760,18 +2812,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", ] [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ "ring", "untrusted", @@ -2779,21 +2831,21 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -2807,35 +2859,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2" dependencies = [ "itoa", "ryu", @@ -2844,9 +2896,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -2927,9 +2979,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "sketches-ddsketch" @@ -2939,9 +2991,9 @@ checksum = "68a406c1882ed7f29cd5e248c9848a80e7cb6ae0fea82346d2746f2f941c07e1" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -2964,9 +3016,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "socket2" @@ -2978,12 +3030,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" version = "0.7.2" @@ -2994,6 +3065,16 @@ dependencies = [ "der", ] +[[package]] +name = "streem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "641396a5ae90767cb12d21832444ab760841ee887717d802b2c456c4f8199114" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "string_cache" version = "0.8.7" @@ -3045,9 +3126,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -3072,6 +3153,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e" +[[package]] +name = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + [[package]] name = "teloxide" version = "0.12.2" @@ -3104,7 +3194,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "303db260110c238e3af77bb9dff18bf7a5b5196f783059b0852aab75f91d5a16" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes", "chrono", "derive_more", @@ -3154,22 +3244,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -3184,10 +3274,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -3202,9 +3293,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" dependencies = [ "time-core", ] @@ -3226,18 +3317,18 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.3", "tokio-macros", "tracing", "windows-sys", @@ -3261,18 +3352,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.8", - "tokio", - "webpki", + "syn 2.0.31", ] [[package]] @@ -3281,7 +3361,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.2", + "rustls", "tokio", ] @@ -3321,9 +3401,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.4" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", @@ -3333,58 +3413,26 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", "winnow", ] -[[package]] -name = "tonic" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "prost-derive", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - [[package]] name = "tonic" version = "0.9.2" @@ -3393,7 +3441,7 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-trait", "axum", - "base64 0.21.2", + "base64 0.21.3", "bytes", "futures-core", "futures-util", @@ -3421,7 +3469,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand", @@ -3460,9 +3508,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce52ffaf2d544e317d3bef63f49a6a22022866505fa4840a4339b1756834a2a9" +checksum = "5c0b08ce08cbde6a96fc1e4ebb8132053e53ec7a5cd27eef93ede6b73ebbda06" dependencies = [ "actix-web", "pin-project", @@ -3478,22 +3526,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", -] - -[[package]] -name = "tracing-awc" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa1a68fce4d1a7fad459f81ddcafbdd7c6f6bcda5c7e07d5f42db637931fac7" -dependencies = [ - "actix-http", - "actix-service", - "awc", - "bytes", - "futures-core", - "pin-project-lite", - "tracing", + "syn 2.0.31", ] [[package]] @@ -3539,12 +3572,14 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600" +checksum = "75327c6b667828ddc28f5e3f169036cb793c3f588d83bf0f262a7f062ffed3c8" dependencies = [ "once_cell", "opentelemetry", + "opentelemetry_sdk", + "smallvec", "tracing", "tracing-core", "tracing-log", @@ -3583,15 +3618,15 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] @@ -3604,9 +3639,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -3625,9 +3660,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -3637,9 +3672,9 @@ dependencies = [ [[package]] name = "urlencoding" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "utf-8" @@ -3655,9 +3690,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.4" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom", "serde", @@ -3711,7 +3746,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", "wasm-bindgen-shared", ] @@ -3745,7 +3780,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3758,9 +3793,9 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-streams" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" dependencies = [ "futures-util", "js-sys", @@ -3779,24 +3814,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "winapi" @@ -3831,9 +3853,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3846,62 +3868,63 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d6358f9..603b5ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ap-relay" description = "A simple activitypub relay" -version = "0.3.85" +version = "0.3.104" authors = ["asonix "] license = "AGPL-3.0" readme = "README.md" @@ -23,25 +23,20 @@ default = [] [dependencies] anyhow = "1.0" actix-rt = "2.7.0" -actix-web = { version = "4.0.1", default-features = false, features = [ - "rustls", - "compress-brotli", - "compress-gzip", -] } -actix-webfinger = "0.4.0" -activitystreams = "0.7.0-alpha.21" +actix-web = { version = "4.4.0", default-features = false, features = ["compress-brotli", "compress-gzip", "rustls-0_21"] } +actix-webfinger = { version = "0.5.0", default-features = false } +activitystreams = "0.7.0-alpha.25" activitystreams-ext = "0.1.0-alpha.3" ammonia = "3.1.0" -awc = { version = "3.0.0", default-features = false, features = ["rustls"] } -bcrypt = "0.14" +bcrypt = "0.15" base64 = "0.21" clap = { version = "4.0.0", features = ["derive"] } config = "0.13.0" console-subscriber = { version = "0.1", optional = true } dashmap = "5.1.0" dotenv = "0.15.0" -futures-util = "0.3.17" -lru = "0.10.0" +flume = "0.11.0" +lru = "0.11.0" metrics = "0.21.0" metrics-exporter-prometheus = { version = "0.12.0", default-features = false, features = [ "http-listener", @@ -49,14 +44,18 @@ metrics-exporter-prometheus = { version = "0.12.0", default-features = false, fe metrics-util = "0.15.0" mime = "0.3.16" minify-html = "0.11.0" -opentelemetry = { version = "0.19", features = ["rt-tokio"] } -opentelemetry-otlp = "0.12" +opentelemetry = { version = "0.20", features = ["rt-tokio"] } +opentelemetry-otlp = "0.13" pin-project-lite = "0.2.9" quanta = "0.11.0" rand = "0.8" -rsa = { version = "0.9", features = ["sha2"] } +reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "stream"]} +reqwest-middleware = "0.2" +reqwest-tracing = "0.4.5" +ring = "0.16.20" +rsa = { version = "0.9" } rsa-magic-public-key = "0.8.0" -rustls = "0.20.7" +rustls = "0.21.0" rustls-pemfile = "1.0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" @@ -69,11 +68,10 @@ teloxide = { version = "0.12.0", default-features = false, features = [ thiserror = "1.0" time = { version = "0.3.17", features = ["serde"] } tracing = "0.1" -tracing-awc = "0.1.7" tracing-error = "0.2" tracing-futures = "0.2" tracing-log = "0.1" -tracing-opentelemetry = "0.19" +tracing-opentelemetry = "0.21" tracing-subscriber = { version = "0.3", features = [ "ansi", "env-filter", @@ -81,6 +79,7 @@ tracing-subscriber = { version = "0.3", features = [ ] } tokio = { version = "1", features = ["macros", "sync"] } uuid = { version = "1", features = ["v4", "serde"] } +streem = "0.1.0" [dependencies.background-jobs] version = "0.15.0" @@ -88,17 +87,22 @@ default-features = false features = ["background-jobs-actix", "error-logging"] [dependencies.http-signature-normalization-actix] -version = "0.8.0" +version = "0.10.1" default-features = false -features = ["client", "server", "sha-2"] +features = ["server", "ring"] + +[dependencies.http-signature-normalization-reqwest] +version = "0.10.0" +default-features = false +features = ["middleware", "ring"] [dependencies.tracing-actix-web] -version = "0.7.5" +version = "0.7.6" [build-dependencies] anyhow = "1.0" dotenv = "0.15.0" -ructe = { version = "0.16.0", features = ["sass", "mime03"] } +ructe = { version = "0.17.0", features = ["sass", "mime03"] } toml = "0.7.0" [profile.dev.package.rsa] diff --git a/README.md b/README.md index 66a6544..72c2e22 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,9 @@ LOCAL_DOMAINS=masto.asonix.dog LOCAL_BLURB="

Welcome to my cool relay where I have cool relay things happening. I hope you enjoy your stay!

" PROMETHEUS_ADDR=0.0.0.0 PROMETHEUS_PORT=9000 -CLIENT_POOL_SIZE=20 +CLIENT_TIMEOUT=10 +DELIVER_CONCURRENCY=8 +SIGNATURE_THREADS=2 ``` #### Descriptions @@ -155,11 +157,22 @@ Optional - description for the relay Optional - Address to bind to for serving the prometheus scrape endpoint ##### `PROMETHEUS_PORT` Optional - Port to bind to for serving the prometheus scrape endpoint -##### `CLIENT_POOL_SIZE` -Optional - How many connections the relay should maintain per thread. This value will be multiplied -by the number of cores available to the relay. This defaults to 20, so a 4-core machine will have a -maximum of 160 simultaneous outbound connections. If you run into problems related to "Too many open -files", you can either decrease this number or increase the ulimit for your system. +##### `CLIENT_TIMEOUT` +Optional - How long the relay will hold open a connection (in seconds) to a remote server during +fetches and deliveries. This defaults to 10 +##### `DELIVER_CONCURRENCY` +Optional - How many deliver requests the relay should allow to be in-flight per thread. the default +is 8 +##### `SIGNATURE_THREADS` +Optional - Override number of threads used for signing and verifying requests. Default is +`std::thread::available_parallelism()` (It tries to detect how many cores you have). If it cannot +detect the correct number of cores, it falls back to 1. +##### 'PROXY_URL' +Optional - URL of an HTTP proxy to forward outbound requests through +##### 'PROXY_USERNAME' +Optional - username to provide to the HTTP proxy set with `PROXY_URL` through HTTP Basic Auth +##### 'PROXY_PASSWORD' +Optional - password to provide to the HTTP proxy set with `PROXY_URL` through HTTP Basic Auth ### Subscribing Mastodon admins can subscribe to this relay by adding the `/inbox` route to their relay settings. diff --git a/flake.lock b/flake.lock index 0cb587b..2a20bfa 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1687171271, - "narHash": "sha256-BJlq+ozK2B1sJDQXS3tzJM5a+oVZmi1q0FlBK/Xqv7M=", + "lastModified": 1692799911, + "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", "owner": "numtide", "repo": "flake-utils", - "rev": "abfb11bd1aec8ced1c9bb9adfe68018230f4fb3c", + "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1687412861, - "narHash": "sha256-Z/g0wbL68C+mSGerYS2quv9FXQ1RRP082cAC0Bh4vcs=", + "lastModified": 1693003285, + "narHash": "sha256-5nm4yrEHKupjn62MibENtfqlP6pWcRTuSKrMiH9bLkc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e603dc5f061ca1d8a19b3ede6a8cf9c9fcba6cdc", + "rev": "5690c4271f2998c304a45c91a0aeb8fb69feaea7", "type": "github" }, "original": { diff --git a/relay.nix b/relay.nix index 08d4a73..487fa65 100644 --- a/relay.nix +++ b/relay.nix @@ -6,19 +6,20 @@ rustPlatform.buildRustPackage { pname = "relay"; - version = "0.3.85"; + version = "0.3.104"; src = ./.; cargoLock.lockFile = ./Cargo.lock; PROTOC = "${protobuf}/bin/protoc"; PROTOC_INCLUDE = "${protobuf}/include"; + RUSTFLAGS = "--cfg tokio_unstable"; nativeBuildInputs = [ ]; passthru.tests = { inherit (nixosTests) relay; }; meta = with lib; { - description = "A simple image hosting service"; + description = "An ActivityPub relay"; homepage = "https://git.asonix.dog/asonix/relay"; license = with licenses; [ agpl3Plus ]; }; diff --git a/src/admin/client.rs b/src/admin/client.rs index fdb1687..88151e1 100644 --- a/src/admin/client.rs +++ b/src/admin/client.rs @@ -3,12 +3,14 @@ use crate::{ collector::Snapshot, config::{AdminUrlKind, Config}, error::{Error, ErrorKind}, + extractors::XApiToken, }; -use awc::Client; +use actix_web::http::header::Header; +use reqwest_middleware::ClientWithMiddleware; use serde::de::DeserializeOwned; pub(crate) async fn allow( - client: &Client, + client: &ClientWithMiddleware, config: &Config, domains: Vec, ) -> Result<(), Error> { @@ -16,7 +18,7 @@ pub(crate) async fn allow( } pub(crate) async fn disallow( - client: &Client, + client: &ClientWithMiddleware, config: &Config, domains: Vec, ) -> Result<(), Error> { @@ -24,7 +26,7 @@ pub(crate) async fn disallow( } pub(crate) async fn block( - client: &Client, + client: &ClientWithMiddleware, config: &Config, domains: Vec, ) -> Result<(), Error> { @@ -32,35 +34,50 @@ pub(crate) async fn block( } pub(crate) async fn unblock( - client: &Client, + client: &ClientWithMiddleware, config: &Config, domains: Vec, ) -> Result<(), Error> { post_domains(client, config, domains, AdminUrlKind::Unblock).await } -pub(crate) async fn allowed(client: &Client, config: &Config) -> Result { +pub(crate) async fn allowed( + client: &ClientWithMiddleware, + config: &Config, +) -> Result { get_results(client, config, AdminUrlKind::Allowed).await } -pub(crate) async fn blocked(client: &Client, config: &Config) -> Result { +pub(crate) async fn blocked( + client: &ClientWithMiddleware, + config: &Config, +) -> Result { get_results(client, config, AdminUrlKind::Blocked).await } -pub(crate) async fn connected(client: &Client, config: &Config) -> Result { +pub(crate) async fn connected( + client: &ClientWithMiddleware, + config: &Config, +) -> Result { get_results(client, config, AdminUrlKind::Connected).await } -pub(crate) async fn stats(client: &Client, config: &Config) -> Result { +pub(crate) async fn stats( + client: &ClientWithMiddleware, + config: &Config, +) -> Result { get_results(client, config, AdminUrlKind::Stats).await } -pub(crate) async fn last_seen(client: &Client, config: &Config) -> Result { +pub(crate) async fn last_seen( + client: &ClientWithMiddleware, + config: &Config, +) -> Result { get_results(client, config, AdminUrlKind::LastSeen).await } async fn get_results( - client: &Client, + client: &ClientWithMiddleware, config: &Config, url_kind: AdminUrlKind, ) -> Result { @@ -68,9 +85,9 @@ async fn get_results( let iri = config.generate_admin_url(url_kind); - let mut res = client + let res = client .get(iri.as_str()) - .insert_header(x_api_token) + .header(XApiToken::name(), x_api_token.to_string()) .send() .await .map_err(|e| ErrorKind::SendRequest(iri.to_string(), e.to_string()))?; @@ -88,7 +105,7 @@ async fn get_results( } async fn post_domains( - client: &Client, + client: &ClientWithMiddleware, config: &Config, domains: Vec, url_kind: AdminUrlKind, @@ -99,8 +116,9 @@ async fn post_domains( let res = client .post(iri.as_str()) - .insert_header(x_api_token) - .send_json(&Domains { domains }) + .header(XApiToken::name(), x_api_token.to_string()) + .json(&Domains { domains }) + .send() .await .map_err(|e| ErrorKind::SendRequest(iri.to_string(), e.to_string()))?; diff --git a/src/collector.rs b/src/collector.rs index 56a533d..b5674c7 100644 --- a/src/collector.rs +++ b/src/collector.rs @@ -159,7 +159,7 @@ impl Snapshot { let entry = merging.entry(name).or_insert_with(HashMap::new); for counter in counters { - let mut merge_counter = entry + let merge_counter = entry .entry(counter.labels.clone()) .or_insert_with(MergeCounter::default); if key == *start { diff --git a/src/config.rs b/src/config.rs index bf58533..35520fd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,8 +11,7 @@ use activitystreams::{ }, }; use config::Environment; -use http_signature_normalization_actix::prelude::VerifyDigest; -use rsa::sha2::{Digest, Sha256}; +use http_signature_normalization_actix::{digest::ring::Sha256, prelude::VerifyDigest}; use rustls::{Certificate, PrivateKey}; use std::{ io::BufReader, @@ -45,7 +44,12 @@ pub(crate) struct ParsedConfig { local_blurb: Option, prometheus_addr: Option, prometheus_port: Option, - client_pool_size: usize, + deliver_concurrency: u64, + client_timeout: u64, + proxy_url: Option, + proxy_username: Option, + proxy_password: Option, + signature_threads: Option, } #[derive(Clone)] @@ -69,7 +73,10 @@ pub struct Config { local_domains: Vec, local_blurb: Option, prometheus_config: Option, - client_pool_size: usize, + deliver_concurrency: u64, + client_timeout: u64, + proxy_config: Option, + signature_threads: Option, } #[derive(Clone)] @@ -84,6 +91,12 @@ struct PrometheusConfig { port: u16, } +#[derive(Clone, Debug)] +struct ProxyConfig { + url: IriString, + auth: Option<(String, String)>, +} + #[derive(Debug)] pub enum UrlKind { Activity, @@ -137,7 +150,10 @@ impl std::fmt::Debug for Config { .field("local_domains", &self.local_domains) .field("local_blurb", &self.local_blurb) .field("prometheus_config", &self.prometheus_config) - .field("client_pool_size", &self.client_pool_size) + .field("deliver_concurrency", &self.deliver_concurrency) + .field("client_timeout", &self.client_timeout) + .field("proxy_config", &self.proxy_config) + .field("signature_threads", &self.signature_threads) .finish() } } @@ -167,7 +183,12 @@ impl Config { .set_default("local_blurb", None as Option<&str>)? .set_default("prometheus_addr", None as Option<&str>)? .set_default("prometheus_port", None as Option)? - .set_default("client_pool_size", 20u64)? + .set_default("deliver_concurrency", 8u64)? + .set_default("client_timeout", 10u64)? + .set_default("proxy_url", None as Option<&str>)? + .set_default("proxy_username", None as Option<&str>)? + .set_default("proxy_password", None as Option<&str>)? + .set_default("signature_threads", None as Option)? .add_source(Environment::default()) .build()?; @@ -209,6 +230,26 @@ impl Config { (None, None) => None, }; + let proxy_config = match (config.proxy_username, config.proxy_password) { + (Some(username), Some(password)) => config.proxy_url.map(|url| ProxyConfig { + url, + auth: Some((username, password)), + }), + (Some(_), None) => { + tracing::warn!( + "PROXY_USERNAME is set but PROXY_PASSWORD is not set, not setting Proxy Auth" + ); + config.proxy_url.map(|url| ProxyConfig { url, auth: None }) + } + (None, Some(_)) => { + tracing::warn!( + "PROXY_PASSWORD is set but PROXY_USERNAME is not set, not setting Proxy Auth" + ); + config.proxy_url.map(|url| ProxyConfig { url, auth: None }) + } + (None, None) => config.proxy_url.map(|url| ProxyConfig { url, auth: None }), + }; + let source_url = match Self::git_hash() { Some(hash) => format!( "{}{}{hash}", @@ -239,10 +280,32 @@ impl Config { local_domains, local_blurb: config.local_blurb, prometheus_config, - client_pool_size: config.client_pool_size, + deliver_concurrency: config.deliver_concurrency, + client_timeout: config.client_timeout, + proxy_config, + signature_threads: config.signature_threads, }) } + pub(crate) fn signature_threads(&self) -> usize { + self.signature_threads + .unwrap_or_else(|| { + std::thread::available_parallelism() + .map(usize::from) + .map_err(|e| tracing::warn!("Failed to get parallelism, {e}")) + .unwrap_or(1) + }) + .max(1) + } + + pub(crate) fn client_timeout(&self) -> u64 { + self.client_timeout + } + + pub(crate) fn deliver_concurrency(&self) -> u64 { + self.deliver_concurrency + } + pub(crate) fn prometheus_bind_address(&self) -> Option { let config = self.prometheus_config.as_ref()?; @@ -291,7 +354,15 @@ impl Config { pub(crate) fn footer_blurb(&self) -> Option> { if let Some(blurb) = &self.footer_blurb { if !blurb.is_empty() { - return Some(crate::templates::Html(ammonia::clean(blurb))); + return Some(crate::templates::Html( + ammonia::Builder::new() + .add_tag_attributes("a", &["rel"]) + .add_tag_attributes("area", &["rel"]) + .add_tag_attributes("link", &["rel"]) + .link_rel(None) + .clean(blurb) + .to_string(), + )); } } @@ -301,7 +372,15 @@ impl Config { pub(crate) fn local_blurb(&self) -> Option> { if let Some(blurb) = &self.local_blurb { if !blurb.is_empty() { - return Some(crate::templates::Html(ammonia::clean(blurb))); + return Some(crate::templates::Html( + ammonia::Builder::new() + .add_tag_attributes("a", &["rel"]) + .add_tag_attributes("area", &["rel"]) + .add_tag_attributes("link", &["rel"]) + .link_rel(None) + .clean(blurb) + .to_string(), + )); } } @@ -419,8 +498,10 @@ impl Config { ) } - pub(crate) fn client_pool_size(&self) -> usize { - self.client_pool_size + pub(crate) fn proxy_config(&self) -> Option<(&IriString, Option<(&str, &str)>)> { + self.proxy_config.as_ref().map(|ProxyConfig { url, auth }| { + (url, auth.as_ref().map(|(u, p)| (u.as_str(), p.as_str()))) + }) } pub(crate) fn source_code(&self) -> &IriString { diff --git a/src/data/actor.rs b/src/data/actor.rs index af6fb78..2966222 100644 --- a/src/data/actor.rs +++ b/src/data/actor.rs @@ -2,7 +2,7 @@ use crate::{ apub::AcceptedActors, db::{Actor, Db}, error::{Error, ErrorKind}, - requests::Requests, + requests::{BreakerStrategy, Requests}, }; use activitystreams::{iri_string::types::IriString, prelude::*}; use std::time::{Duration, SystemTime}; @@ -71,7 +71,9 @@ impl ActorCache { id: &IriString, requests: &Requests, ) -> Result { - let accepted_actor = requests.fetch::(id).await?; + let accepted_actor = requests + .fetch::(id, BreakerStrategy::Require2XX) + .await?; let input_authority = id.authority_components().ok_or(ErrorKind::MissingDomain)?; let accepted_actor_id = accepted_actor @@ -97,6 +99,6 @@ impl ActorCache { fn get_inbox(actor: &AcceptedActors) -> Result<&IriString, Error> { Ok(actor .endpoints()? - .and_then(|e| e.shared_inbox) + .and_then(|e| e.shared_inbox.as_ref()) .unwrap_or(actor.inbox()?)) } diff --git a/src/data/state.rs b/src/data/state.rs index d6c484b..d3b699d 100644 --- a/src/data/state.rs +++ b/src/data/state.rs @@ -1,14 +1,15 @@ use crate::{ - config::{Config, UrlKind}, data::NodeCache, db::Db, error::Error, requests::{Breakers, Requests}, + spawner::Spawner, }; use activitystreams::iri_string::types::IriString; use actix_web::web; use lru::LruCache; use rand::thread_rng; +use reqwest_middleware::ClientWithMiddleware; use rsa::{RsaPrivateKey, RsaPublicKey}; use std::sync::{Arc, RwLock}; @@ -16,10 +17,10 @@ use super::LastOnline; #[derive(Clone)] pub struct State { + pub(crate) requests: Requests, pub(crate) public_key: RsaPublicKey, - private_key: RsaPrivateKey, object_cache: Arc>>, - node_cache: NodeCache, + pub(crate) node_cache: NodeCache, breakers: Breakers, pub(crate) last_online: Arc, pub(crate) db: Db, @@ -36,21 +37,6 @@ impl std::fmt::Debug for State { } impl State { - pub(crate) fn node_cache(&self) -> NodeCache { - self.node_cache.clone() - } - - pub(crate) fn requests(&self, config: &Config) -> Requests { - Requests::new( - config.generate_url(UrlKind::MainKey).to_string(), - self.private_key.clone(), - config.user_agent(), - self.breakers.clone(), - self.last_online.clone(), - config.client_pool_size(), - ) - } - #[tracing::instrument( level = "debug", name = "Get inboxes for other domains", @@ -90,8 +76,17 @@ impl State { self.object_cache.write().unwrap().put(object_id, actor_id); } + pub(crate) fn is_connected(&self, iri: &IriString) -> bool { + self.breakers.should_try(iri) + } + #[tracing::instrument(level = "debug", name = "Building state", skip_all)] - pub(crate) async fn build(db: Db) -> Result { + pub(crate) async fn build( + db: Db, + key_id: String, + spawner: Spawner, + client: ClientWithMiddleware, + ) -> Result { let private_key = if let Ok(Some(key)) = db.private_key().await { tracing::debug!("Using existing key"); key @@ -110,16 +105,28 @@ impl State { let public_key = private_key.to_public_key(); - let state = State { - public_key, + let breakers = Breakers::default(); + let last_online = Arc::new(LastOnline::empty()); + + let requests = Requests::new( + key_id, private_key, + breakers.clone(), + last_online.clone(), + spawner, + client, + ); + + let state = State { + requests, + public_key, object_cache: Arc::new(RwLock::new(LruCache::new( (1024 * 8).try_into().expect("nonzero"), ))), node_cache: NodeCache::new(db.clone()), - breakers: Breakers::default(), + breakers, db, - last_online: Arc::new(LastOnline::empty()), + last_online, }; Ok(state) diff --git a/src/error.rs b/src/error.rs index c72b8b5..e1461db 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,7 @@ use actix_web::{ http::StatusCode, HttpResponse, }; -use http_signature_normalization_actix::PrepareSignError; +use http_signature_normalization_reqwest::SignError; use std::{convert::Infallible, fmt::Debug, io}; use tracing_error::SpanTrace; @@ -81,6 +81,15 @@ pub(crate) enum ErrorKind { #[error("Couldn't encode public key, {0}")] Spki(#[from] rsa::pkcs8::spki::Error), + #[error("Couldn't sign request")] + SignRequest, + + #[error("Couldn't make request")] + Reqwest(#[from] reqwest::Error), + + #[error("Couldn't build client")] + ReqwestMiddleware(#[from] reqwest_middleware::Error), + #[error("Couldn't parse IRI, {0}")] ParseIri(#[from] activitystreams::iri_string::validate::Error), @@ -99,17 +108,17 @@ pub(crate) enum ErrorKind { #[error("Couldn't do the json thing, {0}")] Json(#[from] serde_json::Error), - #[error("Couldn't build signing string, {0}")] - PrepareSign(#[from] PrepareSignError), + #[error("Couldn't sign request, {0}")] + Sign(#[from] SignError), #[error("Couldn't sign digest")] Signature(#[from] rsa::signature::Error), - #[error("Couldn't read signature")] - ReadSignature(rsa::signature::Error), - #[error("Couldn't verify signature")] - VerifySignature(rsa::signature::Error), + VerifySignature, + + #[error("Failed to encode key der")] + DerEncode, #[error("Couldn't parse the signature header")] HeaderValidation(#[from] actix_web::http::header::InvalidHeaderValue), @@ -242,3 +251,15 @@ impl From for ErrorKind { ErrorKind::Rsa(e) } } + +impl From for ErrorKind { + fn from(_: http_signature_normalization_actix::Canceled) -> Self { + Self::Canceled + } +} + +impl From for ErrorKind { + fn from(_: http_signature_normalization_reqwest::Canceled) -> Self { + Self::Canceled + } +} diff --git a/src/extractors.rs b/src/extractors.rs index f56b9af..385ce9a 100644 --- a/src/extractors.rs +++ b/src/extractors.rs @@ -1,6 +1,6 @@ use actix_web::{ dev::Payload, - error::{BlockingError, ParseError}, + error::ParseError, http::{ header::{from_one_raw_str, Header, HeaderName, HeaderValue, TryIntoHeaderValue}, StatusCode, @@ -9,12 +9,11 @@ use actix_web::{ FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError, }; use bcrypt::{BcryptError, DEFAULT_COST}; -use futures_util::future::LocalBoxFuture; -use http_signature_normalization_actix::prelude::InvalidHeaderValue; +use http_signature_normalization_actix::{prelude::InvalidHeaderValue, Canceled, Spawn}; use std::{convert::Infallible, str::FromStr, time::Instant}; use tracing_error::SpanTrace; -use crate::db::Db; +use crate::{db::Db, future::LocalBoxFuture, spawner::Spawner}; #[derive(Clone)] pub(crate) struct AdminConfig { @@ -37,10 +36,10 @@ pub(crate) struct Admin { db: Data, } +type PrepareTuple = (Data, Data, Data, XApiToken); + impl Admin { - fn prepare_verify( - req: &HttpRequest, - ) -> Result<(Data, Data, XApiToken), Error> { + fn prepare_verify(req: &HttpRequest) -> Result { let hashed_api_token = req .app_data::>() .ok_or_else(Error::missing_config)? @@ -53,16 +52,23 @@ impl Admin { .ok_or_else(Error::missing_db)? .clone(); - Ok((db, hashed_api_token, x_api_token)) + let spawner = req + .app_data::>() + .ok_or_else(Error::missing_spawner)? + .clone(); + + Ok((db, hashed_api_token, spawner, x_api_token)) } #[tracing::instrument(level = "debug", skip_all)] async fn verify( hashed_api_token: Data, + spawner: Data, x_api_token: XApiToken, ) -> Result<(), Error> { let span = tracing::Span::current(); - if actix_web::web::block(move || span.in_scope(|| hashed_api_token.verify(x_api_token))) + if spawner + .spawn_blocking(move || span.in_scope(|| hashed_api_token.verify(x_api_token))) .await .map_err(Error::canceled)?? { @@ -107,6 +113,13 @@ impl Error { } } + fn missing_spawner() -> Self { + Error { + context: SpanTrace::capture().to_string(), + kind: ErrorKind::MissingSpawner, + } + } + fn bcrypt_verify(e: BcryptError) -> Self { Error { context: SpanTrace::capture().to_string(), @@ -128,7 +141,7 @@ impl Error { } } - fn canceled(_: BlockingError) -> Self { + fn canceled(_: Canceled) -> Self { Error { context: SpanTrace::capture().to_string(), kind: ErrorKind::Canceled, @@ -147,6 +160,9 @@ enum ErrorKind { #[error("Missing Db")] MissingDb, + #[error("Missing Spawner")] + MissingSpawner, + #[error("Panic in verify")] Canceled, @@ -182,8 +198,8 @@ impl FromRequest for Admin { let now = Instant::now(); let res = Self::prepare_verify(req); Box::pin(async move { - let (db, c, t) = res?; - Self::verify(c, t).await?; + let (db, c, s, t) = res?; + Self::verify(c, s, t).await?; metrics::histogram!( "relay.admin.verify", now.elapsed().as_micros() as f64 / 1_000_000_f64 @@ -226,3 +242,9 @@ impl FromStr for XApiToken { Ok(XApiToken(s.to_string())) } } + +impl std::fmt::Display for XApiToken { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} diff --git a/src/future.rs b/src/future.rs new file mode 100644 index 0000000..905a931 --- /dev/null +++ b/src/future.rs @@ -0,0 +1,3 @@ +use std::{future::Future, pin::Pin}; + +pub(crate) type LocalBoxFuture<'a, T> = Pin + 'a>>; diff --git a/src/jobs.rs b/src/jobs.rs index e2b6aef..6298938 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -14,10 +14,9 @@ pub(crate) use self::{ use crate::{ config::Config, - data::{ActorCache, MediaCache, NodeCache, State}, + data::{ActorCache, MediaCache, State}, error::{Error, ErrorKind}, jobs::{process_listeners::Listeners, record_last_online::RecordLastOnline}, - requests::Requests, }; use background_jobs::{ memory_storage::{ActixTimer, Storage}, @@ -45,6 +44,8 @@ pub(crate) fn create_workers( media: MediaCache, config: Config, ) -> JobServer { + let deliver_concurrency = config.deliver_concurrency(); + let queue_handle = WorkerConfig::new(Storage::new(ActixTimer), move |queue_handle| { JobState::new( state.clone(), @@ -68,7 +69,7 @@ pub(crate) fn create_workers( .register::() .set_worker_count("maintenance", 2) .set_worker_count("apub", 2) - .set_worker_count("deliver", 8) + .set_worker_count("deliver", deliver_concurrency) .start(); queue_handle.every(Duration::from_secs(60 * 5), Listeners); @@ -79,12 +80,10 @@ pub(crate) fn create_workers( #[derive(Clone, Debug)] pub(crate) struct JobState { - requests: Requests, state: State, actors: ActorCache, config: Config, media: MediaCache, - node_cache: NodeCache, job_server: JobServer, } @@ -110,12 +109,10 @@ impl JobState { config: Config, ) -> Self { JobState { - requests: state.requests(&config), - node_cache: state.node_cache(), + state, actors, config, media, - state, job_server, } } diff --git a/src/jobs/contact.rs b/src/jobs/contact.rs index 3c880af..c3c3765 100644 --- a/src/jobs/contact.rs +++ b/src/jobs/contact.rs @@ -2,6 +2,7 @@ use crate::{ apub::AcceptedActors, error::{Error, ErrorKind}, jobs::JobState, + requests::BreakerStrategy, }; use activitystreams::{iri_string::types::IriString, object::Image, prelude::*}; use background_jobs::ActixJob; @@ -32,6 +33,7 @@ impl QueryContact { async fn perform(self, state: JobState) -> Result<(), Error> { let contact_outdated = state + .state .node_cache .is_contact_outdated(self.actor_id.clone()) .await; @@ -41,8 +43,9 @@ impl QueryContact { } let contact = match state + .state .requests - .fetch::(&self.contact_id) + .fetch::(&self.contact_id, BreakerStrategy::Allow404AndBelow) .await { Ok(contact) => contact, @@ -57,6 +60,7 @@ impl QueryContact { to_contact(contact).ok_or(ErrorKind::Extract("contact"))?; state + .state .node_cache .set_contact(self.actor_id, username, display_name, url, avatar) .await?; diff --git a/src/jobs/deliver.rs b/src/jobs/deliver.rs index 72f4aec..0f936e4 100644 --- a/src/jobs/deliver.rs +++ b/src/jobs/deliver.rs @@ -1,6 +1,7 @@ use crate::{ error::Error, jobs::{debug_object, JobState}, + requests::BreakerStrategy, }; use activitystreams::iri_string::types::IriString; use background_jobs::{ActixJob, Backoff}; @@ -35,7 +36,12 @@ impl Deliver { #[tracing::instrument(name = "Deliver", skip(state))] async fn permform(self, state: JobState) -> Result<(), Error> { - if let Err(e) = state.requests.deliver(&self.to, &self.data).await { + if let Err(e) = state + .state + .requests + .deliver(&self.to, &self.data, BreakerStrategy::Allow401AndBelow) + .await + { if e.is_breaker() { tracing::debug!("Not trying due to failed breaker"); return Ok(()); diff --git a/src/jobs/deliver_many.rs b/src/jobs/deliver_many.rs index fc9107c..f932a12 100644 --- a/src/jobs/deliver_many.rs +++ b/src/jobs/deliver_many.rs @@ -1,10 +1,10 @@ use crate::{ error::Error, + future::LocalBoxFuture, jobs::{debug_object, Deliver, JobState}, }; use activitystreams::iri_string::types::IriString; use background_jobs::ActixJob; -use futures_util::future::LocalBoxFuture; #[derive(Clone, serde::Deserialize, serde::Serialize)] pub(crate) struct DeliverMany { diff --git a/src/jobs/instance.rs b/src/jobs/instance.rs index 59826b5..a0f3da1 100644 --- a/src/jobs/instance.rs +++ b/src/jobs/instance.rs @@ -2,6 +2,7 @@ use crate::{ config::UrlKind, error::{Error, ErrorKind}, jobs::{Boolish, JobState}, + requests::BreakerStrategy, }; use activitystreams::{iri, iri_string::types::IriString}; use background_jobs::ActixJob; @@ -40,15 +41,23 @@ impl QueryInstance { InstanceApiType::Mastodon => { let mastodon_instance_uri = iri!(format!("{scheme}://{authority}/api/v1/instance")); state + .state .requests - .fetch_json::(&mastodon_instance_uri) + .fetch_json::( + &mastodon_instance_uri, + BreakerStrategy::Allow404AndBelow, + ) .await } InstanceApiType::Misskey => { let msky_meta_uri = iri!(format!("{scheme}://{authority}/api/meta")); state + .state .requests - .fetch_json_msky::(&msky_meta_uri) + .fetch_json_msky::( + &msky_meta_uri, + BreakerStrategy::Allow404AndBelow, + ) .await .map(|res| res.into()) } @@ -58,10 +67,12 @@ impl QueryInstance { #[tracing::instrument(name = "Query instance", skip(state))] async fn perform(self, state: JobState) -> Result<(), Error> { let contact_outdated = state + .state .node_cache .is_contact_outdated(self.actor_id.clone()) .await; let instance_outdated = state + .state .node_cache .is_instance_outdated(self.actor_id.clone()) .await; @@ -123,6 +134,7 @@ impl QueryInstance { let avatar = state.config.generate_url(UrlKind::Media(uuid)); state + .state .node_cache .set_contact( self.actor_id.clone(), @@ -137,6 +149,7 @@ impl QueryInstance { let description = ammonia::clean(&description); state + .state .node_cache .set_instance( self.actor_id, diff --git a/src/jobs/nodeinfo.rs b/src/jobs/nodeinfo.rs index fa4812f..f9d78a3 100644 --- a/src/jobs/nodeinfo.rs +++ b/src/jobs/nodeinfo.rs @@ -1,6 +1,7 @@ use crate::{ error::{Error, ErrorKind}, jobs::{Boolish, JobState, QueryContact}, + requests::BreakerStrategy, }; use activitystreams::{iri, iri_string::types::IriString, primitives::OneOrMany}; use background_jobs::ActixJob; @@ -27,6 +28,7 @@ impl QueryNodeinfo { #[tracing::instrument(name = "Query node info", skip(state))] async fn perform(self, state: JobState) -> Result<(), Error> { if !state + .state .node_cache .is_nodeinfo_outdated(self.actor_id.clone()) .await @@ -42,8 +44,9 @@ impl QueryNodeinfo { let well_known_uri = iri!(format!("{scheme}://{authority}/.well-known/nodeinfo")); let well_known = match state + .state .requests - .fetch_json::(&well_known_uri) + .fetch_json::(&well_known_uri, BreakerStrategy::Allow404AndBelow) .await { Ok(well_known) => well_known, @@ -60,7 +63,12 @@ impl QueryNodeinfo { return Ok(()); }; - let nodeinfo = match state.requests.fetch_json::(&href).await { + let nodeinfo = match state + .state + .requests + .fetch_json::(&href, BreakerStrategy::Require2XX) + .await + { Ok(nodeinfo) => nodeinfo, Err(e) if e.is_breaker() => { tracing::debug!("Not retrying due to failed breaker"); @@ -70,6 +78,7 @@ impl QueryNodeinfo { }; state + .state .node_cache .set_info( self.actor_id.clone(), diff --git a/src/main.rs b/src/main.rs index 6ce2f22..0373afb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,21 @@ // need this for ructe #![allow(clippy::needless_borrow)] +use std::time::Duration; + use activitystreams::iri_string::types::IriString; use actix_rt::task::JoinHandle; use actix_web::{middleware::Compress, web, App, HttpServer}; use collector::MemoryCollector; #[cfg(feature = "console")] use console_subscriber::ConsoleLayer; +use error::Error; use http_signature_normalization_actix::middleware::VerifySignature; use metrics_exporter_prometheus::PrometheusBuilder; use metrics_util::layers::FanoutBuilder; use opentelemetry::{sdk::Resource, KeyValue}; use opentelemetry_otlp::WithExportConfig; +use reqwest_middleware::ClientWithMiddleware; use rustls::ServerConfig; use tracing_actix_web::TracingLogger; use tracing_error::ErrorLayer; @@ -27,12 +31,16 @@ mod data; mod db; mod error; mod extractors; +mod future; mod jobs; mod middleware; mod requests; mod routes; +mod spawner; mod telegram; +use crate::config::UrlKind; + use self::{ args::Args, config::Config, @@ -41,6 +49,7 @@ use self::{ jobs::create_workers, middleware::{DebugPayload, MyVerify, RelayResolver, Timings}, routes::{actor, healthz, inbox, index, nodeinfo, nodeinfo_meta, statics}, + spawner::Spawner, }; fn init_subscriber( @@ -98,6 +107,38 @@ fn init_subscriber( Ok(()) } +fn build_client( + user_agent: &str, + timeout_seconds: u64, + proxy: Option<(&IriString, Option<(&str, &str)>)>, +) -> Result { + let builder = reqwest::Client::builder().user_agent(user_agent.to_string()); + + let builder = if let Some((url, auth)) = proxy { + let proxy = reqwest::Proxy::all(url.as_str())?; + + let proxy = if let Some((username, password)) = auth { + proxy.basic_auth(username, password) + } else { + proxy + }; + + builder.proxy(proxy) + } else { + builder + }; + + let client = builder + .timeout(Duration::from_secs(timeout_seconds)) + .build()?; + + let client_with_middleware = reqwest_middleware::ClientBuilder::new(client) + .with(reqwest_tracing::TracingMiddleware::default()) + .build(); + + Ok(client_with_middleware) +} + #[actix_rt::main] async fn main() -> Result<(), anyhow::Error> { dotenv::dotenv().ok(); @@ -148,7 +189,11 @@ fn client_main(config: Config, args: Args) -> JoinHandle Result<(), anyhow::Error> { - let client = requests::build_client(&config.user_agent(), config.client_pool_size()); + let client = build_client( + &config.user_agent(), + config.client_timeout(), + config.proxy_config(), + )?; if !args.blocks().is_empty() || !args.allowed().is_empty() { if args.undo() { @@ -236,6 +281,8 @@ fn server_main( actix_rt::spawn(do_server_main(db, actors, media, collector, config)) } +const VERIFY_RATIO: usize = 7; + async fn do_server_main( db: Db, actors: ActorCache, @@ -243,8 +290,30 @@ async fn do_server_main( collector: MemoryCollector, config: Config, ) -> Result<(), anyhow::Error> { + let client = build_client( + &config.user_agent(), + config.client_timeout(), + config.proxy_config(), + )?; + tracing::warn!("Creating state"); - let state = State::build(db.clone()).await?; + + let (signature_threads, verify_threads) = match config.signature_threads() { + 0 | 1 => (1, 1), + n if n <= VERIFY_RATIO => (n, 1), + n => { + let verify_threads = (n / VERIFY_RATIO).max(1); + let signature_threads = n.saturating_sub(verify_threads).max(VERIFY_RATIO); + + (signature_threads, verify_threads) + } + }; + + let verify_spawner = Spawner::build("verify-cpu", verify_threads)?; + let sign_spawner = Spawner::build("sign-cpu", signature_threads)?; + + let key_id = config.generate_url(UrlKind::MainKey).to_string(); + let state = State::build(db.clone(), key_id, sign_spawner, client).await?; if let Some((token, admin_handle)) = config.telegram_info() { tracing::warn!("Creating telegram handler"); @@ -255,20 +324,21 @@ async fn do_server_main( let bind_address = config.bind_address(); let server = HttpServer::new(move || { - let requests = state.requests(&config); - let job_server = create_workers(state.clone(), actors.clone(), media.clone(), config.clone()); let app = App::new() .app_data(web::Data::new(db.clone())) .app_data(web::Data::new(state.clone())) - .app_data(web::Data::new(requests.clone())) + .app_data(web::Data::new( + state.requests.clone().spawner(verify_spawner.clone()), + )) .app_data(web::Data::new(actors.clone())) .app_data(web::Data::new(config.clone())) .app_data(web::Data::new(job_server)) .app_data(web::Data::new(media.clone())) - .app_data(web::Data::new(collector.clone())); + .app_data(web::Data::new(collector.clone())) + .app_data(web::Data::new(verify_spawner.clone())); let app = if let Some(data) = config.admin_config() { app.app_data(data) @@ -284,10 +354,15 @@ async fn do_server_main( .service(web::resource("/media/{path}").route(web::get().to(routes::media))) .service( web::resource("/inbox") - .wrap(config.digest_middleware()) + .wrap(config.digest_middleware().spawner(verify_spawner.clone())) .wrap(VerifySignature::new( - MyVerify(requests, actors.clone(), state.clone()), - Default::default(), + MyVerify( + state.requests.clone().spawner(verify_spawner.clone()), + actors.clone(), + state.clone(), + verify_spawner.clone(), + ), + http_signature_normalization_actix::Config::new(), )) .wrap(DebugPayload(config.debug())) .route(web::post().to(inbox)), @@ -325,7 +400,7 @@ async fn do_server_main( .with_no_client_auth() .with_single_cert(certs, key)?; server - .bind_rustls(bind_address, server_config)? + .bind_rustls_021(bind_address, server_config)? .run() .await?; } else { diff --git a/src/middleware/payload.rs b/src/middleware/payload.rs index bae7774..c23a271 100644 --- a/src/middleware/payload.rs +++ b/src/middleware/payload.rs @@ -4,14 +4,11 @@ use actix_web::{ web::BytesMut, HttpMessage, }; -use futures_util::{ - future::TryFutureExt, - stream::{once, TryStreamExt}, -}; use std::{ future::{ready, Ready}, task::{Context, Poll}, }; +use streem::IntoStreamer; #[derive(Clone, Debug)] pub(crate) struct DebugPayload(pub bool); @@ -53,19 +50,23 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { if self.0 && req.method() == Method::POST { - let pl = req.take_payload(); + let mut pl = req.take_payload().into_streamer(); + req.set_payload(Payload::Stream { - payload: Box::pin(once( - pl.try_fold(BytesMut::new(), |mut acc, bytes| async { - acc.extend(bytes); - Ok(acc) - }) - .map_ok(|bytes| { - let bytes = bytes.freeze(); - tracing::info!("{}", String::from_utf8_lossy(&bytes)); - bytes - }), - )), + payload: Box::pin(streem::try_from_fn(|yielder| async move { + let mut buf = BytesMut::new(); + + while let Some(bytes) = pl.try_next().await? { + buf.extend(bytes); + } + + let bytes = buf.freeze(); + tracing::info!("{}", String::from_utf8_lossy(&bytes)); + + yielder.yield_ok(bytes).await; + + Ok(()) + })), }); self.1.call(req) diff --git a/src/middleware/verifier.rs b/src/middleware/verifier.rs index 6528b83..91debe5 100644 --- a/src/middleware/verifier.rs +++ b/src/middleware/verifier.rs @@ -2,20 +2,17 @@ use crate::{ apub::AcceptedActors, data::{ActorCache, State}, error::{Error, ErrorKind}, - requests::Requests, + requests::{BreakerStrategy, Requests}, + spawner::Spawner, }; use activitystreams::{base::BaseExt, iri, iri_string::types::IriString}; -use actix_web::web; use base64::{engine::general_purpose::STANDARD, Engine}; -use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm}; -use rsa::{ - pkcs1v15::Signature, pkcs1v15::VerifyingKey, pkcs8::DecodePublicKey, sha2::Sha256, - signature::Verifier, RsaPublicKey, -}; +use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm, Spawn}; +use rsa::{pkcs1::EncodeRsaPublicKey, pkcs8::DecodePublicKey, RsaPublicKey}; use std::{future::Future, pin::Pin}; #[derive(Clone, Debug)] -pub(crate) struct MyVerify(pub Requests, pub ActorCache, pub State); +pub(crate) struct MyVerify(pub Requests, pub ActorCache, pub State, pub Spawner); impl MyVerify { #[tracing::instrument("Verify request", skip(self, signature, signing_string))] @@ -55,7 +52,13 @@ impl MyVerify { None => (), }; - let res = do_verify(&actor.public_key, signature.clone(), signing_string.clone()).await; + let res = do_verify( + &self.3, + &actor.public_key, + signature.clone(), + signing_string.clone(), + ) + .await; if let Err(e) = res { if !was_cached { @@ -67,7 +70,11 @@ impl MyVerify { actor_id } else { - match self.0.fetch::(&public_key_id).await { + match self + .0 + .fetch::(&public_key_id, BreakerStrategy::Require2XX) + .await + { Ok(res) => res.actor_id().ok_or(ErrorKind::MissingId), Err(e) => { if e.is_gone() { @@ -85,7 +92,7 @@ impl MyVerify { // Now we make sure we fetch an updated actor let actor = self.1.get_no_cache(&actor_id, &self.0).await?; - do_verify(&actor.public_key, signature, signing_string).await?; + do_verify(&self.3, &actor.public_key, signature, signing_string).await?; Ok(true) } @@ -116,28 +123,34 @@ impl PublicKeyResponse { #[tracing::instrument("Verify signature")] async fn do_verify( + spawner: &Spawner, public_key: &str, signature: String, signing_string: String, ) -> Result<(), Error> { let public_key = RsaPublicKey::from_public_key_pem(public_key.trim())?; + let public_key_der = public_key + .to_pkcs1_der() + .map_err(|_| ErrorKind::DerEncode)?; + let public_key = ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PKCS1_2048_8192_SHA256, + public_key_der, + ); let span = tracing::Span::current(); - web::block(move || { - span.in_scope(|| { - let decoded = STANDARD.decode(signature)?; - let signature = - Signature::try_from(decoded.as_slice()).map_err(ErrorKind::ReadSignature)?; + spawner + .spawn_blocking(move || { + span.in_scope(|| { + let decoded = STANDARD.decode(signature)?; - let verifying_key = VerifyingKey::::new(public_key); - verifying_key - .verify(signing_string.as_bytes(), &signature) - .map_err(ErrorKind::VerifySignature)?; + public_key + .verify(signing_string.as_bytes(), decoded.as_slice()) + .map_err(|_| ErrorKind::VerifySignature)?; - Ok(()) as Result<(), Error> + Ok(()) as Result<(), Error> + }) }) - }) - .await??; + .await??; Ok(()) } diff --git a/src/middleware/webfinger.rs b/src/middleware/webfinger.rs index 9ccbe0e..0590408 100644 --- a/src/middleware/webfinger.rs +++ b/src/middleware/webfinger.rs @@ -1,10 +1,10 @@ use crate::{ config::{Config, UrlKind}, data::State, + future::LocalBoxFuture, }; use actix_web::web::Data; use actix_webfinger::{Resolver, Webfinger}; -use futures_util::future::LocalBoxFuture; use rsa_magic_public_key::AsMagicPublicKey; pub(crate) struct RelayResolver; diff --git a/src/requests.rs b/src/requests.rs index a1fc8ef..08c1002 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -1,31 +1,39 @@ use crate::{ data::LastOnline, error::{Error, ErrorKind}, + spawner::Spawner, }; use activitystreams::iri_string::types::IriString; use actix_web::http::header::Date; -use awc::{error::SendRequestError, Client, ClientResponse, Connector}; use base64::{engine::general_purpose::STANDARD, Engine}; use dashmap::DashMap; -use http_signature_normalization_actix::prelude::*; -use rand::thread_rng; -use rsa::{ - pkcs1v15::SigningKey, - sha2::{Digest, Sha256}, - signature::{RandomizedSigner, SignatureEncoding}, - RsaPrivateKey, +use http_signature_normalization_reqwest::{digest::ring::Sha256, prelude::*}; +use reqwest_middleware::ClientWithMiddleware; +use ring::{ + rand::SystemRandom, + signature::{RsaKeyPair, RSA_PKCS1_SHA256}, }; +use rsa::{pkcs1::EncodeRsaPrivateKey, RsaPrivateKey}; use std::{ sync::Arc, time::{Duration, SystemTime}, }; -use tracing_awc::Tracing; const ONE_SECOND: u64 = 1; const ONE_MINUTE: u64 = 60 * ONE_SECOND; const ONE_HOUR: u64 = 60 * ONE_MINUTE; const ONE_DAY: u64 = 24 * ONE_HOUR; +#[derive(Debug)] +pub(crate) enum BreakerStrategy { + // Requires a successful response + Require2XX, + // Allows HTTP 2xx-401 + Allow401AndBelow, + // Allows HTTP 2xx-404 + Allow404AndBelow, +} + #[derive(Clone)] pub(crate) struct Breakers { inner: Arc>, @@ -38,7 +46,7 @@ impl std::fmt::Debug for Breakers { } impl Breakers { - fn should_try(&self, url: &IriString) -> bool { + pub(crate) fn should_try(&self, url: &IriString) -> bool { if let Some(authority) = url.authority_str() { if let Some(breaker) = self.inner.get(authority) { breaker.should_try() @@ -140,12 +148,11 @@ impl Default for Breaker { #[derive(Clone)] pub(crate) struct Requests { - pool_size: usize, - client: Client, + client: ClientWithMiddleware, key_id: String, - user_agent: String, - private_key: RsaPrivateKey, - config: Config, + private_key: Arc, + rng: SystemRandom, + config: Config, breakers: Breakers, last_online: Arc, } @@ -153,57 +160,42 @@ pub(crate) struct Requests { impl std::fmt::Debug for Requests { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Requests") - .field("pool_size", &self.pool_size) .field("key_id", &self.key_id) - .field("user_agent", &self.user_agent) .field("config", &self.config) .field("breakers", &self.breakers) .finish() } } -thread_local! { - static CLIENT: std::cell::OnceCell = std::cell::OnceCell::new(); -} - -pub(crate) fn build_client(user_agent: &str, pool_size: usize) -> Client { - CLIENT.with(|client| { - client - .get_or_init(|| { - let connector = Connector::new().limit(pool_size); - - Client::builder() - .connector(connector) - .wrap(Tracing) - .add_default_header(("User-Agent", user_agent.to_string())) - .timeout(Duration::from_secs(15)) - .finish() - }) - .clone() - }) -} - impl Requests { + #[allow(clippy::too_many_arguments)] pub(crate) fn new( key_id: String, private_key: RsaPrivateKey, - user_agent: String, breakers: Breakers, last_online: Arc, - pool_size: usize, + spawner: Spawner, + client: ClientWithMiddleware, ) -> Self { + let private_key_der = private_key.to_pkcs1_der().expect("Can encode der"); + let private_key = ring::signature::RsaKeyPair::from_der(private_key_der.as_bytes()) + .expect("Key is valid"); Requests { - pool_size, - client: build_client(&user_agent, pool_size), + client, key_id, - user_agent, - private_key, - config: Config::default().mastodon_compat(), + private_key: Arc::new(private_key), + rng: SystemRandom::new(), + config: Config::new_with_spawner(spawner).mastodon_compat(), breakers, last_online, } } + pub(crate) fn spawner(mut self, spawner: Spawner) -> Self { + self.config = self.config.set_spawner(spawner); + self + } + pub(crate) fn reset_breaker(&self, iri: &IriString) { self.breakers.succeed(iri); } @@ -211,97 +203,126 @@ impl Requests { async fn check_response( &self, parsed_url: &IriString, - res: Result, - ) -> Result { + strategy: BreakerStrategy, + res: Result, + ) -> Result { if res.is_err() { self.breakers.fail(&parsed_url); } - let mut res = - res.map_err(|e| ErrorKind::SendRequest(parsed_url.to_string(), e.to_string()))?; + let res = res?; - if res.status().is_server_error() { + let status = res.status(); + + let success = match strategy { + BreakerStrategy::Require2XX => status.is_success(), + BreakerStrategy::Allow401AndBelow => (200..=401).contains(&status.as_u16()), + BreakerStrategy::Allow404AndBelow => (200..=404).contains(&status.as_u16()), + }; + + if !success { self.breakers.fail(&parsed_url); - if let Ok(bytes) = res.body().await { - if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) { - if !s.is_empty() { - tracing::warn!("Response from {parsed_url}, {s}"); - } + if let Ok(s) = res.text().await { + if !s.is_empty() { + tracing::debug!("Response from {parsed_url}, {s}"); } } - return Err(ErrorKind::Status(parsed_url.to_string(), res.status()).into()); + return Err(ErrorKind::Status(parsed_url.to_string(), status).into()); } - self.last_online.mark_seen(&parsed_url); - self.breakers.succeed(&parsed_url); + // only actually succeed a breaker on 2xx response + if status.is_success() { + self.last_online.mark_seen(&parsed_url); + self.breakers.succeed(&parsed_url); + } Ok(res) } #[tracing::instrument(name = "Fetch Json", skip(self), fields(signing_string))] - pub(crate) async fn fetch_json(&self, url: &IriString) -> Result + pub(crate) async fn fetch_json( + &self, + url: &IriString, + strategy: BreakerStrategy, + ) -> Result where T: serde::de::DeserializeOwned, { - self.do_fetch(url, "application/json").await + self.do_fetch(url, "application/json", strategy).await } #[tracing::instrument(name = "Fetch Json", skip(self), fields(signing_string))] - pub(crate) async fn fetch_json_msky(&self, url: &IriString) -> Result + pub(crate) async fn fetch_json_msky( + &self, + url: &IriString, + strategy: BreakerStrategy, + ) -> Result where T: serde::de::DeserializeOwned, { - let mut res = self + let body = self .do_deliver( url, &serde_json::json!({}), "application/json", "application/json", + strategy, ) + .await? + .bytes() .await?; - let body = res - .body() - .await - .map_err(|e| ErrorKind::ReceiveResponse(url.to_string(), e.to_string()))?; - - Ok(serde_json::from_slice(body.as_ref())?) + Ok(serde_json::from_slice(&body)?) } #[tracing::instrument(name = "Fetch Activity+Json", skip(self), fields(signing_string))] - pub(crate) async fn fetch(&self, url: &IriString) -> Result + pub(crate) async fn fetch( + &self, + url: &IriString, + strategy: BreakerStrategy, + ) -> Result where T: serde::de::DeserializeOwned, { - self.do_fetch(url, "application/activity+json").await + self.do_fetch(url, "application/activity+json", strategy) + .await } - async fn do_fetch(&self, url: &IriString, accept: &str) -> Result + async fn do_fetch( + &self, + url: &IriString, + accept: &str, + strategy: BreakerStrategy, + ) -> Result where T: serde::de::DeserializeOwned, { - let mut res = self.do_fetch_response(url, accept).await?; + let body = self + .do_fetch_response(url, accept, strategy) + .await? + .bytes() + .await?; - let body = res - .body() - .await - .map_err(|e| ErrorKind::ReceiveResponse(url.to_string(), e.to_string()))?; - - Ok(serde_json::from_slice(body.as_ref())?) + Ok(serde_json::from_slice(&body)?) } #[tracing::instrument(name = "Fetch response", skip(self), fields(signing_string))] - pub(crate) async fn fetch_response(&self, url: &IriString) -> Result { - self.do_fetch_response(url, "*/*").await + pub(crate) async fn fetch_response( + &self, + url: &IriString, + strategy: BreakerStrategy, + ) -> Result { + self.do_fetch_response(url, "*/*", strategy).await } pub(crate) async fn do_fetch_response( &self, url: &IriString, accept: &str, - ) -> Result { + strategy: BreakerStrategy, + ) -> Result { if !self.breakers.should_try(url) { return Err(ErrorKind::Breaker.into()); } @@ -309,25 +330,20 @@ impl Requests { let signer = self.signer(); let span = tracing::Span::current(); - let res = self + let request = self .client .get(url.as_str()) - .insert_header(("Accept", accept)) - .insert_header(Date(SystemTime::now().into())) - .no_decompress() - .signature( - self.config.clone(), - self.key_id.clone(), - move |signing_string| { - span.record("signing_string", signing_string); - span.in_scope(|| signer.sign(signing_string)) - }, - ) - .await? - .send() - .await; + .header("Accept", accept) + .header("Date", Date(SystemTime::now().into()).to_string()) + .signature(&self.config, self.key_id.clone(), move |signing_string| { + span.record("signing_string", signing_string); + span.in_scope(|| signer.sign(signing_string)) + }) + .await?; - let res = self.check_response(url, res).await?; + let res = self.client.execute(request).await; + + let res = self.check_response(url, strategy, res).await?; Ok(res) } @@ -337,7 +353,12 @@ impl Requests { skip_all, fields(inbox = inbox.to_string().as_str(), signing_string) )] - pub(crate) async fn deliver(&self, inbox: &IriString, item: &T) -> Result<(), Error> + pub(crate) async fn deliver( + &self, + inbox: &IriString, + item: &T, + strategy: BreakerStrategy, + ) -> Result<(), Error> where T: serde::ser::Serialize + std::fmt::Debug, { @@ -346,6 +367,7 @@ impl Requests { item, "application/activity+json", "application/activity+json", + strategy, ) .await?; Ok(()) @@ -357,7 +379,8 @@ impl Requests { item: &T, content_type: &str, accept: &str, - ) -> Result + strategy: BreakerStrategy, + ) -> Result where T: serde::ser::Serialize + std::fmt::Debug, { @@ -369,12 +392,12 @@ impl Requests { let span = tracing::Span::current(); let item_string = serde_json::to_string(item)?; - let (req, body) = self + let request = self .client .post(inbox.as_str()) - .insert_header(("Accept", accept)) - .insert_header(("Content-Type", content_type)) - .insert_header(Date(SystemTime::now().into())) + .header("Accept", accept) + .header("Content-Type", content_type) + .header("Date", Date(SystemTime::now().into()).to_string()) .signature_with_digest( self.config.clone(), self.key_id.clone(), @@ -385,12 +408,11 @@ impl Requests { span.in_scope(|| signer.sign(signing_string)) }, ) - .await? - .split(); + .await?; - let res = req.send_body(body).await; + let res = self.client.execute(request).await; - let res = self.check_response(inbox, res).await?; + let res = self.check_response(inbox, strategy, res).await?; Ok(res) } @@ -398,19 +420,29 @@ impl Requests { fn signer(&self) -> Signer { Signer { private_key: self.private_key.clone(), + rng: self.rng.clone(), } } } struct Signer { - private_key: RsaPrivateKey, + private_key: Arc, + rng: SystemRandom, } impl Signer { fn sign(&self, signing_string: &str) -> Result { - let signing_key = SigningKey::::new(self.private_key.clone()); - let signature = - signing_key.try_sign_with_rng(&mut thread_rng(), signing_string.as_bytes())?; - Ok(STANDARD.encode(signature.to_bytes().as_ref())) + let mut signature = vec![0; self.private_key.public_modulus_len()]; + + self.private_key + .sign( + &RSA_PKCS1_SHA256, + &self.rng, + signing_string.as_bytes(), + &mut signature, + ) + .map_err(|_| ErrorKind::SignRequest)?; + + Ok(STANDARD.encode(&signature)) } } diff --git a/src/routes/index.rs b/src/routes/index.rs index cdd2a91..7c94759 100644 --- a/src/routes/index.rs +++ b/src/routes/index.rs @@ -36,12 +36,16 @@ pub(crate) async fn route( state: web::Data, config: web::Data, ) -> Result { - let all_nodes = state.node_cache().nodes().await?; + let all_nodes = state.node_cache.nodes().await?; let mut nodes = Vec::new(); let mut local = Vec::new(); for node in all_nodes { + if !state.is_connected(&node.base) { + continue; + } + if node .base .authority_str() diff --git a/src/routes/media.rs b/src/routes/media.rs index 7cc3ed9..4c9b260 100644 --- a/src/routes/media.rs +++ b/src/routes/media.rs @@ -1,4 +1,8 @@ -use crate::{data::MediaCache, error::Error, requests::Requests}; +use crate::{ + data::MediaCache, + error::Error, + requests::{BreakerStrategy, Requests}, +}; use actix_web::{body::BodyStream, web, HttpResponse}; use uuid::Uuid; @@ -11,7 +15,9 @@ pub(crate) async fn route( let uuid = uuid.into_inner(); if let Some(url) = media.get_url(uuid).await? { - let res = requests.fetch_response(&url).await?; + let res = requests + .fetch_response(&url, BreakerStrategy::Allow404AndBelow) + .await?; let mut response = HttpResponse::build(res.status()); @@ -19,7 +25,7 @@ pub(crate) async fn route( response.insert_header((name.clone(), value.clone())); } - return Ok(response.body(BodyStream::new(res))); + return Ok(response.body(BodyStream::new(res.bytes_stream()))); } Ok(HttpResponse::NotFound().finish()) diff --git a/src/spawner.rs b/src/spawner.rs new file mode 100644 index 0000000..3b611d7 --- /dev/null +++ b/src/spawner.rs @@ -0,0 +1,193 @@ +use http_signature_normalization_actix::{Canceled, Spawn}; +use std::{ + panic::AssertUnwindSafe, + sync::Arc, + thread::JoinHandle, + time::{Duration, Instant}, +}; + +fn spawner_thread( + receiver: flume::Receiver>, + name: &'static str, + id: usize, +) { + let guard = MetricsGuard::guard(name, id); + + while let Ok(f) = receiver.recv() { + let start = Instant::now(); + metrics::increment_counter!(format!("relay.{name}.operation.start"), "id" => id.to_string()); + let res = std::panic::catch_unwind(AssertUnwindSafe(f)); + metrics::increment_counter!(format!("relay.{name}.operation.end"), "complete" => res.is_ok().to_string(), "id" => id.to_string()); + metrics::histogram!(format!("relay.{name}.operation.duration"), start.elapsed().as_secs_f64(), "complete" => res.is_ok().to_string(), "id" => id.to_string()); + + if let Err(e) = res { + tracing::warn!("{name} fn panicked: {e:?}"); + } + } + + guard.disarm(); +} + +#[derive(Clone, Debug)] +pub(crate) struct Spawner { + name: &'static str, + sender: Option>>, + threads: Option>>>, +} + +struct MetricsGuard { + name: &'static str, + id: usize, + start: Instant, + armed: bool, +} + +impl MetricsGuard { + fn guard(name: &'static str, id: usize) -> Self { + metrics::increment_counter!(format!("relay.{name}.launched"), "id" => id.to_string()); + + Self { + name, + id, + start: Instant::now(), + armed: true, + } + } + + fn disarm(mut self) { + self.armed = false; + } +} + +impl Drop for MetricsGuard { + fn drop(&mut self) { + metrics::increment_counter!(format!("relay.{}.closed", self.name), "clean" => (!self.armed).to_string(), "id" => self.id.to_string()); + metrics::histogram!(format!("relay.{}.duration", self.name), self.start.elapsed().as_secs_f64(), "clean" => (!self.armed).to_string(), "id" => self.id.to_string()); + tracing::warn!("Stopping {} - {}", self.name, self.id); + } +} + +impl Spawner { + pub(crate) fn build(name: &'static str, threads: usize) -> std::io::Result { + let (sender, receiver) = flume::bounded(8); + + tracing::warn!("Launching {threads} {name}s"); + + let threads = (0..threads) + .map(|i| { + let receiver = receiver.clone(); + std::thread::Builder::new() + .name(format!("{name}-{i}")) + .spawn(move || { + spawner_thread(receiver, name, i); + }) + }) + .collect::, _>>()?; + + Ok(Spawner { + name, + sender: Some(sender), + threads: Some(Arc::new(threads)), + }) + } +} + +impl Drop for Spawner { + fn drop(&mut self) { + self.sender.take(); + + if let Some(threads) = self.threads.take().and_then(Arc::into_inner) { + tracing::warn!("Joining {}s", self.name); + for thread in threads { + let _ = thread.join(); + } + } + } +} + +async fn timer(fut: Fut) -> Fut::Output +where + Fut: std::future::Future, +{ + let id = uuid::Uuid::new_v4(); + + metrics::increment_counter!("relay.spawner.wait-timer.start"); + + let mut interval = actix_rt::time::interval(Duration::from_secs(5)); + + // pass the first tick (instant) + interval.tick().await; + + let mut fut = std::pin::pin!(fut); + + let mut counter = 0; + loop { + tokio::select! { + out = &mut fut => { + metrics::increment_counter!("relay.spawner.wait-timer.end"); + return out; + } + _ = interval.tick() => { + counter += 1; + metrics::increment_counter!("relay.spawner.wait-timer.pending"); + tracing::warn!("Blocking operation {id} is taking a long time, {} seconds", counter * 5); + } + } + } +} + +impl Spawn for Spawner { + type Future = std::pin::Pin>>>; + + fn spawn_blocking(&self, func: Func) -> Self::Future + where + Func: FnOnce() -> Out + Send + 'static, + Out: Send + 'static, + { + let sender = self.sender.as_ref().expect("Sender exists").clone(); + + Box::pin(async move { + let (tx, rx) = flume::bounded(1); + + let _ = sender + .send_async(Box::new(move || { + if tx.try_send((func)()).is_err() { + tracing::warn!("Requestor hung up"); + metrics::increment_counter!("relay.spawner.disconnected"); + } + })) + .await; + + timer(rx.recv_async()).await.map_err(|_| Canceled) + }) + } +} + +impl http_signature_normalization_reqwest::Spawn for Spawner { + type Future = std::pin::Pin> + Send>> where T: Send; + + fn spawn_blocking(&self, func: Func) -> Self::Future + where + Func: FnOnce() -> Out + Send + 'static, + Out: Send + 'static, + { + let sender = self.sender.as_ref().expect("Sender exists").clone(); + + Box::pin(async move { + let (tx, rx) = flume::bounded(1); + + let _ = sender + .send_async(Box::new(move || { + if tx.try_send((func)()).is_err() { + tracing::warn!("Requestor hung up"); + metrics::increment_counter!("relay.spawner.disconnected"); + } + })) + .await; + + timer(rx.recv_async()) + .await + .map_err(|_| http_signature_normalization_reqwest::Canceled) + }) + } +}