Switch from awc to reqwest, enable HTTP Proxies

This commit is contained in:
asonix 2023-08-17 17:09:35 -05:00
parent 73b429ab51
commit 75df271b58
18 changed files with 454 additions and 339 deletions

321
Cargo.lock generated
View file

@ -100,7 +100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -140,7 +140,7 @@ dependencies = [
"futures-util", "futures-util",
"mio", "mio",
"num_cpus", "num_cpus",
"socket2", "socket2 0.4.9",
"tokio", "tokio",
"tracing", "tracing",
] ]
@ -167,7 +167,6 @@ dependencies = [
"actix-service", "actix-service",
"actix-utils", "actix-utils",
"futures-core", "futures-core",
"http",
"log", "log",
"pin-project-lite", "pin-project-lite",
"tokio-rustls 0.23.4", "tokio-rustls 0.23.4",
@ -219,20 +218,19 @@ dependencies = [
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"smallvec", "smallvec",
"socket2", "socket2 0.4.9",
"time", "time",
"url", "url",
] ]
[[package]] [[package]]
name = "actix-webfinger" name = "actix-webfinger"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e64f0f9b28305d38058daaff76a608684a43cbf67e9a9289bdd124a2a45b5e" checksum = "74a22b44deff50693521b489885151fd65a2a596f7aef6d8c0753485b8915082"
dependencies = [ dependencies = [
"actix-rt", "actix-rt",
"actix-web", "actix-web",
"awc",
"serde", "serde",
"serde_derive", "serde_derive",
"thiserror", "thiserror",
@ -287,9 +285,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.0.2" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -375,9 +373,9 @@ dependencies = [
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys",
@ -385,9 +383,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.72" version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]] [[package]]
name = "ap-relay" name = "ap-relay"
@ -400,7 +398,6 @@ dependencies = [
"actix-webfinger", "actix-webfinger",
"ammonia", "ammonia",
"anyhow", "anyhow",
"awc",
"background-jobs", "background-jobs",
"base64 0.21.2", "base64 0.21.2",
"bcrypt", "bcrypt",
@ -412,6 +409,7 @@ dependencies = [
"flume", "flume",
"futures-util", "futures-util",
"http-signature-normalization-actix", "http-signature-normalization-actix",
"http-signature-normalization-reqwest",
"lru", "lru",
"metrics", "metrics",
"metrics-exporter-prometheus", "metrics-exporter-prometheus",
@ -423,6 +421,9 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"quanta", "quanta",
"rand", "rand",
"reqwest",
"reqwest-middleware",
"reqwest-tracing",
"ring", "ring",
"rsa", "rsa",
"rsa-magic-public-key", "rsa-magic-public-key",
@ -439,7 +440,6 @@ dependencies = [
"toml 0.7.6", "toml 0.7.6",
"tracing", "tracing",
"tracing-actix-web", "tracing-actix-web",
"tracing-awc",
"tracing-error", "tracing-error",
"tracing-futures", "tracing-futures",
"tracing-log", "tracing-log",
@ -469,13 +469,13 @@ checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.72" version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -484,40 +484,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 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]] [[package]]
name = "axum" name = "axum"
version = "0.6.20" version = "0.6.20"
@ -667,9 +633,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.3.3" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@ -746,9 +712,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -781,9 +747,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.3.19" version = "4.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -792,9 +758,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.3.19" version = "4.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -811,7 +777,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -883,9 +849,9 @@ dependencies = [
[[package]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.4" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
[[package]] [[package]]
name = "convert_case" name = "convert_case"
@ -1014,9 +980,9 @@ dependencies = [
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.7" version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
dependencies = [ dependencies = [
"const-oid", "const-oid",
"pem-rfc7468", "pem-rfc7468",
@ -1149,9 +1115,9 @@ checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.26" version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
@ -1261,7 +1227,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -1458,7 +1424,6 @@ dependencies = [
"actix-http", "actix-http",
"actix-rt", "actix-rt",
"actix-web", "actix-web",
"awc",
"base64 0.13.1", "base64 0.13.1",
"futures-util", "futures-util",
"http-signature-normalization", "http-signature-normalization",
@ -1470,6 +1435,22 @@ dependencies = [
"tracing-futures", "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]] [[package]]
name = "httparse" name = "httparse"
version = "1.8.0" version = "1.8.0"
@ -1478,9 +1459,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]] [[package]]
name = "httpdate" name = "httpdate"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "humantime" name = "humantime"
@ -1505,7 +1486,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2 0.4.9",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@ -1741,9 +1722,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.19" version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "lru" name = "lru"
@ -1861,7 +1842,7 @@ checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -1870,7 +1851,7 @@ version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e" checksum = "4de2ed6e491ed114b40b732e4d1659a9d53992ebd87490c44a6ffe23739d973e"
dependencies = [ dependencies = [
"aho-corasick 1.0.2", "aho-corasick 1.0.4",
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
"hashbrown 0.13.1", "hashbrown 0.13.1",
@ -2327,7 +2308,7 @@ dependencies = [
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -2381,29 +2362,29 @@ dependencies = [
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [ dependencies = [
"pin-project-internal", "pin-project-internal",
] ]
[[package]] [[package]]
name = "pin-project-internal" name = "pin-project-internal"
version = "1.1.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.10" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -2533,9 +2514,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.32" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -2618,13 +2599,13 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.9.1" version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
dependencies = [ dependencies = [
"aho-corasick 1.0.2", "aho-corasick 1.0.4",
"memchr", "memchr",
"regex-automata 0.3.4", "regex-automata 0.3.6",
"regex-syntax 0.7.4", "regex-syntax 0.7.4",
] ]
@ -2639,11 +2620,11 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.3.4" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
dependencies = [ dependencies = [
"aho-corasick 1.0.2", "aho-corasick 1.0.4",
"memchr", "memchr",
"regex-syntax 0.7.4", "regex-syntax 0.7.4",
] ]
@ -2702,6 +2683,37 @@ dependencies = [
"winreg", "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.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b97ad83c2fc18113346b7158d79732242002427c30f620fa817c1f32901e0a8"
dependencies = [
"anyhow",
"async-trait",
"getrandom",
"matchit",
"reqwest",
"reqwest-middleware",
"task-local-extensions",
"tracing",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.16.20" version = "0.16.20"
@ -2827,11 +2839,11 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.6" version = "0.38.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f" checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
dependencies = [ dependencies = [
"bitflags 2.3.3", "bitflags 2.4.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@ -2873,9 +2885,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.101.2" version = "0.101.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0"
dependencies = [ dependencies = [
"ring", "ring",
"untrusted", "untrusted",
@ -2917,29 +2929,29 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.181" version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d3e73c93c3240c0bda063c239298e633114c69a888c3e37ca8bb33f343e9890" checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.181" version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be02f6cb0cd3a5ec20bbcfbcbd749f57daddb1a0882dc2e46a6c236c90b977ed" checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.104" version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -3082,6 +3094,16 @@ dependencies = [
"winapi", "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]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@ -3158,9 +3180,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.28" version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3185,6 +3207,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e" 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]] [[package]]
name = "teloxide" name = "teloxide"
version = "0.12.2" version = "0.12.2"
@ -3267,22 +3298,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.44" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.44" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -3340,11 +3371,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.29.1" version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [ dependencies = [
"autocfg",
"backtrace", "backtrace",
"bytes", "bytes",
"libc", "libc",
@ -3352,7 +3382,7 @@ dependencies = [
"parking_lot 0.12.1", "parking_lot 0.12.1",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2 0.5.3",
"tokio-macros", "tokio-macros",
"tracing", "tracing",
"windows-sys", "windows-sys",
@ -3376,7 +3406,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
] ]
[[package]] [[package]]
@ -3561,22 +3591,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
]
[[package]]
name = "tracing-awc"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afd0c52e66eec56d4fbddbfa1d15261ee48a78360d7d3ee3d3900c4c3489d8ad"
dependencies = [
"actix-http",
"actix-service",
"awc",
"bytes",
"futures-core",
"pin-project-lite",
"tracing",
] ]
[[package]] [[package]]
@ -3794,7 +3809,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3828,7 +3843,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.28", "syn 2.0.29",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3914,9 +3929,9 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.1" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" checksum = "27f51fb4c64f8b770a823c043c7fad036323e1c48f55287b7bbb7987b2fcdf3b"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
@ -3929,51 +3944,51 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" checksum = "fde1bb55ae4ce76a597a8566d82c57432bc69c039449d61572a7a353da28f68c"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" checksum = "1513e8d48365a78adad7322fd6b5e4c4e99d92a69db8df2d435b25b1f1f286d4"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" checksum = "60587c0265d2b842298f5858e1a5d79d146f9ee0c37be5782e92a6eb5e1d7a83"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" checksum = "224fe0e0ffff5d2ea6a29f82026c8f43870038a0ffc247aa95a52b47df381ac4"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" checksum = "62fc52a0f50a088de499712cbc012df7ebd94e2d6eb948435449d76a6287e7ad"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" checksum = "2093925509d91ea3d69bcd20238f4c2ecdb1a29d3c281d026a09705d0dd35f3d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.0" version = "0.48.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.3" version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View file

@ -28,11 +28,10 @@ actix-web = { version = "4.0.1", default-features = false, features = [
"compress-brotli", "compress-brotli",
"compress-gzip", "compress-gzip",
] } ] }
actix-webfinger = "0.4.0" actix-webfinger = { version = "0.5.0", default-features = false }
activitystreams = "0.7.0-alpha.25" activitystreams = "0.7.0-alpha.25"
activitystreams-ext = "0.1.0-alpha.3" activitystreams-ext = "0.1.0-alpha.3"
ammonia = "3.1.0" ammonia = "3.1.0"
awc = { version = "3.0.0", default-features = false, features = ["rustls"] }
bcrypt = "0.15" bcrypt = "0.15"
base64 = "0.21" base64 = "0.21"
clap = { version = "4.0.0", features = ["derive"] } clap = { version = "4.0.0", features = ["derive"] }
@ -55,6 +54,9 @@ opentelemetry-otlp = "0.13"
pin-project-lite = "0.2.9" pin-project-lite = "0.2.9"
quanta = "0.11.0" quanta = "0.11.0"
rand = "0.8" rand = "0.8"
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "stream"]}
reqwest-middleware = "0.2"
reqwest-tracing = "0.4.5"
ring = "0.16.20" ring = "0.16.20"
rsa = { version = "0.9" } rsa = { version = "0.9" }
rsa-magic-public-key = "0.8.0" rsa-magic-public-key = "0.8.0"
@ -71,7 +73,6 @@ teloxide = { version = "0.12.0", default-features = false, features = [
thiserror = "1.0" thiserror = "1.0"
time = { version = "0.3.17", features = ["serde"] } time = { version = "0.3.17", features = ["serde"] }
tracing = "0.1" tracing = "0.1"
tracing-awc = "0.1.8"
tracing-error = "0.2" tracing-error = "0.2"
tracing-futures = "0.2" tracing-futures = "0.2"
tracing-log = "0.1" tracing-log = "0.1"
@ -92,7 +93,12 @@ features = ["background-jobs-actix", "error-logging"]
[dependencies.http-signature-normalization-actix] [dependencies.http-signature-normalization-actix]
version = "0.10.1" version = "0.10.1"
default-features = false default-features = false
features = ["client", "server", "ring"] features = ["server", "ring"]
[dependencies.http-signature-normalization-reqwest]
version = "0.10.0"
default-features = false
features = ["middleware", "ring"]
[dependencies.tracing-actix-web] [dependencies.tracing-actix-web]
version = "0.7.6" version = "0.7.6"

View file

@ -106,7 +106,6 @@ LOCAL_BLURB="<p>Welcome to my cool relay where I have cool relay things happenin
PROMETHEUS_ADDR=0.0.0.0 PROMETHEUS_ADDR=0.0.0.0
PROMETHEUS_PORT=9000 PROMETHEUS_PORT=9000
CLIENT_TIMEOUT=10 CLIENT_TIMEOUT=10
CLIENT_POOL_SIZE=20
DELIVER_CONCURRENCY=8 DELIVER_CONCURRENCY=8
SIGNATURE_THREADS=2 SIGNATURE_THREADS=2
``` ```
@ -161,11 +160,6 @@ Optional - Port to bind to for serving the prometheus scrape endpoint
##### `CLIENT_TIMEOUT` ##### `CLIENT_TIMEOUT`
Optional - How long the relay will hold open a connection (in seconds) to a remote server during Optional - How long the relay will hold open a connection (in seconds) to a remote server during
fetches and deliveries. This defaults to 10 fetches and deliveries. This defaults to 10
##### `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.
##### `DELIVER_CONCURRENCY` ##### `DELIVER_CONCURRENCY`
Optional - How many deliver requests the relay should allow to be in-flight per thread. the default Optional - How many deliver requests the relay should allow to be in-flight per thread. the default
is 8 is 8
@ -173,6 +167,12 @@ is 8
Optional - Override number of threads used for signing and verifying requests. Default is 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 `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. 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 ### Subscribing
Mastodon admins can subscribe to this relay by adding the `/inbox` route to their relay settings. Mastodon admins can subscribe to this relay by adding the `/inbox` route to their relay settings.

View file

@ -3,12 +3,14 @@ use crate::{
collector::Snapshot, collector::Snapshot,
config::{AdminUrlKind, Config}, config::{AdminUrlKind, Config},
error::{Error, ErrorKind}, error::{Error, ErrorKind},
extractors::XApiToken,
}; };
use awc::Client; use actix_web::http::header::Header;
use reqwest_middleware::ClientWithMiddleware;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
pub(crate) async fn allow( pub(crate) async fn allow(
client: &Client, client: &ClientWithMiddleware,
config: &Config, config: &Config,
domains: Vec<String>, domains: Vec<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -16,7 +18,7 @@ pub(crate) async fn allow(
} }
pub(crate) async fn disallow( pub(crate) async fn disallow(
client: &Client, client: &ClientWithMiddleware,
config: &Config, config: &Config,
domains: Vec<String>, domains: Vec<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -24,7 +26,7 @@ pub(crate) async fn disallow(
} }
pub(crate) async fn block( pub(crate) async fn block(
client: &Client, client: &ClientWithMiddleware,
config: &Config, config: &Config,
domains: Vec<String>, domains: Vec<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -32,35 +34,50 @@ pub(crate) async fn block(
} }
pub(crate) async fn unblock( pub(crate) async fn unblock(
client: &Client, client: &ClientWithMiddleware,
config: &Config, config: &Config,
domains: Vec<String>, domains: Vec<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
post_domains(client, config, domains, AdminUrlKind::Unblock).await post_domains(client, config, domains, AdminUrlKind::Unblock).await
} }
pub(crate) async fn allowed(client: &Client, config: &Config) -> Result<AllowedDomains, Error> { pub(crate) async fn allowed(
client: &ClientWithMiddleware,
config: &Config,
) -> Result<AllowedDomains, Error> {
get_results(client, config, AdminUrlKind::Allowed).await get_results(client, config, AdminUrlKind::Allowed).await
} }
pub(crate) async fn blocked(client: &Client, config: &Config) -> Result<BlockedDomains, Error> { pub(crate) async fn blocked(
client: &ClientWithMiddleware,
config: &Config,
) -> Result<BlockedDomains, Error> {
get_results(client, config, AdminUrlKind::Blocked).await get_results(client, config, AdminUrlKind::Blocked).await
} }
pub(crate) async fn connected(client: &Client, config: &Config) -> Result<ConnectedActors, Error> { pub(crate) async fn connected(
client: &ClientWithMiddleware,
config: &Config,
) -> Result<ConnectedActors, Error> {
get_results(client, config, AdminUrlKind::Connected).await get_results(client, config, AdminUrlKind::Connected).await
} }
pub(crate) async fn stats(client: &Client, config: &Config) -> Result<Snapshot, Error> { pub(crate) async fn stats(
client: &ClientWithMiddleware,
config: &Config,
) -> Result<Snapshot, Error> {
get_results(client, config, AdminUrlKind::Stats).await get_results(client, config, AdminUrlKind::Stats).await
} }
pub(crate) async fn last_seen(client: &Client, config: &Config) -> Result<LastSeen, Error> { pub(crate) async fn last_seen(
client: &ClientWithMiddleware,
config: &Config,
) -> Result<LastSeen, Error> {
get_results(client, config, AdminUrlKind::LastSeen).await get_results(client, config, AdminUrlKind::LastSeen).await
} }
async fn get_results<T: DeserializeOwned>( async fn get_results<T: DeserializeOwned>(
client: &Client, client: &ClientWithMiddleware,
config: &Config, config: &Config,
url_kind: AdminUrlKind, url_kind: AdminUrlKind,
) -> Result<T, Error> { ) -> Result<T, Error> {
@ -68,9 +85,9 @@ async fn get_results<T: DeserializeOwned>(
let iri = config.generate_admin_url(url_kind); let iri = config.generate_admin_url(url_kind);
let mut res = client let res = client
.get(iri.as_str()) .get(iri.as_str())
.insert_header(x_api_token) .header(XApiToken::name(), x_api_token.to_string())
.send() .send()
.await .await
.map_err(|e| ErrorKind::SendRequest(iri.to_string(), e.to_string()))?; .map_err(|e| ErrorKind::SendRequest(iri.to_string(), e.to_string()))?;
@ -88,7 +105,7 @@ async fn get_results<T: DeserializeOwned>(
} }
async fn post_domains( async fn post_domains(
client: &Client, client: &ClientWithMiddleware,
config: &Config, config: &Config,
domains: Vec<String>, domains: Vec<String>,
url_kind: AdminUrlKind, url_kind: AdminUrlKind,
@ -99,8 +116,9 @@ async fn post_domains(
let res = client let res = client
.post(iri.as_str()) .post(iri.as_str())
.insert_header(x_api_token) .header(XApiToken::name(), x_api_token.to_string())
.send_json(&Domains { domains }) .json(&Domains { domains })
.send()
.await .await
.map_err(|e| ErrorKind::SendRequest(iri.to_string(), e.to_string()))?; .map_err(|e| ErrorKind::SendRequest(iri.to_string(), e.to_string()))?;

View file

@ -46,7 +46,9 @@ pub(crate) struct ParsedConfig {
prometheus_port: Option<u16>, prometheus_port: Option<u16>,
deliver_concurrency: u64, deliver_concurrency: u64,
client_timeout: u64, client_timeout: u64,
client_pool_size: usize, proxy_url: Option<IriString>,
proxy_username: Option<String>,
proxy_password: Option<String>,
signature_threads: Option<usize>, signature_threads: Option<usize>,
} }
@ -73,7 +75,7 @@ pub struct Config {
prometheus_config: Option<PrometheusConfig>, prometheus_config: Option<PrometheusConfig>,
deliver_concurrency: u64, deliver_concurrency: u64,
client_timeout: u64, client_timeout: u64,
client_pool_size: usize, proxy_config: Option<ProxyConfig>,
signature_threads: Option<usize>, signature_threads: Option<usize>,
} }
@ -89,6 +91,12 @@ struct PrometheusConfig {
port: u16, port: u16,
} }
#[derive(Clone, Debug)]
struct ProxyConfig {
url: IriString,
auth: Option<(String, String)>,
}
#[derive(Debug)] #[derive(Debug)]
pub enum UrlKind { pub enum UrlKind {
Activity, Activity,
@ -144,7 +152,7 @@ impl std::fmt::Debug for Config {
.field("prometheus_config", &self.prometheus_config) .field("prometheus_config", &self.prometheus_config)
.field("deliver_concurrency", &self.deliver_concurrency) .field("deliver_concurrency", &self.deliver_concurrency)
.field("client_timeout", &self.client_timeout) .field("client_timeout", &self.client_timeout)
.field("client_pool_size", &self.client_pool_size) .field("proxy_config", &self.proxy_config)
.field("signature_threads", &self.signature_threads) .field("signature_threads", &self.signature_threads)
.finish() .finish()
} }
@ -177,7 +185,9 @@ impl Config {
.set_default("prometheus_port", None as Option<u16>)? .set_default("prometheus_port", None as Option<u16>)?
.set_default("deliver_concurrency", 8u64)? .set_default("deliver_concurrency", 8u64)?
.set_default("client_timeout", 10u64)? .set_default("client_timeout", 10u64)?
.set_default("client_pool_size", 20u64)? .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<u64>)? .set_default("signature_threads", None as Option<u64>)?
.add_source(Environment::default()) .add_source(Environment::default())
.build()?; .build()?;
@ -220,6 +230,26 @@ impl Config {
(None, None) => None, (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() { let source_url = match Self::git_hash() {
Some(hash) => format!( Some(hash) => format!(
"{}{}{hash}", "{}{}{hash}",
@ -252,7 +282,7 @@ impl Config {
prometheus_config, prometheus_config,
deliver_concurrency: config.deliver_concurrency, deliver_concurrency: config.deliver_concurrency,
client_timeout: config.client_timeout, client_timeout: config.client_timeout,
client_pool_size: config.client_pool_size, proxy_config,
signature_threads: config.signature_threads, signature_threads: config.signature_threads,
}) })
} }
@ -468,8 +498,10 @@ impl Config {
) )
} }
pub(crate) fn client_pool_size(&self) -> usize { pub(crate) fn proxy_config(&self) -> Option<(&IriString, Option<(&str, &str)>)> {
self.client_pool_size 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 { pub(crate) fn source_code(&self) -> &IriString {

View file

@ -1,5 +1,4 @@
use crate::{ use crate::{
config::{Config, UrlKind},
data::NodeCache, data::NodeCache,
db::Db, db::Db,
error::Error, error::Error,
@ -10,6 +9,7 @@ use activitystreams::iri_string::types::IriString;
use actix_web::web; use actix_web::web;
use lru::LruCache; use lru::LruCache;
use rand::thread_rng; use rand::thread_rng;
use reqwest_middleware::ClientWithMiddleware;
use rsa::{RsaPrivateKey, RsaPublicKey}; use rsa::{RsaPrivateKey, RsaPublicKey};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -17,10 +17,10 @@ use super::LastOnline;
#[derive(Clone)] #[derive(Clone)]
pub struct State { pub struct State {
pub(crate) requests: Requests,
pub(crate) public_key: RsaPublicKey, pub(crate) public_key: RsaPublicKey,
private_key: RsaPrivateKey,
object_cache: Arc<RwLock<LruCache<IriString, IriString>>>, object_cache: Arc<RwLock<LruCache<IriString, IriString>>>,
node_cache: NodeCache, pub(crate) node_cache: NodeCache,
breakers: Breakers, breakers: Breakers,
pub(crate) last_online: Arc<LastOnline>, pub(crate) last_online: Arc<LastOnline>,
pub(crate) db: Db, pub(crate) db: Db,
@ -37,23 +37,6 @@ impl std::fmt::Debug for State {
} }
impl State { impl State {
pub(crate) fn node_cache(&self) -> NodeCache {
self.node_cache.clone()
}
pub(crate) fn requests(&self, config: &Config, spawner: Spawner) -> 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(),
config.client_timeout(),
spawner,
)
}
#[tracing::instrument( #[tracing::instrument(
level = "debug", level = "debug",
name = "Get inboxes for other domains", name = "Get inboxes for other domains",
@ -98,7 +81,12 @@ impl State {
} }
#[tracing::instrument(level = "debug", name = "Building state", skip_all)] #[tracing::instrument(level = "debug", name = "Building state", skip_all)]
pub(crate) async fn build(db: Db) -> Result<Self, Error> { pub(crate) async fn build(
db: Db,
key_id: String,
spawner: Spawner,
client: ClientWithMiddleware,
) -> Result<Self, Error> {
let private_key = if let Ok(Some(key)) = db.private_key().await { let private_key = if let Ok(Some(key)) = db.private_key().await {
tracing::debug!("Using existing key"); tracing::debug!("Using existing key");
key key
@ -117,16 +105,28 @@ impl State {
let public_key = private_key.to_public_key(); let public_key = private_key.to_public_key();
let state = State { let breakers = Breakers::default();
public_key, let last_online = Arc::new(LastOnline::empty());
let requests = Requests::new(
key_id,
private_key, private_key,
breakers.clone(),
last_online.clone(),
spawner,
client,
);
let state = State {
requests,
public_key,
object_cache: Arc::new(RwLock::new(LruCache::new( object_cache: Arc::new(RwLock::new(LruCache::new(
(1024 * 8).try_into().expect("nonzero"), (1024 * 8).try_into().expect("nonzero"),
))), ))),
node_cache: NodeCache::new(db.clone()), node_cache: NodeCache::new(db.clone()),
breakers: Breakers::default(), breakers,
db, db,
last_online: Arc::new(LastOnline::empty()), last_online,
}; };
Ok(state) Ok(state)

View file

@ -5,7 +5,7 @@ use actix_web::{
http::StatusCode, http::StatusCode,
HttpResponse, HttpResponse,
}; };
use http_signature_normalization_actix::PrepareSignError; use http_signature_normalization_reqwest::SignError;
use std::{convert::Infallible, fmt::Debug, io}; use std::{convert::Infallible, fmt::Debug, io};
use tracing_error::SpanTrace; use tracing_error::SpanTrace;
@ -84,6 +84,12 @@ pub(crate) enum ErrorKind {
#[error("Couldn't sign request")] #[error("Couldn't sign request")]
SignRequest, 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}")] #[error("Couldn't parse IRI, {0}")]
ParseIri(#[from] activitystreams::iri_string::validate::Error), ParseIri(#[from] activitystreams::iri_string::validate::Error),
@ -102,8 +108,8 @@ pub(crate) enum ErrorKind {
#[error("Couldn't do the json thing, {0}")] #[error("Couldn't do the json thing, {0}")]
Json(#[from] serde_json::Error), Json(#[from] serde_json::Error),
#[error("Couldn't build signing string, {0}")] #[error("Couldn't sign request, {0}")]
PrepareSign(#[from] PrepareSignError), Sign(#[from] SignError),
#[error("Couldn't sign digest")] #[error("Couldn't sign digest")]
Signature(#[from] rsa::signature::Error), Signature(#[from] rsa::signature::Error),
@ -251,3 +257,9 @@ impl From<http_signature_normalization_actix::Canceled> for ErrorKind {
Self::Canceled Self::Canceled
} }
} }
impl From<http_signature_normalization_reqwest::Canceled> for ErrorKind {
fn from(_: http_signature_normalization_reqwest::Canceled) -> Self {
Self::Canceled
}
}

View file

@ -243,3 +243,9 @@ impl FromStr for XApiToken {
Ok(XApiToken(s.to_string())) 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)
}
}

View file

@ -14,11 +14,9 @@ pub(crate) use self::{
use crate::{ use crate::{
config::Config, config::Config,
data::{ActorCache, MediaCache, NodeCache, State}, data::{ActorCache, MediaCache, State},
error::{Error, ErrorKind}, error::{Error, ErrorKind},
jobs::{process_listeners::Listeners, record_last_online::RecordLastOnline}, jobs::{process_listeners::Listeners, record_last_online::RecordLastOnline},
requests::Requests,
spawner::Spawner,
}; };
use background_jobs::{ use background_jobs::{
memory_storage::{ActixTimer, Storage}, memory_storage::{ActixTimer, Storage},
@ -45,7 +43,6 @@ pub(crate) fn create_workers(
actors: ActorCache, actors: ActorCache,
media: MediaCache, media: MediaCache,
config: Config, config: Config,
spawner: Spawner,
) -> JobServer { ) -> JobServer {
let deliver_concurrency = config.deliver_concurrency(); let deliver_concurrency = config.deliver_concurrency();
@ -56,7 +53,6 @@ pub(crate) fn create_workers(
JobServer::new(queue_handle), JobServer::new(queue_handle),
media.clone(), media.clone(),
config.clone(), config.clone(),
spawner.clone(),
) )
}) })
.register::<Deliver>() .register::<Deliver>()
@ -84,12 +80,10 @@ pub(crate) fn create_workers(
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct JobState { pub(crate) struct JobState {
requests: Requests,
state: State, state: State,
actors: ActorCache, actors: ActorCache,
config: Config, config: Config,
media: MediaCache, media: MediaCache,
node_cache: NodeCache,
job_server: JobServer, job_server: JobServer,
} }
@ -113,15 +107,12 @@ impl JobState {
job_server: JobServer, job_server: JobServer,
media: MediaCache, media: MediaCache,
config: Config, config: Config,
spawner: Spawner,
) -> Self { ) -> Self {
JobState { JobState {
requests: state.requests(&config, spawner), state,
node_cache: state.node_cache(),
actors, actors,
config, config,
media, media,
state,
job_server, job_server,
} }
} }

View file

@ -32,6 +32,7 @@ impl QueryContact {
async fn perform(self, state: JobState) -> Result<(), Error> { async fn perform(self, state: JobState) -> Result<(), Error> {
let contact_outdated = state let contact_outdated = state
.state
.node_cache .node_cache
.is_contact_outdated(self.actor_id.clone()) .is_contact_outdated(self.actor_id.clone())
.await; .await;
@ -41,6 +42,7 @@ impl QueryContact {
} }
let contact = match state let contact = match state
.state
.requests .requests
.fetch::<AcceptedActors>(&self.contact_id) .fetch::<AcceptedActors>(&self.contact_id)
.await .await
@ -57,6 +59,7 @@ impl QueryContact {
to_contact(contact).ok_or(ErrorKind::Extract("contact"))?; to_contact(contact).ok_or(ErrorKind::Extract("contact"))?;
state state
.state
.node_cache .node_cache
.set_contact(self.actor_id, username, display_name, url, avatar) .set_contact(self.actor_id, username, display_name, url, avatar)
.await?; .await?;

View file

@ -35,7 +35,7 @@ impl Deliver {
#[tracing::instrument(name = "Deliver", skip(state))] #[tracing::instrument(name = "Deliver", skip(state))]
async fn permform(self, state: JobState) -> Result<(), Error> { 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).await {
if e.is_breaker() { if e.is_breaker() {
tracing::debug!("Not trying due to failed breaker"); tracing::debug!("Not trying due to failed breaker");
return Ok(()); return Ok(());

View file

@ -40,6 +40,7 @@ impl QueryInstance {
InstanceApiType::Mastodon => { InstanceApiType::Mastodon => {
let mastodon_instance_uri = iri!(format!("{scheme}://{authority}/api/v1/instance")); let mastodon_instance_uri = iri!(format!("{scheme}://{authority}/api/v1/instance"));
state state
.state
.requests .requests
.fetch_json::<Instance>(&mastodon_instance_uri) .fetch_json::<Instance>(&mastodon_instance_uri)
.await .await
@ -47,6 +48,7 @@ impl QueryInstance {
InstanceApiType::Misskey => { InstanceApiType::Misskey => {
let msky_meta_uri = iri!(format!("{scheme}://{authority}/api/meta")); let msky_meta_uri = iri!(format!("{scheme}://{authority}/api/meta"));
state state
.state
.requests .requests
.fetch_json_msky::<MisskeyMeta>(&msky_meta_uri) .fetch_json_msky::<MisskeyMeta>(&msky_meta_uri)
.await .await
@ -58,10 +60,12 @@ impl QueryInstance {
#[tracing::instrument(name = "Query instance", skip(state))] #[tracing::instrument(name = "Query instance", skip(state))]
async fn perform(self, state: JobState) -> Result<(), Error> { async fn perform(self, state: JobState) -> Result<(), Error> {
let contact_outdated = state let contact_outdated = state
.state
.node_cache .node_cache
.is_contact_outdated(self.actor_id.clone()) .is_contact_outdated(self.actor_id.clone())
.await; .await;
let instance_outdated = state let instance_outdated = state
.state
.node_cache .node_cache
.is_instance_outdated(self.actor_id.clone()) .is_instance_outdated(self.actor_id.clone())
.await; .await;
@ -123,6 +127,7 @@ impl QueryInstance {
let avatar = state.config.generate_url(UrlKind::Media(uuid)); let avatar = state.config.generate_url(UrlKind::Media(uuid));
state state
.state
.node_cache .node_cache
.set_contact( .set_contact(
self.actor_id.clone(), self.actor_id.clone(),
@ -137,6 +142,7 @@ impl QueryInstance {
let description = ammonia::clean(&description); let description = ammonia::clean(&description);
state state
.state
.node_cache .node_cache
.set_instance( .set_instance(
self.actor_id, self.actor_id,

View file

@ -27,6 +27,7 @@ impl QueryNodeinfo {
#[tracing::instrument(name = "Query node info", skip(state))] #[tracing::instrument(name = "Query node info", skip(state))]
async fn perform(self, state: JobState) -> Result<(), Error> { async fn perform(self, state: JobState) -> Result<(), Error> {
if !state if !state
.state
.node_cache .node_cache
.is_nodeinfo_outdated(self.actor_id.clone()) .is_nodeinfo_outdated(self.actor_id.clone())
.await .await
@ -42,6 +43,7 @@ impl QueryNodeinfo {
let well_known_uri = iri!(format!("{scheme}://{authority}/.well-known/nodeinfo")); let well_known_uri = iri!(format!("{scheme}://{authority}/.well-known/nodeinfo"));
let well_known = match state let well_known = match state
.state
.requests .requests
.fetch_json::<WellKnown>(&well_known_uri) .fetch_json::<WellKnown>(&well_known_uri)
.await .await
@ -60,7 +62,7 @@ impl QueryNodeinfo {
return Ok(()); return Ok(());
}; };
let nodeinfo = match state.requests.fetch_json::<Nodeinfo>(&href).await { let nodeinfo = match state.state.requests.fetch_json::<Nodeinfo>(&href).await {
Ok(nodeinfo) => nodeinfo, Ok(nodeinfo) => nodeinfo,
Err(e) if e.is_breaker() => { Err(e) if e.is_breaker() => {
tracing::debug!("Not retrying due to failed breaker"); tracing::debug!("Not retrying due to failed breaker");
@ -70,6 +72,7 @@ impl QueryNodeinfo {
}; };
state state
.state
.node_cache .node_cache
.set_info( .set_info(
self.actor_id.clone(), self.actor_id.clone(),

View file

@ -1,17 +1,21 @@
// need this for ructe // need this for ructe
#![allow(clippy::needless_borrow)] #![allow(clippy::needless_borrow)]
use std::time::Duration;
use activitystreams::iri_string::types::IriString; use activitystreams::iri_string::types::IriString;
use actix_rt::task::JoinHandle; use actix_rt::task::JoinHandle;
use actix_web::{middleware::Compress, web, App, HttpServer}; use actix_web::{middleware::Compress, web, App, HttpServer};
use collector::MemoryCollector; use collector::MemoryCollector;
#[cfg(feature = "console")] #[cfg(feature = "console")]
use console_subscriber::ConsoleLayer; use console_subscriber::ConsoleLayer;
use error::Error;
use http_signature_normalization_actix::middleware::VerifySignature; use http_signature_normalization_actix::middleware::VerifySignature;
use metrics_exporter_prometheus::PrometheusBuilder; use metrics_exporter_prometheus::PrometheusBuilder;
use metrics_util::layers::FanoutBuilder; use metrics_util::layers::FanoutBuilder;
use opentelemetry::{sdk::Resource, KeyValue}; use opentelemetry::{sdk::Resource, KeyValue};
use opentelemetry_otlp::WithExportConfig; use opentelemetry_otlp::WithExportConfig;
use reqwest_middleware::ClientWithMiddleware;
use rustls::ServerConfig; use rustls::ServerConfig;
use tracing_actix_web::TracingLogger; use tracing_actix_web::TracingLogger;
use tracing_error::ErrorLayer; use tracing_error::ErrorLayer;
@ -34,6 +38,8 @@ mod routes;
mod spawner; mod spawner;
mod telegram; mod telegram;
use crate::config::UrlKind;
use self::{ use self::{
args::Args, args::Args,
config::Config, config::Config,
@ -100,6 +106,38 @@ fn init_subscriber(
Ok(()) Ok(())
} }
fn build_client(
user_agent: &str,
timeout_seconds: u64,
proxy: Option<(&IriString, Option<(&str, &str)>)>,
) -> Result<ClientWithMiddleware, Error> {
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] #[actix_rt::main]
async fn main() -> Result<(), anyhow::Error> { async fn main() -> Result<(), anyhow::Error> {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
@ -150,11 +188,11 @@ fn client_main(config: Config, args: Args) -> JoinHandle<Result<(), anyhow::Erro
} }
async fn do_client_main(config: Config, args: Args) -> Result<(), anyhow::Error> { async fn do_client_main(config: Config, args: Args) -> Result<(), anyhow::Error> {
let client = requests::build_client( let client = build_client(
&config.user_agent(), &config.user_agent(),
config.client_pool_size(),
config.client_timeout(), config.client_timeout(),
); config.proxy_config(),
)?;
if !args.blocks().is_empty() || !args.allowed().is_empty() { if !args.blocks().is_empty() || !args.allowed().is_empty() {
if args.undo() { if args.undo() {
@ -251,15 +289,13 @@ async fn do_server_main(
collector: MemoryCollector, collector: MemoryCollector,
config: Config, config: Config,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
let client = build_client(
&config.user_agent(),
config.client_timeout(),
config.proxy_config(),
)?;
tracing::warn!("Creating state"); tracing::warn!("Creating state");
let state = State::build(db.clone()).await?;
if let Some((token, admin_handle)) = config.telegram_info() {
tracing::warn!("Creating telegram handler");
telegram::start(admin_handle.to_owned(), db.clone(), token);
}
let keys = config.open_keys()?;
let (signature_threads, verify_threads) = match config.signature_threads() { let (signature_threads, verify_threads) = match config.signature_threads() {
0 | 1 => (1, 1), 0 | 1 => (1, 1),
@ -272,26 +308,29 @@ async fn do_server_main(
} }
}; };
let spawner = Spawner::build("sign-cpu", signature_threads)?;
let verify_spawner = Spawner::build("verify-cpu", 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");
telegram::start(admin_handle.to_owned(), db.clone(), token);
}
let keys = config.open_keys()?;
let bind_address = config.bind_address(); let bind_address = config.bind_address();
let server = HttpServer::new(move || { let server = HttpServer::new(move || {
let requests = state.requests(&config, spawner.clone()); let job_server =
create_workers(state.clone(), actors.clone(), media.clone(), config.clone());
let job_server = create_workers(
state.clone(),
actors.clone(),
media.clone(),
config.clone(),
spawner.clone(),
);
let app = App::new() let app = App::new()
.app_data(web::Data::new(db.clone())) .app_data(web::Data::new(db.clone()))
.app_data(web::Data::new(state.clone())) .app_data(web::Data::new(state.clone()))
.app_data(web::Data::new( .app_data(web::Data::new(
requests.clone().spawner(verify_spawner.clone()), state.requests.clone().spawner(verify_spawner.clone()),
)) ))
.app_data(web::Data::new(actors.clone())) .app_data(web::Data::new(actors.clone()))
.app_data(web::Data::new(config.clone())) .app_data(web::Data::new(config.clone()))
@ -317,7 +356,7 @@ async fn do_server_main(
.wrap(config.digest_middleware().spawner(verify_spawner.clone())) .wrap(config.digest_middleware().spawner(verify_spawner.clone()))
.wrap(VerifySignature::new( .wrap(VerifySignature::new(
MyVerify( MyVerify(
requests.spawner(verify_spawner.clone()), state.requests.clone().spawner(verify_spawner.clone()),
actors.clone(), actors.clone(),
state.clone(), state.clone(),
verify_spawner.clone(), verify_spawner.clone(),

View file

@ -5,10 +5,10 @@ use crate::{
}; };
use activitystreams::iri_string::types::IriString; use activitystreams::iri_string::types::IriString;
use actix_web::http::header::Date; use actix_web::http::header::Date;
use awc::{error::SendRequestError, Client, ClientResponse, Connector};
use base64::{engine::general_purpose::STANDARD, Engine}; use base64::{engine::general_purpose::STANDARD, Engine};
use dashmap::DashMap; use dashmap::DashMap;
use http_signature_normalization_actix::{digest::ring::Sha256, prelude::*}; use http_signature_normalization_reqwest::{digest::ring::Sha256, prelude::*};
use reqwest_middleware::ClientWithMiddleware;
use ring::{ use ring::{
rand::SystemRandom, rand::SystemRandom,
signature::{RsaKeyPair, RSA_PKCS1_SHA256}, signature::{RsaKeyPair, RSA_PKCS1_SHA256},
@ -18,7 +18,6 @@ use std::{
sync::Arc, sync::Arc,
time::{Duration, SystemTime}, time::{Duration, SystemTime},
}; };
use tracing_awc::Tracing;
const ONE_SECOND: u64 = 1; const ONE_SECOND: u64 = 1;
const ONE_MINUTE: u64 = 60 * ONE_SECOND; const ONE_MINUTE: u64 = 60 * ONE_SECOND;
@ -139,10 +138,8 @@ impl Default for Breaker {
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Requests { pub(crate) struct Requests {
pool_size: usize, client: ClientWithMiddleware,
client: Client,
key_id: String, key_id: String,
user_agent: String,
private_key: Arc<RsaKeyPair>, private_key: Arc<RsaKeyPair>,
rng: SystemRandom, rng: SystemRandom,
config: Config<Spawner>, config: Config<Spawner>,
@ -153,66 +150,39 @@ pub(crate) struct Requests {
impl std::fmt::Debug for Requests { impl std::fmt::Debug for Requests {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Requests") f.debug_struct("Requests")
.field("pool_size", &self.pool_size)
.field("key_id", &self.key_id) .field("key_id", &self.key_id)
.field("user_agent", &self.user_agent)
.field("config", &self.config) .field("config", &self.config)
.field("breakers", &self.breakers) .field("breakers", &self.breakers)
.finish() .finish()
} }
} }
thread_local! {
static CLIENT: std::cell::OnceCell<Client> = std::cell::OnceCell::new();
}
pub(crate) fn build_client(user_agent: &str, pool_size: usize, timeout_seconds: u64) -> 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(timeout_seconds))
.finish()
})
.clone()
})
}
impl Requests { impl Requests {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn new( pub(crate) fn new(
key_id: String, key_id: String,
private_key: RsaPrivateKey, private_key: RsaPrivateKey,
user_agent: String,
breakers: Breakers, breakers: Breakers,
last_online: Arc<LastOnline>, last_online: Arc<LastOnline>,
pool_size: usize,
timeout_seconds: u64,
spawner: Spawner, spawner: Spawner,
client: ClientWithMiddleware,
) -> Self { ) -> Self {
let private_key_der = private_key.to_pkcs1_der().expect("Can encode der"); 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()) let private_key = ring::signature::RsaKeyPair::from_der(private_key_der.as_bytes())
.expect("Key is valid"); .expect("Key is valid");
Requests { Requests {
pool_size, client,
client: build_client(&user_agent, pool_size, timeout_seconds),
key_id, key_id,
user_agent,
private_key: Arc::new(private_key), private_key: Arc::new(private_key),
rng: SystemRandom::new(), rng: SystemRandom::new(),
config: Config::new().mastodon_compat().spawner(spawner), config: Config::new_with_spawner(spawner).mastodon_compat(),
breakers, breakers,
last_online, last_online,
} }
} }
pub(crate) fn spawner(mut self, spawner: Spawner) -> Self { pub(crate) fn spawner(mut self, spawner: Spawner) -> Self {
self.config = self.config.spawner(spawner); self.config = self.config.set_spawner(spawner);
self self
} }
@ -223,27 +193,26 @@ impl Requests {
async fn check_response( async fn check_response(
&self, &self,
parsed_url: &IriString, parsed_url: &IriString,
res: Result<ClientResponse, SendRequestError>, res: Result<reqwest::Response, reqwest_middleware::Error>,
) -> Result<ClientResponse, Error> { ) -> Result<reqwest::Response, Error> {
if res.is_err() { if res.is_err() {
self.breakers.fail(&parsed_url); self.breakers.fail(&parsed_url);
} }
let mut res = let res = res?;
res.map_err(|e| ErrorKind::SendRequest(parsed_url.to_string(), e.to_string()))?;
if res.status().is_server_error() { let status = res.status();
if status.is_server_error() {
self.breakers.fail(&parsed_url); self.breakers.fail(&parsed_url);
if let Ok(bytes) = res.body().await { if let Ok(s) = res.text().await {
if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) { if !s.is_empty() {
if !s.is_empty() { tracing::debug!("Response from {parsed_url}, {s}");
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.last_online.mark_seen(&parsed_url);
@ -265,21 +234,18 @@ impl Requests {
where where
T: serde::de::DeserializeOwned, T: serde::de::DeserializeOwned,
{ {
let mut res = self let body = self
.do_deliver( .do_deliver(
url, url,
&serde_json::json!({}), &serde_json::json!({}),
"application/json", "application/json",
"application/json", "application/json",
) )
.await?
.bytes()
.await?; .await?;
let body = res Ok(serde_json::from_slice(&body)?)
.body()
.await
.map_err(|e| ErrorKind::ReceiveResponse(url.to_string(), e.to_string()))?;
Ok(serde_json::from_slice(body.as_ref())?)
} }
#[tracing::instrument(name = "Fetch Activity+Json", skip(self), fields(signing_string))] #[tracing::instrument(name = "Fetch Activity+Json", skip(self), fields(signing_string))]
@ -294,18 +260,13 @@ impl Requests {
where where
T: serde::de::DeserializeOwned, T: serde::de::DeserializeOwned,
{ {
let mut res = self.do_fetch_response(url, accept).await?; let body = self.do_fetch_response(url, accept).await?.bytes().await?;
let body = res Ok(serde_json::from_slice(&body)?)
.body()
.await
.map_err(|e| ErrorKind::ReceiveResponse(url.to_string(), e.to_string()))?;
Ok(serde_json::from_slice(body.as_ref())?)
} }
#[tracing::instrument(name = "Fetch response", skip(self), fields(signing_string))] #[tracing::instrument(name = "Fetch response", skip(self), fields(signing_string))]
pub(crate) async fn fetch_response(&self, url: &IriString) -> Result<ClientResponse, Error> { pub(crate) async fn fetch_response(&self, url: &IriString) -> Result<reqwest::Response, Error> {
self.do_fetch_response(url, "*/*").await self.do_fetch_response(url, "*/*").await
} }
@ -313,7 +274,7 @@ impl Requests {
&self, &self,
url: &IriString, url: &IriString,
accept: &str, accept: &str,
) -> Result<ClientResponse, Error> { ) -> Result<reqwest::Response, Error> {
if !self.breakers.should_try(url) { if !self.breakers.should_try(url) {
return Err(ErrorKind::Breaker.into()); return Err(ErrorKind::Breaker.into());
} }
@ -321,23 +282,18 @@ impl Requests {
let signer = self.signer(); let signer = self.signer();
let span = tracing::Span::current(); let span = tracing::Span::current();
let res = self let request = self
.client .client
.get(url.as_str()) .get(url.as_str())
.insert_header(("Accept", accept)) .header("Accept", accept)
.insert_header(Date(SystemTime::now().into())) .header("Date", Date(SystemTime::now().into()).to_string())
.no_decompress() .signature(&self.config, self.key_id.clone(), move |signing_string| {
.signature( span.record("signing_string", signing_string);
self.config.clone(), span.in_scope(|| signer.sign(signing_string))
self.key_id.clone(), })
move |signing_string| { .await?;
span.record("signing_string", signing_string);
span.in_scope(|| signer.sign(signing_string)) let res = self.client.execute(request).await;
},
)
.await?
.send()
.await;
let res = self.check_response(url, res).await?; let res = self.check_response(url, res).await?;
@ -369,7 +325,7 @@ impl Requests {
item: &T, item: &T,
content_type: &str, content_type: &str,
accept: &str, accept: &str,
) -> Result<ClientResponse, Error> ) -> Result<reqwest::Response, Error>
where where
T: serde::ser::Serialize + std::fmt::Debug, T: serde::ser::Serialize + std::fmt::Debug,
{ {
@ -381,12 +337,12 @@ impl Requests {
let span = tracing::Span::current(); let span = tracing::Span::current();
let item_string = serde_json::to_string(item)?; let item_string = serde_json::to_string(item)?;
let (req, body) = self let request = self
.client .client
.post(inbox.as_str()) .post(inbox.as_str())
.insert_header(("Accept", accept)) .header("Accept", accept)
.insert_header(("Content-Type", content_type)) .header("Content-Type", content_type)
.insert_header(Date(SystemTime::now().into())) .header("Date", Date(SystemTime::now().into()).to_string())
.signature_with_digest( .signature_with_digest(
self.config.clone(), self.config.clone(),
self.key_id.clone(), self.key_id.clone(),
@ -397,10 +353,9 @@ impl Requests {
span.in_scope(|| signer.sign(signing_string)) span.in_scope(|| signer.sign(signing_string))
}, },
) )
.await? .await?;
.split();
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, res).await?;

View file

@ -36,7 +36,7 @@ pub(crate) async fn route(
state: web::Data<State>, state: web::Data<State>,
config: web::Data<Config>, config: web::Data<Config>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let all_nodes = state.node_cache().nodes().await?; let all_nodes = state.node_cache.nodes().await?;
let mut nodes = Vec::new(); let mut nodes = Vec::new();
let mut local = Vec::new(); let mut local = Vec::new();

View file

@ -19,7 +19,7 @@ pub(crate) async fn route(
response.insert_header((name.clone(), value.clone())); 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()) Ok(HttpResponse::NotFound().finish())

View file

@ -162,3 +162,32 @@ impl Spawn for Spawner {
}) })
} }
} }
impl http_signature_normalization_reqwest::Spawn for Spawner {
type Future<T> = std::pin::Pin<Box<dyn std::future::Future<Output = Result<T, http_signature_normalization_reqwest::Canceled>> + Send>> where T: Send;
fn spawn_blocking<Func, Out>(&self, func: Func) -> Self::Future<Out>
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)
})
}
}