diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7308d8d6b..3dc9293fd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -18,7 +18,9 @@ trace-protobuf @Datadog/serverless @Datadog/libdatadog-apm trace-mini-agent @Datadog/serverless trace-utils @Datadog/serverless @Datadog/libdatadog-apm serverless @Datadog/serverless +dynamic-configuration @Datadog/libdatadog-php @Datadog/libdatadog-apm +remote-config @Datadog/libdatadog-php @Datadog/libdatadog-apm @Datadog/remote-config sidecar @Datadog/libdatadog-php @Datadog/libdatadog-apm sidecar-ffi @Datadog/libdatadog-php @Datadog/libdatadog-apm data-pipeline*/ @Datadog/libdatadog-apm -ddsketch @Datadog/libdatadog-apm @Datadog/libdatadog-telemetry +ddsketch @Datadog/libdatadog-apm @Datadog/libdatadog-telemetry diff --git a/Cargo.lock b/Cargo.lock index 7ca6f5cef..f862ad746 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,7 +373,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -401,9 +401,9 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "aws-lc-rs" -version = "1.8.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a47f2fb521b70c11ce7369a6c5fa4bd6af7e5d62ec06303875bafe7c6ba245" +checksum = "474d7cec9d0a1126fad1b224b767fcbf351c23b0309bb21ec210bcfd379926a5" dependencies = [ "aws-lc-sys", "mirai-annotations", @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.19.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2927c7af777b460b7ccd95f8b67acd7b4c04ec8896bf0c8e80ba30523cffc057" +checksum = "7505fc3cb7acbf42699a43a79dd9caa4ed9e99861dfbb837c5c0fb5a0a8d2980" dependencies = [ "bindgen", "cc", @@ -547,13 +547,13 @@ dependencies = [ "lazy_static", "lazycell", "log", - "prettyplease 0.2.20", + "prettyplease 0.2.17", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.68", + "syn 2.0.70", "which", ] @@ -611,6 +611,15 @@ dependencies = [ "memoffset 0.9.1", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.6.0" @@ -731,7 +740,7 @@ dependencies = [ "home", "http 1.1.0", "http-body-util", - "hyper 1.4.0", + "hyper 1.3.1", "hyper-named-pipe", "hyper-rustls 0.26.0", "hyper-util", @@ -1000,7 +1009,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -1119,6 +1128,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.4.0" @@ -1214,6 +1232,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "csv" version = "1.3.0" @@ -1262,7 +1290,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -1273,7 +1301,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -1375,6 +1403,14 @@ dependencies = [ "protoc-bin-vendored", ] +[[package]] +name = "datadog-dynamic-configuration" +version = "0.0.1" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "datadog-ipc" version = "0.1.0" @@ -1411,7 +1447,7 @@ name = "datadog-ipc-macros" version = "0.0.1" dependencies = [ "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -1484,6 +1520,31 @@ dependencies = [ "sysinfo", ] +[[package]] +name = "datadog-remote-config" +version = "0.0.1" +dependencies = [ + "anyhow", + "base64 0.21.7", + "datadog-dynamic-configuration", + "datadog-trace-protobuf", + "ddcommon", + "futures", + "futures-util", + "http 0.2.12", + "hyper 0.14.28", + "lazy_static", + "manual_future", + "serde", + "serde_json", + "sha2", + "time", + "tokio", + "tokio-util 0.7.10", + "tracing", + "uuid", +] + [[package]] name = "datadog-serverless-trace-mini-agent" version = "0.6.1" @@ -1501,13 +1562,16 @@ version = "0.0.1" dependencies = [ "anyhow", "arrayref", + "base64 0.21.7", "bincode", "bytes", "cadence", "chrono", "console-subscriber", + "datadog-dynamic-configuration", "datadog-ipc", "datadog-ipc-macros", + "datadog-remote-config", "datadog-sidecar-macros", "datadog-trace-normalization", "datadog-trace-protobuf", @@ -1534,7 +1598,9 @@ dependencies = [ "rmp-serde", "sendfd", "serde", + "serde_json", "serde_with", + "sha2", "simd-json", "spawn_worker", "sys-info", @@ -1555,6 +1621,7 @@ name = "datadog-sidecar-ffi" version = "0.0.1" dependencies = [ "datadog-ipc", + "datadog-remote-config", "datadog-sidecar", "datadog-trace-utils", "ddcommon", @@ -1572,7 +1639,7 @@ name = "datadog-sidecar-macros" version = "0.0.1" dependencies = [ "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -1647,6 +1714,7 @@ dependencies = [ "bolero", "bolero-generator", "bytes", + "cargo-platform", "cargo_metadata", "criterion", "datadog-trace-normalization", @@ -1688,7 +1756,7 @@ dependencies = [ "maplit", "pin-project", "regex", - "rustls 0.23.10", + "rustls 0.23.9", "rustls-native-certs 0.6.3", "serde", "static_assertions", @@ -1707,6 +1775,7 @@ dependencies = [ "crossbeam-queue", "ddcommon", "hyper 0.14.28", + "serde", ] [[package]] @@ -1784,6 +1853,16 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dirs" version = "5.0.1" @@ -1890,7 +1969,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -2132,7 +2211,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -2182,6 +2261,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.14" @@ -2480,9 +2569,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", @@ -2517,7 +2606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper 1.4.0", + "hyper 1.3.1", "hyper-util", "pin-project-lite", "tokio", @@ -2533,7 +2622,7 @@ checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.0", + "hyper 1.3.1", "hyper-util", "log", "rustls 0.22.4", @@ -2552,9 +2641,9 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.0", + "hyper 1.3.1", "hyper-util", - "rustls 0.23.10", + "rustls 0.23.9", "rustls-native-certs 0.7.0", "rustls-pki-types", "tokio", @@ -2577,16 +2666,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.0", - "hyper 1.4.0", + "hyper 1.3.1", "pin-project-lite", "socket2 0.5.6", "tokio", @@ -2603,7 +2692,7 @@ checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc" dependencies = [ "hex", "http-body-util", - "hyper 1.4.0", + "hyper 1.3.1", "hyper-util", "pin-project-lite", "tokio", @@ -2899,9 +2988,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", "windows-targets 0.52.4", @@ -3433,7 +3522,7 @@ dependencies = [ "regex", "regex-syntax 0.8.3", "structmeta", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -3490,7 +3579,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -3640,12 +3729,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" dependencies = [ "proc-macro2", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -3766,7 +3855,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -3924,7 +4013,7 @@ checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -4082,9 +4171,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "a218f0f6d05669de4eabfb24f31ce802035c952429d037507b4a4a39f0e60c5b" dependencies = [ "aws-lc-rs", "once_cell", @@ -4272,14 +4361,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -4304,7 +4393,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -4355,7 +4444,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -4380,7 +4469,18 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", ] [[package]] @@ -4552,7 +4652,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -4563,14 +4663,14 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] @@ -4585,14 +4685,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] name = "subtle" -version = "2.6.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "symbolic-common" @@ -4639,9 +4739,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -4815,7 +4915,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -4953,7 +5053,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -4973,7 +5073,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls 0.23.9", "rustls-pki-types", "tokio", ] @@ -5176,7 +5276,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -5262,6 +5362,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicase" version = "2.7.0" @@ -5414,7 +5520,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", "wasm-bindgen-shared", ] @@ -5448,7 +5554,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5800,7 +5906,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] @@ -5820,7 +5926,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.70", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 00d77659a..4840ad1af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,11 @@ members = [ "ddcommon-ffi", "ddtelemetry", "ddtelemetry-ffi", + "dynamic-configuration", "tools", "ipc", "ipc/macros", + "remote-config", "sidecar", "sidecar/macros", "sidecar-ffi", diff --git a/LICENSE-3rdparty.yml b/LICENSE-3rdparty.yml index 0ec429cc4..3fa2fc0bb 100644 --- a/LICENSE-3rdparty.yml +++ b/LICENSE-3rdparty.yml @@ -1,4 +1,4 @@ -root_name: datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, datadog-crashtracker-ffi, ddcommon-ffi, build_common, datadog-profiling, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-normalization, datadog-trace-protobuf, datadog-trace-utils, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, tools, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, spawn_worker, cc_utils, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, sidecar_mockgen, datadog-trace-obfuscation, test_spawn_from_lib, datadog-serverless-trace-mini-agent, datadog-trace-mini-agent +root_name: datadog-alloc, datadog-crashtracker, ddcommon, ddtelemetry, datadog-ddsketch, datadog-crashtracker-ffi, ddcommon-ffi, build_common, datadog-profiling, datadog-profiling-ffi, data-pipeline-ffi, data-pipeline, datadog-trace-normalization, datadog-trace-protobuf, datadog-trace-utils, ddtelemetry-ffi, symbolizer-ffi, datadog-profiling-replayer, datadog-dynamic-configuration, tools, datadog-ipc, datadog-ipc-macros, tarpc, tarpc-plugins, spawn_worker, cc_utils, datadog-remote-config, datadog-sidecar, datadog-sidecar-macros, datadog-sidecar-ffi, sidecar_mockgen, datadog-trace-obfuscation, test_spawn_from_lib, datadog-serverless-trace-mini-agent, datadog-trace-mini-agent third_party_libraries: - package_name: addr2line package_version: 0.21.0 @@ -2595,7 +2595,7 @@ third_party_libraries: OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - package_name: aws-lc-rs - package_version: 1.8.0 + package_version: 1.7.2 repository: https://github.com/awslabs/aws-lc-rs license: ISC AND (Apache-2.0 OR ISC) licenses: @@ -3008,7 +3008,7 @@ third_party_libraries: ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - package_name: aws-lc-sys - package_version: 0.19.0 + package_version: 0.17.0 repository: https://github.com/aws/aws-lc-rs license: ISC AND (Apache-2.0 OR ISC) AND OpenSSL licenses: @@ -4763,6 +4763,241 @@ third_party_libraries: CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- package_name: block-buffer + package_version: 0.10.4 + repository: https://github.com/RustCrypto/utils + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + Copyright (c) 2018-2019 The RustCrypto Project Developers + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: |2 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. - package_name: blocking package_version: 1.6.0 repository: https://github.com/smol-rs/blocking @@ -7448,25 +7683,260 @@ third_party_libraries: DEALINGS IN THE SOFTWARE. - license: Apache-2.0 text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" -- package_name: crc32fast - package_version: 1.4.0 - repository: https://github.com/srijs/rust-crc32fast +- package_name: cpufeatures + package_version: 0.2.12 + repository: https://github.com/RustCrypto/utils license: MIT OR Apache-2.0 licenses: - license: MIT text: | - MIT License - - Copyright (c) 2018 Sam Rijs, Alex Crichton and contributors + Copyright (c) 2020 The RustCrypto Project Developers - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: |2 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +- package_name: crc32fast + package_version: 1.4.0 + repository: https://github.com/srijs/rust-crc32fast + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + MIT License + + Copyright (c) 2018 Sam Rijs, Alex Crichton and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -7773,21 +8243,256 @@ third_party_libraries: is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice - shall be included in all copies or substantial portions - of the Software. + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" +- package_name: crypto-common + package_version: 0.1.6 + repository: https://github.com/RustCrypto/traits + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + Copyright (c) 2021 RustCrypto Developers + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: |2 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF - ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - license: Apache-2.0 - text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. - package_name: current_platform package_version: 0.2.0 repository: https://github.com/Shnatsel/current_platform @@ -8325,47 +9030,282 @@ third_party_libraries: same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 Jacob Pratt et al. + Copyright 2022 Jacob Pratt et al. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +- package_name: derivative + package_version: 2.2.0 + repository: https://github.com/mcarton/rust-derivative + license: MIT/Apache-2.0 + licenses: + - license: MIT + text: | + Copyright (c) 2016 Martin Carton + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + - license: Apache-2.0 + text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" +- package_name: digest + package_version: 0.10.7 + repository: https://github.com/RustCrypto/traits + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + Copyright (c) 2017 Artyom Pavlov + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: |2 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + END OF TERMS AND CONDITIONS - http://www.apache.org/licenses/LICENSE-2.0 + APPENDIX: How to apply the Apache License to your work. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -- package_name: derivative - package_version: 2.2.0 - repository: https://github.com/mcarton/rust-derivative - license: MIT/Apache-2.0 - licenses: - - license: MIT - text: | - Copyright (c) 2016 Martin Carton + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: + Copyright [yyyy] [name of copyright owner] - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - license: Apache-2.0 - text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. - package_name: dirs package_version: 5.0.1 repository: https://github.com/soc/dirs-rs @@ -10361,6 +11301,13 @@ third_party_libraries: DEALINGS IN THE SOFTWARE. - license: Apache-2.0 text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright (c) 2016 Alex Crichton\nCopyright (c) 2017 The Tokio Authors\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" +- package_name: generic-array + package_version: 0.14.7 + repository: https://github.com/fizyk20/generic-array.git + license: MIT + licenses: + - license: MIT + text: "The MIT License (MIT)\r\n\r\nCopyright (c) 2015 Bartłomiej Kamiński\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE." - package_name: getrandom package_version: 0.2.14 repository: https://github.com/rust-random/getrandom @@ -11857,7 +12804,7 @@ third_party_libraries: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - package_name: hyper - package_version: 1.4.0 + package_version: 1.3.1 repository: https://github.com/hyperium/hyper license: MIT licenses: @@ -12202,7 +13149,7 @@ third_party_libraries: IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - package_name: hyper-util - package_version: 0.1.6 + package_version: 0.1.5 repository: https://github.com/hyperium/hyper-util license: MIT licenses: @@ -20713,9 +21660,9 @@ third_party_libraries: - package_name: ring package_version: 0.17.8 repository: https://github.com/briansmith/ring - license: License specified in file ($CARGO_HOME/registry/src/index.crates.io-6f17d22bba15001f/ring-0.17.8/LICENSE) + license: License specified in file ($CARGO_HOME/registry/src/github.com-1ecc6299db9ec823/ring-0.17.8/LICENSE) licenses: - - license: License specified in file ($CARGO_HOME/registry/src/index.crates.io-6f17d22bba15001f/ring-0.17.8/LICENSE) + - license: License specified in file ($CARGO_HOME/registry/src/github.com-1ecc6299db9ec823/ring-0.17.8/LICENSE) text: "Note that it is easy for this file to get out of sync with the licenses in the\nsource code files. It's recommended to compare the licenses in the source code\nwith what's mentioned here.\n\n*ring* is derived from BoringSSL, so the licensing situation in *ring* is\nsimilar to BoringSSL.\n\n*ring* uses an ISC-style license like BoringSSL for code in new files,\nincluding in particular all the Rust code:\n\n Copyright 2015-2016 Brian Smith.\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHORS DISCLAIM ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY\n SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nBoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL\nlicensing. Files that are completely new have a Google copyright and an ISC\nlicense. This license is reproduced at the bottom of this file.\n\nContributors to BoringSSL are required to follow the CLA rules for Chromium:\nhttps://cla.developers.google.com/clas\n\nFiles in third_party/ have their own licenses, as described therein. The MIT\nlicense, for third_party/fiat, which, unlike other third_party directories, is\ncompiled into non-test libraries, is included below.\n\nThe OpenSSL toolkit stays under a dual license, i.e. both the conditions of the\nOpenSSL License and the original SSLeay license apply to the toolkit. See below\nfor the actual license texts. Actually both licenses are BSD-style Open Source\nlicenses. In case of any license issues related to OpenSSL please contact\nopenssl-core@openssl.org.\n\nThe following are Google-internal bug numbers where explicit permission from\nsome authors is recorded for use of their work:\n 27287199\n 27287880\n 27287883\n\n OpenSSL License\n ---------------\n\n/* ====================================================================\n * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer. \n *\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in\n * the documentation and/or other materials provided with the\n * distribution.\n *\n * 3. All advertising materials mentioning features or use of this\n * software must display the following acknowledgment:\n * \"This product includes software developed by the OpenSSL Project\n * for use in the OpenSSL Toolkit. (http://www.openssl.org/)\"\n *\n * 4. The names \"OpenSSL Toolkit\" and \"OpenSSL Project\" must not be used to\n * endorse or promote products derived from this software without\n * prior written permission. For written permission, please contact\n * openssl-core@openssl.org.\n *\n * 5. Products derived from this software may not be called \"OpenSSL\"\n * nor may \"OpenSSL\" appear in their names without prior written\n * permission of the OpenSSL Project.\n *\n * 6. Redistributions of any form whatsoever must retain the following\n * acknowledgment:\n * \"This product includes software developed by the OpenSSL Project\n * for use in the OpenSSL Toolkit (http://www.openssl.org/)\"\n *\n * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY\n * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * ====================================================================\n *\n * This product includes cryptographic software written by Eric Young\n * (eay@cryptsoft.com). This product includes software written by Tim\n * Hudson (tjh@cryptsoft.com).\n *\n */\n\n Original SSLeay License\n -----------------------\n\n/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)\n * All rights reserved.\n *\n * This package is an SSL implementation written\n * by Eric Young (eay@cryptsoft.com).\n * The implementation was written so as to conform with Netscapes SSL.\n * \n * This library is free for commercial and non-commercial use as long as\n * the following conditions are aheared to. The following conditions\n * apply to all code found in this distribution, be it the RC4, RSA,\n * lhash, DES, etc., code; not just the SSL code. The SSL documentation\n * included with this distribution is covered by the same copyright terms\n * except that the holder is Tim Hudson (tjh@cryptsoft.com).\n * \n * Copyright remains Eric Young's, and as such any Copyright notices in\n * the code are not to be removed.\n * If this package is used in a product, Eric Young should be given attribution\n * as the author of the parts of the library used.\n * This can be in the form of a textual message at program startup or\n * in documentation (online or textual) provided with the package.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the copyright\n * notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n * must display the following acknowledgement:\n * \"This product includes cryptographic software written by\n * Eric Young (eay@cryptsoft.com)\"\n * The word 'cryptographic' can be left out if the rouines from the library\n * being used are not cryptographic related :-).\n * 4. If you include any Windows specific code (or a derivative thereof) from \n * the apps directory (application code) you must include an acknowledgement:\n * \"This product includes software written by Tim Hudson (tjh@cryptsoft.com)\"\n * \n * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * \n * The licence and distribution terms for any publically available version or\n * derivative of this code cannot be changed. i.e. this code cannot simply be\n * copied and put under another distribution licence\n * [including the GNU Public Licence.]\n */\n\n\nISC license used for completely new code in BoringSSL:\n\n/* Copyright (c) 2015, Google Inc.\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */\n\n\nThe code in third_party/fiat carries the MIT license:\n\nCopyright (c) 2015-2016 the fiat-crypto authors (see\nhttps://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" - package_name: rmp package_version: 0.8.14 @@ -21427,7 +22374,7 @@ third_party_libraries: IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - package_name: rustls - package_version: 0.23.10 + package_version: 0.23.9 repository: https://github.com/rustls/rustls license: Apache-2.0 OR ISC OR MIT licenses: @@ -23335,7 +24282,7 @@ third_party_libraries: END OF TERMS AND CONDITIONS - package_name: serde_json - package_version: 1.0.117 + package_version: 1.0.120 repository: https://github.com/serde-rs/json license: MIT OR Apache-2.0 licenses: @@ -23777,36 +24724,246 @@ third_party_libraries: APPENDIX: How to apply the Apache License to your work. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +- package_name: serde_repr + package_version: 0.1.19 + repository: https://github.com/dtolnay/serde-repr + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: |2 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. - Copyright {yyyy} {name of copyright owner} + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. - http://www.apache.org/licenses/LICENSE-2.0 + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. -- package_name: serde_repr - package_version: 0.1.19 - repository: https://github.com/dtolnay/serde-repr - license: MIT OR Apache-2.0 + END OF TERMS AND CONDITIONS +- package_name: serde_urlencoded + package_version: 0.7.1 + repository: https://github.com/nox/serde_urlencoded + license: MIT/Apache-2.0 licenses: - license: MIT text: | + Copyright (c) 2016 Anthony Ramine + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the @@ -24008,14 +25165,84 @@ third_party_libraries: of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS -- package_name: serde_urlencoded - package_version: 0.7.1 - repository: https://github.com/nox/serde_urlencoded - license: MIT/Apache-2.0 +- package_name: serde_with + package_version: 3.7.0 + repository: https://github.com/jonasbb/serde_with/ + license: MIT OR Apache-2.0 licenses: - license: MIT text: | - Copyright (c) 2016 Anthony Ramine + Copyright (c) 2015 + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" +- package_name: serde_with_macros + package_version: 3.7.0 + repository: https://github.com/jonasbb/serde_with/ + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + Copyright (c) 2015 + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + - license: Apache-2.0 + text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" +- package_name: sha2 + package_version: 0.10.8 + repository: https://github.com/RustCrypto/hashes + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + Copyright (c) 2006-2009 Graydon Hoare + Copyright (c) 2009-2013 Mozilla Foundation + Copyright (c) 2016 Artyom Pavlov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -24218,74 +25445,31 @@ third_party_libraries: of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS -- package_name: serde_with - package_version: 3.7.0 - repository: https://github.com/jonasbb/serde_with/ - license: MIT OR Apache-2.0 - licenses: - - license: MIT - text: | - Copyright (c) 2015 - Permission is hereby granted, free of charge, to any - person obtaining a copy of this software and associated - documentation files (the "Software"), to deal in the - Software without restriction, including without - limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software - is furnished to do so, subject to the following - conditions: + APPENDIX: How to apply the Apache License to your work. - The above copyright notice and this permission notice - shall be included in all copies or substantial portions - of the Software. + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF - ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - license: Apache-2.0 - text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" -- package_name: serde_with_macros - package_version: 3.7.0 - repository: https://github.com/jonasbb/serde_with/ - license: MIT OR Apache-2.0 - licenses: - - license: MIT - text: | - Copyright (c) 2015 + Copyright [yyyy] [name of copyright owner] - Permission is hereby granted, free of charge, to any - person obtaining a copy of this software and associated - documentation files (the "Software"), to deal in the - Software without restriction, including without - limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software - is furnished to do so, subject to the following - conditions: + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - The above copyright notice and this permission notice - shall be included in all copies or substantial portions - of the Software. + http://www.apache.org/licenses/LICENSE-2.0 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF - ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - license: Apache-2.0 - text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. - package_name: sharded-slab package_version: 0.1.7 repository: https://github.com/hawkw/sharded-slab @@ -25295,7 +26479,7 @@ third_party_libraries: - license: Apache-2.0 text: NOT FOUND - package_name: strum - package_version: 0.26.2 + package_version: 0.26.3 repository: https://github.com/Peternator7/strum license: MIT licenses: @@ -25351,12 +26535,12 @@ third_party_libraries: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - package_name: subtle - package_version: 2.6.1 + package_version: 2.5.0 repository: https://github.com/dalek-cryptography/subtle license: BSD-3-Clause licenses: - license: BSD-3-Clause - text: "Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved.\nCopyright (c) 2016-2024 Isis Agora Lovecruft. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n1. Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n" + text: "Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n1. Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n" - package_name: symbolic-common package_version: 12.8.0 repository: https://github.com/getsentry/symbolic @@ -25404,7 +26588,7 @@ third_party_libraries: - license: Apache-2.0 text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright [yyyy] [name of copyright owner]\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n" - package_name: syn - package_version: 2.0.68 + package_version: 2.0.70 repository: https://github.com/dtolnay/syn license: MIT OR Apache-2.0 licenses: @@ -28007,6 +29191,36 @@ third_party_libraries: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +- package_name: typenum + package_version: 1.17.0 + repository: https://github.com/paholg/typenum + license: MIT OR Apache-2.0 + licenses: + - license: MIT + text: | + The MIT License (MIT) + + Copyright (c) 2014 Paho Lurie-Gregg + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + - license: Apache-2.0 + text: " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\nCopyright 2014 Paho Lurie-Gregg\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\thttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License." - package_name: unicase package_version: 2.7.0 repository: https://github.com/seanmonstar/unicase diff --git a/ddcommon-ffi/Cargo.toml b/ddcommon-ffi/Cargo.toml index e9064644a..0ea38b004 100644 --- a/ddcommon-ffi/Cargo.toml +++ b/ddcommon-ffi/Cargo.toml @@ -24,6 +24,7 @@ chrono = { version = "0.4.38", features = ["std"] } crossbeam-queue = "0.3.11" ddcommon = { path = "../ddcommon" } hyper = {version = "0.14", default-features = false} +serde = "1.0" [dev-dependencies] bolero = "0.10.1" diff --git a/ddcommon-ffi/src/option.rs b/ddcommon-ffi/src/option.rs index 05047a81a..550467819 100644 --- a/ddcommon-ffi/src/option.rs +++ b/ddcommon-ffi/src/option.rs @@ -23,6 +23,15 @@ impl From> for std::option::Option { } } +impl From> for Option { + fn from(o: std::option::Option) -> Self { + match o { + Some(s) => Option::Some(s), + None => Option::None, + } + } +} + impl From<&Option> for std::option::Option { fn from(o: &Option) -> Self { match o { diff --git a/ddcommon-ffi/src/slice.rs b/ddcommon-ffi/src/slice.rs index 83319dba2..f54a80fe7 100644 --- a/ddcommon-ffi/src/slice.rs +++ b/ddcommon-ffi/src/slice.rs @@ -2,8 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use core::slice; +use serde::ser::Error; +use serde::Serializer; use std::borrow::Cow; -use std::fmt::{Debug, Formatter}; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::os::raw::c_char; use std::str::Utf8Error; @@ -123,6 +126,36 @@ impl<'a, T> Default for Slice<'a, T> { } } +impl<'a, T> Hash for Slice<'a, T> +where + Slice<'a, T>: AsBytes<'a>, +{ + fn hash(&self, state: &mut H) { + state.write(self.as_bytes()) + } +} + +impl<'a, T> serde::Serialize for Slice<'a, T> +where + Slice<'a, T>: AsBytes<'a>, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.try_to_utf8().map_err(Error::custom)?) + } +} + +impl<'a, T> Display for Slice<'a, T> +where + Slice<'a, T>: AsBytes<'a>, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.try_to_utf8().map_err(|_| std::fmt::Error)?) + } +} + impl<'a, T: 'a> From<&'a [T]> for Slice<'a, T> { fn from(s: &'a [T]) -> Self { Slice::new(s) diff --git a/dynamic-configuration/Cargo.toml b/dynamic-configuration/Cargo.toml new file mode 100644 index 000000000..7db7b17e2 --- /dev/null +++ b/dynamic-configuration/Cargo.toml @@ -0,0 +1,15 @@ +[package] +edition = "2021" +license = "Apache 2.0" +name = "datadog-dynamic-configuration" +version = "0.0.1" + +[features] +test = [] + +[dependencies] +serde = "1.0" +serde_json = { version = "1.0" } + +[lib] +bench = false diff --git a/dynamic-configuration/src/data.rs b/dynamic-configuration/src/data.rs new file mode 100644 index 000000000..320cc7878 --- /dev/null +++ b/dynamic-configuration/src/data.rs @@ -0,0 +1,79 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "test", derive(Default, Serialize))] +pub struct DynamicConfigTarget { + pub service: String, + pub env: String, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "test", derive(Serialize))] +pub struct DynamicConfigFile { + pub action: String, + pub service_target: DynamicConfigTarget, + pub lib_config: DynamicConfig, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "test", derive(Serialize))] +pub(crate) struct TracingHeaderTag { + pub header: String, + pub tag_name: String, +} + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum TracingSamplingRuleProvenance { + Customer, + Dynamic, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "test", derive(Serialize))] +pub struct TracingSamplingRuleTag { + pub key: String, + pub value_glob: String, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "test", derive(Serialize))] +pub struct TracingSamplingRule { + pub service: String, + pub name: Option, + pub provenance: TracingSamplingRuleProvenance, + pub resource: String, + #[serde(default)] + pub tags: Vec, + pub sample_rate: f64, +} + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "test", derive(Default, Serialize))] +pub struct DynamicConfig { + pub(crate) tracing_header_tags: Option>, + pub(crate) tracing_sample_rate: Option, + pub(crate) log_injection_enabled: Option, + pub(crate) tracing_tags: Option>, + pub(crate) tracing_enabled: Option, + pub(crate) tracing_sampling_rules: Option>, +} + +#[cfg(feature = "test")] +pub mod tests { + use super::*; + + pub fn dummy_dynamic_config(enabled: bool) -> DynamicConfigFile { + DynamicConfigFile { + action: "".to_string(), + service_target: DynamicConfigTarget::default(), + lib_config: DynamicConfig { + tracing_enabled: Some(enabled), + ..DynamicConfig::default() + }, + } + } +} diff --git a/dynamic-configuration/src/lib.rs b/dynamic-configuration/src/lib.rs new file mode 100644 index 000000000..7d2fdb518 --- /dev/null +++ b/dynamic-configuration/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::data::{DynamicConfig, DynamicConfigFile, TracingSamplingRule}; +use std::collections::HashMap; + +pub mod data; + +impl From for Vec { + fn from(value: DynamicConfig) -> Self { + let mut vec = vec![]; + if let Some(tags) = value.tracing_header_tags { + vec.push(Configs::TracingHeaderTags( + tags.into_iter().map(|t| (t.header, t.tag_name)).collect(), + )) + } + if let Some(sample_rate) = value.tracing_sample_rate { + vec.push(Configs::TracingSampleRate(sample_rate)); + } + if let Some(log_injection) = value.log_injection_enabled { + vec.push(Configs::LogInjectionEnabled(log_injection)); + } + if let Some(tags) = value.tracing_tags { + vec.push(Configs::TracingTags(tags)); + } + if let Some(enabled) = value.tracing_enabled { + vec.push(Configs::TracingEnabled(enabled)); + } + if let Some(sampling_rules) = value.tracing_sampling_rules { + vec.push(Configs::TracingSamplingRules(sampling_rules)); + } + vec + } +} + +pub enum Configs { + TracingHeaderTags(HashMap), + TracingSampleRate(f64), + LogInjectionEnabled(bool), + TracingTags(Vec), // "key:val" format + TracingEnabled(bool), + TracingSamplingRules(Vec), +} + +pub fn parse_json(data: &[u8]) -> serde_json::error::Result { + serde_json::from_slice(data) +} diff --git a/ipc/src/platform/unix/mem_handle_macos.rs b/ipc/src/platform/unix/mem_handle_macos.rs index 7ae0fc356..6a5930e0e 100644 --- a/ipc/src/platform/unix/mem_handle_macos.rs +++ b/ipc/src/platform/unix/mem_handle_macos.rs @@ -58,7 +58,7 @@ pub(crate) fn mmap_handle(mut handle: T) -> io::Result(mapped: &mut MappedMem) { +pub(crate) fn munmap_handle(mapped: &MappedMem) { unsafe { _ = munmap(mapped.ptr, mapped.mem.get_size()); } diff --git a/remote-config/Cargo.toml b/remote-config/Cargo.toml new file mode 100644 index 000000000..004f7d8b4 --- /dev/null +++ b/remote-config/Cargo.toml @@ -0,0 +1,35 @@ +[package] +edition = "2021" +license = "Apache 2.0" +name = "datadog-remote-config" +version = "0.0.1" + +[features] +test = [] + +[dependencies] +anyhow = { version = "1.0" } +ddcommon = { path = "../ddcommon" } +datadog-dynamic-configuration = { path = "../dynamic-configuration" } +datadog-trace-protobuf = { path = "../trace-protobuf" } +hyper = { version = "0.14", features = ["client"], default-features = false } +http = "0.2" +base64 = "0.21.0" +sha2 = "0.10" +uuid = { version = "1.7.0", features = ["v4"] } +futures-util = "0.3" +tokio = { version = "1.36.0" } +tokio-util = "0.7.10" +manual_future = "0.1.1" +time = { version = "0.3", features = ["parsing", "serde", "formatting"] } +tracing = { version = "0.1", default-features = false } +serde = "1.0" +serde_json = { version = "1.0", features = ["raw_value"] } + +[dev-dependencies] +hyper = { version = "0.14", features = ["client", "server"], default-features = false } +lazy_static = "1.4.0" +futures = "0.3" + +[lib] +bench = false diff --git a/remote-config/examples/remote_config_fetch.rs b/remote-config/examples/remote_config_fetch.rs new file mode 100644 index 000000000..15de1660c --- /dev/null +++ b/remote-config/examples/remote_config_fetch.rs @@ -0,0 +1,93 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use datadog_remote_config::fetch::{ConfigInvariants, SingleChangesFetcher}; +use datadog_remote_config::file_change_tracker::{Change, FilePath}; +use datadog_remote_config::file_storage::ParsedFileStorage; +use datadog_remote_config::RemoteConfigProduct::ApmTracing; +use datadog_remote_config::{RemoteConfigData, Target}; +use ddcommon::Endpoint; +use std::time::Duration; +use tokio::time::sleep; + +const RUNTIME_ID: &str = "23e76587-5ae1-410c-a05c-137cae600a10"; +const SERVICE: &str = "testservice"; +const ENV: &str = "testenv"; +const VERSION: &str = "1.2.3"; + +#[tokio::main(flavor = "current_thread")] +async fn main() { + // SingleChangesFetcher is ideal for a single static (runtime_id, service, env, version) tuple + // Otherwise a SharedFetcher (or even a MultiTargetFetcher for a potentially high number of + // targets) for multiple targets is needed. These can be manually wired together with a + // ChangeTracker to keep track of changes. The SingleChangesTracker does it for you. + let mut fetcher = SingleChangesFetcher::new( + // Use SimpleFileStorage if you desire just the raw, unparsed contents + // (e.g. to do processing directly in your language) + // For more complicated use cases, like needing to store data in shared memory, a custom + // FileStorage implementation is recommended + ParsedFileStorage::default(), + Target { + service: SERVICE.to_string(), + env: ENV.to_string(), + app_version: VERSION.to_string(), + }, + RUNTIME_ID.to_string(), + ConfigInvariants { + language: "awesomelang".to_string(), + tracer_version: "99.10.5".to_string(), + endpoint: Endpoint { + url: hyper::Uri::from_static("http://localhost:8126"), + api_key: None, + timeout_ms: 5000, // custom timeout, defaults to 3 seconds + test_token: None, + }, + products: vec![ApmTracing], + capabilities: vec![], + }, + ); + + loop { + match fetcher.fetch_changes().await { + Ok(changes) => { + println!("Got {} changes:", changes.len()); + for change in changes { + match change { + Change::Add(file) => { + println!("Added file: {} (version: {})", file.path(), file.version()); + print_file_contents(&file.contents()); + } + Change::Update(file, _) => { + println!( + "Got update for file: {} (version: {})", + file.path(), + file.version() + ); + print_file_contents(&file.contents()); + } + Change::Remove(file) => { + println!("Removing file {}", file.path()); + } + } + } + } + Err(e) => { + eprintln!("Fetch failed with {e}"); + } + } + + sleep(Duration::from_secs(1)).await; + } +} + +fn print_file_contents(contents: &anyhow::Result) { + // Note: these contents may be large. Do not actually print it fully in a non-dev env. + match contents { + Ok(data) => { + println!("File contents: {:?}", data); + } + Err(e) => { + println!("Failed parsing file: {:?}", e); + } + } +} diff --git a/remote-config/src/fetch/fetcher.rs b/remote-config/src/fetch/fetcher.rs new file mode 100644 index 000000000..d988096c1 --- /dev/null +++ b/remote-config/src/fetch/fetcher.rs @@ -0,0 +1,807 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::targets::TargetsList; +use crate::{ + RemoteConfigCapabilities, RemoteConfigPath, RemoteConfigPathRef, RemoteConfigPathType, + RemoteConfigProduct, Target, +}; +use base64::Engine; +use datadog_trace_protobuf::remoteconfig::{ + ClientGetConfigsRequest, ClientGetConfigsResponse, ClientState, ClientTracer, ConfigState, + TargetFileHash, TargetFileMeta, +}; +use ddcommon::{connector, Endpoint}; +use hyper::http::uri::PathAndQuery; +use hyper::{Client, StatusCode}; +use sha2::{Digest, Sha256, Sha512}; +use std::collections::{HashMap, HashSet}; +use std::mem::transmute; +use std::sync::{Arc, Mutex, MutexGuard}; +use std::time::Duration; +use tracing::{debug, trace, warn}; + +const PROD_INTAKE_SUBDOMAIN: &str = "config"; + +/// Manages config files. +/// Presents store() and update() operations. +/// It is recommended to minimize the overhead of these operations as they will be invoked while +/// a lock across all ConfigFetchers referencing the same ConfigFetcherState is held. +pub trait FileStorage { + type StoredFile; + + /// A new, currently unknown file was received. + fn store( + &self, + version: u64, + path: Arc, + contents: Vec, + ) -> anyhow::Result>; + + /// A file at a given path was updated (new contents). + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()>; +} + +/// Fundamental configuration of the RC client, which always must be set. +#[derive(Clone, Hash, Eq, PartialEq)] +pub struct ConfigInvariants { + pub language: String, + pub tracer_version: String, + pub endpoint: Endpoint, + pub products: Vec, + pub capabilities: Vec, +} + +struct StoredTargetFile { + hash: String, + handle: Arc, + state: ConfigState, + meta: TargetFileMeta, + expiring: bool, +} + +pub enum ConfigApplyState { + Unacknowledged, + Acknowledged, + Error(String), +} + +pub struct ConfigFetcherState { + target_files_by_path: Mutex, StoredTargetFile>>, + pub invariants: ConfigInvariants, + endpoint: Endpoint, + pub expire_unused_files: bool, +} + +pub struct ConfigFetcherFilesLock<'a, S> { + inner: MutexGuard<'a, HashMap, StoredTargetFile>>, +} + +impl<'a, S> ConfigFetcherFilesLock<'a, S> { + /// Actually remove the file from the known files. + /// It may only be expired if already marked as expiring. + pub fn expire_file(&mut self, path: &RemoteConfigPath) { + if let Some(target_file) = self.inner.get(path) { + if !target_file.expiring { + return; + } + } else { + return; + } + self.inner.remove(path); + } + + /// Stop advertising the file as known. It's the predecessor to expire_file(). + pub fn mark_expiring(&mut self, path: &RemoteConfigPath) { + if let Some(target_file) = self.inner.get_mut(path) { + target_file.expiring = true; + } + } +} + +impl ConfigFetcherState { + pub fn new(invariants: ConfigInvariants) -> Self { + ConfigFetcherState { + target_files_by_path: Default::default(), + endpoint: get_product_endpoint(PROD_INTAKE_SUBDOMAIN, &invariants.endpoint), + invariants, + expire_unused_files: true, + } + } + + /// To remove unused remote files manually. Must not be called when auto expiration is active. + /// Note: careful attention must be paid when using this API in order to not deadlock: + /// - This files_lock() must always be called prior to locking any data structure locked within + /// FileStorage::store(). + /// - Also, files_lock() must not be called from within FileStorage::store(). + pub fn files_lock(&self) -> ConfigFetcherFilesLock { + assert!(!self.expire_unused_files); + ConfigFetcherFilesLock { + inner: self.target_files_by_path.lock().unwrap(), + } + } + + /// Sets the apply state on a stored file. + pub fn set_config_state(&self, file: &RemoteConfigPath, state: ConfigApplyState) { + if let Some(target_file) = self.target_files_by_path.lock().unwrap().get_mut(file) { + match state { + ConfigApplyState::Unacknowledged => { + target_file.state.apply_state = 1; + target_file.state.apply_error = "".to_string(); + } + ConfigApplyState::Acknowledged => { + target_file.state.apply_state = 1; + target_file.state.apply_error = "".to_string(); + } + ConfigApplyState::Error(error) => { + target_file.state.apply_state = 1; + target_file.state.apply_error = error; + } + } + } + } +} + +pub struct ConfigFetcher { + pub file_storage: S, + state: Arc>, +} + +#[derive(Default)] +pub struct ConfigClientState { + opaque_backend_state: Vec, + last_configs: Vec, + // 'static because it actually depends on last_configs, and rust doesn't like self-referencing + last_config_paths: HashSet>, + targets_version: u64, + last_error: Option, +} + +impl ConfigFetcher { + pub fn new(file_storage: S, state: Arc>) -> Self { + ConfigFetcher { + file_storage, + state, + } + } + + /// Sets the apply state on a stored file. + pub fn set_config_state(&self, file: &RemoteConfigPath, state: ConfigApplyState) { + self.state.set_config_state(file, state) + } + + /// Quite generic fetching implementation: + /// - runs a request against the Remote Config Server, + /// - validates the data, + /// - removes unused files + /// - checks if the files are already known, + /// - stores new files, + /// - returns all currently active files. + /// + /// It also makes sure that old files are dropped before new files are inserted. + /// + /// Returns None if nothing changed. Otherwise Some(active configs). + pub async fn fetch_once( + &mut self, + runtime_id: &str, + target: Arc, + client_id: &str, + opaque_state: &mut ConfigClientState, + ) -> anyhow::Result>>> { + if self.state.endpoint.api_key.is_some() { + // Using remote config talking to the backend directly is not supported. + return Ok(Some(vec![])); + } + + let Target { + service, + env, + app_version, + } = (*target).clone(); + + let mut cached_target_files = vec![]; + let mut config_states = vec![]; + + { + let target_files = self.state.target_files_by_path.lock().unwrap(); + for StoredTargetFile { meta, expiring, .. } in target_files.values() { + if !expiring { + cached_target_files.push(meta.clone()); + } + } + + for config in opaque_state.last_config_paths.iter() { + if let Some(StoredTargetFile { state, .. }) = + target_files.get(config as &dyn RemoteConfigPathType) + { + config_states.push(state.clone()); + } + } + } + + let config_req = ClientGetConfigsRequest { + client: Some(datadog_trace_protobuf::remoteconfig::Client { + state: Some(ClientState { + root_version: 1, + targets_version: opaque_state.targets_version, + config_states, + has_error: opaque_state.last_error.is_some(), + error: opaque_state.last_error.take().unwrap_or_default(), + backend_client_state: std::mem::take(&mut opaque_state.opaque_backend_state), + }), + id: client_id.into(), + products: self + .state + .invariants + .products + .iter() + .map(|p| p.to_string()) + .collect(), + is_tracer: true, + client_tracer: Some(ClientTracer { + runtime_id: runtime_id.to_string(), + language: self.state.invariants.language.to_string(), + tracer_version: self.state.invariants.tracer_version.clone(), + service, + extra_services: vec![], + env, + app_version, + tags: vec![], + }), + is_agent: false, + client_agent: None, + last_seen: 0, + capabilities: self + .state + .invariants + .capabilities + .iter() + .map(|c| *c as u8) + .collect(), + }), + cached_target_files, + }; + + trace!("Submitting remote config request: {config_req:?}"); + + let req = self + .state + .endpoint + .into_request_builder(concat!("Sidecar/", env!("CARGO_PKG_VERSION")))? + .method(http::Method::POST) + .header( + http::header::CONTENT_TYPE, + ddcommon::header::APPLICATION_JSON, + ) + .body(serde_json::to_string(&config_req)?)?; + let response = tokio::time::timeout( + Duration::from_millis(self.state.endpoint.timeout_ms), + Client::builder() + .build(connector::Connector::default()) + .request(req), + ) + .await + .map_err(|e| anyhow::Error::msg(e).context(format!("Url: {:?}", self.state.endpoint)))? + .map_err(|e| anyhow::Error::msg(e).context(format!("Url: {:?}", self.state.endpoint)))?; + let status = response.status(); + let body_bytes = hyper::body::to_bytes(response.into_body()).await?; + if status != StatusCode::OK { + // Not active + if status == StatusCode::NOT_FOUND { + trace!("Requested remote config and but remote config not active"); + return Ok(Some(vec![])); + } + + let response_body = String::from_utf8(body_bytes.to_vec()).unwrap_or_default(); + anyhow::bail!("Server did not accept remote config request: {response_body}"); + } + + // Nothing changed + if body_bytes.len() <= 3 { + trace!("Requested remote config and got an empty reply"); + return Ok(None); + } + + let response: ClientGetConfigsResponse = + serde_json::from_str(&String::from_utf8_lossy(body_bytes.as_ref()))?; + + let decoded_targets = + base64::engine::general_purpose::STANDARD.decode(response.targets.as_slice())?; + let targets_list = TargetsList::try_parse(decoded_targets.as_slice()).map_err(|e| { + anyhow::Error::msg(e).context(format!( + "Decoded targets reply: {}", + String::from_utf8_lossy(decoded_targets.as_slice()) + )) + })?; + + opaque_state.opaque_backend_state = targets_list + .signed + .custom + .opaque_backend_state + .as_bytes() + .to_vec(); + + debug!( + "Received remote config of length {}, containing {:?} paths for target {:?}", + body_bytes.len(), + targets_list.signed.targets.keys().collect::>(), + target + ); + + let incoming_files: HashMap<_, _> = response + .target_files + .iter() + .map(|f| (f.path.as_str(), f.raw.as_slice())) + .collect(); + + // This lock must be held continuously at least between the existence check + // (target_files.get()) and the insertion later on. Makes more sense to just hold it + // continuously + let mut target_files = self.state.target_files_by_path.lock().unwrap(); + + let mut config_paths: HashSet> = HashSet::new(); + for path in response.client_configs.iter() { + match RemoteConfigPath::try_parse(path) { + // SAFTEY: The lifetime of RemoteConfigPathRef is tied to the config_paths + // Vec + Ok(parsed) => { + config_paths.insert(unsafe { + transmute::, RemoteConfigPathRef<'_>>(parsed) + }); + } + Err(e) => warn!("Failed parsing remote config path: {path} - {e:?}"), + } + } + + if self.state.expire_unused_files { + target_files.retain(|k, _| config_paths.contains(&(&**k).into())); + } + + for (path, target_file) in targets_list.signed.targets { + fn hash_sha256(v: &[u8]) -> String { + format!("{:x}", Sha256::digest(v)) + } + fn hash_sha512(v: &[u8]) -> String { + format!("{:x}", Sha512::digest(v)) + } + let (hasher, hash) = if let Some(sha256) = target_file.hashes.get("sha256") { + (hash_sha256 as fn(&[u8]) -> String, *sha256) + } else if let Some(sha512) = target_file.hashes.get("sha512") { + (hash_sha512 as fn(&[u8]) -> String, *sha512) + } else { + warn!("Found a target file without hashes at path {path}"); + continue; + }; + let parsed_path = match RemoteConfigPath::try_parse(path) { + Ok(parsed_path) => parsed_path, + Err(e) => { + warn!("Failed parsing remote config path: {path} - {e:?}"); + continue; + } + }; + let handle = if let Some(StoredTargetFile { + hash: old_hash, + handle, + .. + }) = target_files.get(&parsed_path as &dyn RemoteConfigPathType) + { + if old_hash == hash { + continue; + } + Some(handle.clone()) + } else { + None + }; + if let Some(raw_file) = incoming_files.get(path) { + if let Ok(decoded) = base64::engine::general_purpose::STANDARD.decode(raw_file) { + let computed_hash = hasher(decoded.as_slice()); + if hash != computed_hash { + anyhow::bail!("Computed hash of file {computed_hash} did not match remote config targets file hash {hash} for path {path}: file: {}", String::from_utf8_lossy(decoded.as_slice())); + } + if let Some(version) = target_file.try_parse_version() { + debug!( + "Fetched new remote config file at path {path} targeting {target:?}" + ); + + let parsed_path: Arc = Arc::new(parsed_path.into()); + target_files.insert( + parsed_path.clone(), + StoredTargetFile { + hash: computed_hash, + state: ConfigState { + id: parsed_path.config_id.to_string(), + version, + product: parsed_path.product.to_string(), + apply_state: 2, // Acknowledged + apply_error: "".to_string(), + }, + meta: TargetFileMeta { + path: path.to_string(), + length: decoded.len() as i64, + hashes: target_file + .hashes + .iter() + .map(|(algorithm, hash)| TargetFileHash { + algorithm: algorithm.to_string(), + hash: hash.to_string(), + }) + .collect(), + }, + handle: if let Some(handle) = handle { + self.file_storage.update(&handle, version, decoded)?; + handle + } else { + self.file_storage.store(version, parsed_path, decoded)? + }, + expiring: false, + }, + ); + } else { + anyhow::bail!("Failed parsing version from remote config path {path}"); + } + } else { + anyhow::bail!( + "Failed base64 decoding config for path {path}: {}", + String::from_utf8_lossy(raw_file) + ) + } + } else { + anyhow::bail!( + "Found changed config data for path {path}, but no file; existing files: {:?}", + incoming_files.keys().collect::>() + ) + } + } + + let mut configs = Vec::with_capacity(config_paths.len()); + for config in config_paths.iter() { + if let Some(target_file) = target_files.get_mut(config as &dyn RemoteConfigPathType) { + target_file.expiring = false; + configs.push(target_file.handle.clone()); + } else { + anyhow::bail!("Found {config} in client_configs response, but it isn't stored."); + } + } + + opaque_state.targets_version = targets_list.signed.version as u64; + opaque_state.last_configs = response.client_configs; + opaque_state.last_config_paths = config_paths; + Ok(Some(configs)) + } +} + +fn get_product_endpoint(_subdomain: &str, endpoint: &Endpoint) -> Endpoint { + let mut parts = endpoint.url.clone().into_parts(); + parts.path_and_query = Some(PathAndQuery::from_static("/v0.7/config")); + Endpoint { + url: hyper::Uri::from_parts(parts).unwrap(), + api_key: endpoint.api_key.clone(), + test_token: endpoint.test_token.clone(), + ..*endpoint + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::fetch::test_server::RemoteConfigServer; + use crate::RemoteConfigSource; + use http::Response; + use hyper::Body; + use lazy_static::lazy_static; + + lazy_static! { + pub static ref PATH_FIRST: RemoteConfigPath = RemoteConfigPath { + source: RemoteConfigSource::Employee, + product: RemoteConfigProduct::ApmTracing, + config_id: "1234".to_string(), + name: "config".to_string(), + }; + pub static ref PATH_SECOND: RemoteConfigPath = RemoteConfigPath { + source: RemoteConfigSource::Employee, + product: RemoteConfigProduct::ApmTracing, + config_id: "9876".to_string(), + name: "config".to_string(), + }; + pub static ref DUMMY_TARGET: Arc = Arc::new(Target { + service: "service".to_string(), + env: "env".to_string(), + app_version: "1.3.5".to_string(), + }); + } + + static DUMMY_RUNTIME_ID: &str = "3b43524b-a70c-45dc-921d-34504e50c5eb"; + + #[derive(Default)] + pub struct Storage { + pub files: Mutex, Arc>>>, + } + + pub struct PathStore { + path: Arc, + storage: Arc, + pub data: Arc>, + } + + #[derive(Debug, Eq, PartialEq)] + pub struct DataStore { + pub version: u64, + pub contents: String, + } + + impl Drop for PathStore { + fn drop(&mut self) { + self.storage.files.lock().unwrap().remove(&self.path); + } + } + + impl FileStorage for Arc { + type StoredFile = PathStore; + + fn store( + &self, + version: u64, + path: Arc, + contents: Vec, + ) -> anyhow::Result> { + let data = Arc::new(Mutex::new(DataStore { + version, + contents: String::from_utf8(contents).unwrap(), + })); + assert!(self + .files + .lock() + .unwrap() + .insert(path.clone(), data.clone()) + .is_none()); + Ok(Arc::new(PathStore { + path: path.clone(), + storage: self.clone(), + data, + })) + } + + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()> { + *file.data.lock().unwrap() = DataStore { + version, + contents: String::from_utf8(contents).unwrap(), + }; + Ok(()) + } + } + + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_inactive() { + let server = RemoteConfigServer::spawn(); + let storage = Arc::new(Storage::default()); + let mut fetcher = ConfigFetcher::new( + storage.clone(), + Arc::new(ConfigFetcherState::new(server.dummy_invariants())), + ); + let mut opaque_state = ConfigClientState::default(); + + let mut response = Response::new(Body::from("")); + *response.status_mut() = StatusCode::NOT_FOUND; + *server.next_response.lock().unwrap() = Some(response); + + let fetched = fetcher + .fetch_once( + DUMMY_RUNTIME_ID, + DUMMY_TARGET.clone(), + "foo", + &mut opaque_state, + ) + .await + .unwrap() + .unwrap(); + + assert!(fetched.is_empty()); + } + + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_fetch_cache() { + let server = RemoteConfigServer::spawn(); + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![DUMMY_TARGET.clone()], 1, "v1".to_string()), + ); + + let storage = Arc::new(Storage::default()); + + let invariants = ConfigInvariants { + language: "php".to_string(), + tracer_version: "1.2.3".to_string(), + endpoint: server.endpoint.clone(), + products: vec![ + RemoteConfigProduct::ApmTracing, + RemoteConfigProduct::LiveDebugger, + ], + capabilities: vec![RemoteConfigCapabilities::ApmTracingCustomTags], + }; + + let mut fetcher = ConfigFetcher::new( + storage.clone(), + Arc::new(ConfigFetcherState::new(invariants)), + ); + let mut opaque_state = ConfigClientState::default(); + + { + opaque_state.last_error = Some("test".to_string()); + let fetched = fetcher + .fetch_once( + DUMMY_RUNTIME_ID, + DUMMY_TARGET.clone(), + "foo", + &mut opaque_state, + ) + .await + .unwrap() + .unwrap(); + + let req = server.last_request.lock().unwrap(); + let req = req.as_ref().unwrap(); + assert!(req.cached_target_files.is_empty()); + + let client = req.client.as_ref().unwrap(); + assert_eq!( + client.capabilities, + &[RemoteConfigCapabilities::ApmTracingCustomTags as u8] + ); + assert_eq!(client.products, &["APM_TRACING", "LIVE_DEBUGGING"]); + assert!(client.is_tracer); + assert!(!client.is_agent); + assert_eq!(client.id, "foo"); + + let state = client.state.as_ref().unwrap(); + assert_eq!(state.error, "test"); + assert!(state.has_error); + assert!(state.config_states.is_empty()); + assert!(state.backend_client_state.is_empty()); + + let tracer = client.client_tracer.as_ref().unwrap(); + assert_eq!(tracer.service, DUMMY_TARGET.service); + assert_eq!(tracer.env, DUMMY_TARGET.env); + assert_eq!(tracer.app_version, DUMMY_TARGET.app_version); + assert_eq!(tracer.runtime_id, DUMMY_RUNTIME_ID); + assert_eq!(tracer.language, "php"); + assert_eq!(tracer.tracer_version, "1.2.3"); + + assert_eq!( + String::from_utf8_lossy(&opaque_state.opaque_backend_state), + "some state" + ); + assert_eq!(fetched.len(), 1); + assert_eq!(storage.files.lock().unwrap().len(), 1); + + assert!(Arc::ptr_eq( + &fetched[0].data, + storage.files.lock().unwrap().get(&*PATH_FIRST).unwrap() + )); + assert_eq!(fetched[0].data.lock().unwrap().contents, "v1"); + assert_eq!(fetched[0].data.lock().unwrap().version, 1); + } + + { + let fetched = fetcher + .fetch_once( + DUMMY_RUNTIME_ID, + DUMMY_TARGET.clone(), + "foo", + &mut opaque_state, + ) + .await + .unwrap(); + assert!(fetched.is_none()); // no change + + let req = server.last_request.lock().unwrap(); + let req = req.as_ref().unwrap(); + assert_eq!(req.cached_target_files.len(), 1); + + let client = req.client.as_ref().unwrap(); + assert_eq!( + client.capabilities, + &[RemoteConfigCapabilities::ApmTracingCustomTags as u8] + ); + assert_eq!(client.products, &["APM_TRACING", "LIVE_DEBUGGING"]); + assert!(client.is_tracer); + assert!(!client.is_agent); + assert_eq!(client.id, "foo"); + + let state = client.state.as_ref().unwrap(); + assert!(!state.has_error); + assert!(!state.config_states.is_empty()); + assert!(!state.backend_client_state.is_empty()); + + let cached = &req.cached_target_files[0]; + assert_eq!(cached.path, PATH_FIRST.to_string()); + assert_eq!(cached.length, 2); + assert_eq!(cached.hashes.len(), 1); + } + + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![DUMMY_TARGET.clone()], 2, "v2".to_string()), + ); + server.files.lock().unwrap().insert( + PATH_SECOND.clone(), + (vec![DUMMY_TARGET.clone()], 1, "X".to_string()), + ); + + { + let fetched = fetcher + .fetch_once( + DUMMY_RUNTIME_ID, + DUMMY_TARGET.clone(), + "foo", + &mut opaque_state, + ) + .await + .unwrap() + .unwrap(); + assert_eq!(fetched.len(), 2); + assert_eq!(storage.files.lock().unwrap().len(), 2); + + let (first, second) = if fetched[0].data.lock().unwrap().version == 2 { + (0, 1) + } else { + (1, 0) + }; + + assert!(Arc::ptr_eq( + &fetched[first].data, + storage.files.lock().unwrap().get(&*PATH_FIRST).unwrap() + )); + assert_eq!(fetched[first].data.lock().unwrap().contents, "v2"); + assert_eq!(fetched[first].data.lock().unwrap().version, 2); + + assert!(Arc::ptr_eq( + &fetched[second].data, + storage.files.lock().unwrap().get(&*PATH_SECOND).unwrap() + )); + assert_eq!(fetched[second].data.lock().unwrap().contents, "X"); + assert_eq!(fetched[second].data.lock().unwrap().version, 1); + } + + { + let fetched = fetcher + .fetch_once( + DUMMY_RUNTIME_ID, + DUMMY_TARGET.clone(), + "foo", + &mut opaque_state, + ) + .await + .unwrap(); + assert!(fetched.is_none()); // no change + } + + server.files.lock().unwrap().remove(&*PATH_FIRST); + + { + let fetched = fetcher + .fetch_once( + DUMMY_RUNTIME_ID, + DUMMY_TARGET.clone(), + "foo", + &mut opaque_state, + ) + .await + .unwrap() + .unwrap(); + assert_eq!(fetched.len(), 1); + assert_eq!(storage.files.lock().unwrap().len(), 1); + } + } +} diff --git a/remote-config/src/fetch/mod.rs b/remote-config/src/fetch/mod.rs new file mode 100644 index 000000000..a14319587 --- /dev/null +++ b/remote-config/src/fetch/mod.rs @@ -0,0 +1,16 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +mod fetcher; +mod multitarget; +mod shared; +mod single; +#[cfg(any(test, feature = "test"))] +pub mod test_server; + +#[allow(clippy::useless_attribute)] // different clippy versions are differently picky +#[cfg_attr(test, allow(ambiguous_glob_reexports))] // ignore mod tests re-export +pub use fetcher::*; +pub use multitarget::*; +pub use shared::*; +pub use single::*; diff --git a/remote-config/src/fetch/multitarget.rs b/remote-config/src/fetch/multitarget.rs new file mode 100644 index 000000000..f87b134c8 --- /dev/null +++ b/remote-config/src/fetch/multitarget.rs @@ -0,0 +1,789 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::fetch::{ + ConfigApplyState, ConfigFetcherState, ConfigInvariants, FileStorage, RefcountedFile, + RefcountingStorage, SharedFetcher, +}; +use crate::Target; +use futures_util::future::Shared; +use futures_util::FutureExt; +use manual_future::ManualFuture; +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; +use std::default::Default; +use std::fmt::Debug; +use std::hash::Hash; +use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::select; +use tokio::sync::Semaphore; +use tokio::time::Instant; +use tracing::{debug, error, trace}; + +/// MultiTargetFetcher built on a set of SharedFetchers, managing multiple environments and services +/// at once. +/// It is able to keep track of all Target tuples as well as runtime_ids currently active. +/// The implementation chooses an arbitrary runtime id from the set of runtimes which have just a +/// single associated Target. If there is no such runtime id, it uses a synthetic runtime id. +/// This fetcher is designed for use cases with more than one Target tuple associated to a +/// specific runtime id and/or handling hundreds to thousands of different runtime ids with a low +/// amount of actual remote config clients. +pub struct MultiTargetFetcher +where + S::StoredFile: RefcountedFile + Sync + Send, + S: MultiTargetHandlers, +{ + /// All runtime ids belonging to a specific target + target_runtimes: Mutex, HashSet>>, + /// Keyed by runtime_id + runtimes: Mutex>>, + /// Refetch interval in nanoseconds. + pub remote_config_interval: AtomicU64, + /// All services by target in use + services: Mutex, KnownTarget>>, + pending_async_insertions: AtomicU32, + storage: RefcountingStorage, + /// Limit on how many fetchers can be active at once. + /// This functionality is mostly targeted at CLI programs which generally have their file name + /// as the service name. E.g. a phpt testsuite will generate one service for every single file. + /// The remote config backend can only handle a certain amount of services at once. + fetcher_semaphore: Semaphore, +} + +enum KnownTargetStatus { + Pending, + Alive, + RemoveAt(Instant), + Removing(Shared>), +} + +struct KnownTarget { + refcount: u32, + status: Arc>, + synthetic_id: bool, + runtimes: HashSet, + fetcher: Arc, +} + +impl Drop for KnownTarget { + fn drop(&mut self) { + self.fetcher.cancel(); + } +} + +pub trait NotifyTarget: Sync + Send + Sized + Hash + Eq + Clone + Debug { + fn notify(&self); +} + +pub trait MultiTargetHandlers { + fn fetched(&self, target: &Arc, files: &[Arc]) -> bool; + + fn expired(&self, target: &Arc); + + fn dead(&self); +} + +struct RuntimeInfo { + notify_target: N, + targets: HashMap, u32>, +} + +impl + MultiTargetFetcher +where + S::StoredFile: RefcountedFile + Sync + Send, + S: MultiTargetHandlers, +{ + pub const DEFAULT_CLIENTS_LIMIT: u32 = 100; + + pub fn new(storage: S, invariants: ConfigInvariants) -> Arc { + Arc::new(MultiTargetFetcher { + storage: RefcountingStorage::new(storage, ConfigFetcherState::new(invariants)), + target_runtimes: Mutex::new(Default::default()), + runtimes: Mutex::new(Default::default()), + remote_config_interval: AtomicU64::new(5_000_000_000), + services: Mutex::new(Default::default()), + pending_async_insertions: AtomicU32::new(0), + fetcher_semaphore: Semaphore::new(Self::DEFAULT_CLIENTS_LIMIT as usize), + }) + } + + pub fn is_dead(&self) -> bool { + self.services.lock().unwrap().is_empty() + && self.pending_async_insertions.load(Ordering::Relaxed) == 0 + } + + /// Allow for more than DEFAULT_CLIENTS_LIMIT fetchers running simultaneously + pub fn increase_clients_limit(&self, increase: u32) { + self.fetcher_semaphore.add_permits(increase as usize); + } + + fn generate_synthetic_id() -> String { + uuid::Uuid::new_v4().to_string() + } + + fn remove_target(self: &Arc, runtime_id: &str, target: &Arc) { + let mut services = self.services.lock().unwrap(); + // "goto" like handling to drop the known_service borrow and be able to change services + 'service_handling: { + 'drop_service: { + let known_service = services.get_mut(target).unwrap(); + known_service.refcount = if known_service.refcount == 1 { + known_service.runtimes.remove(runtime_id); + let mut status = known_service.status.lock().unwrap(); + *status = match *status { + KnownTargetStatus::Pending => break 'drop_service, + KnownTargetStatus::Alive => { + KnownTargetStatus::RemoveAt(Instant::now() + Duration::from_secs(3666)) + } + KnownTargetStatus::RemoveAt(_) | KnownTargetStatus::Removing(_) => { + unreachable!() + } + }; + 0 + } else { + if *known_service.fetcher.runtime_id.lock().unwrap() == runtime_id { + 'changed_rt_id: { + for (id, runtime) in self.runtimes.lock().unwrap().iter() { + if runtime.targets.len() == 1 + && runtime.targets.contains_key(target) + { + *known_service.fetcher.runtime_id.lock().unwrap() = + id.to_string(); + break 'changed_rt_id; + } + } + known_service.synthetic_id = true; + *known_service.fetcher.runtime_id.lock().unwrap() = + Self::generate_synthetic_id(); + } + } + known_service.refcount - 1 + }; + break 'service_handling; + } + services.remove(target); + } + + let mut target_runtimes = self.target_runtimes.lock().unwrap(); + if if let Some(target_runtime) = target_runtimes.get_mut(target) { + target_runtime.remove(runtime_id); + target_runtime.is_empty() + } else { + false + } { + target_runtimes.remove(target); + } + } + + fn add_target(self: &Arc, synthetic_id: bool, runtime_id: &str, target: Arc) { + let mut target_runtimes = self.target_runtimes.lock().unwrap(); + match target_runtimes.entry(target.clone()) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => e.insert(HashSet::new()), + } + .insert(runtime_id.to_string()); + drop(target_runtimes); // unlock + + let mut services = self.services.lock().unwrap(); + match services.entry(target.clone()) { + Entry::Occupied(mut e) => { + let known_target = &mut e.get_mut(); + if known_target.refcount == 0 { + let mut status = known_target.status.lock().unwrap(); + match *status { + KnownTargetStatus::RemoveAt(_) => { + *status = KnownTargetStatus::Alive; + known_target.refcount = 1; + if synthetic_id && !known_target.synthetic_id { + known_target.synthetic_id = true; + *known_target.fetcher.runtime_id.lock().unwrap() = + Self::generate_synthetic_id(); + } + known_target.runtimes.insert(runtime_id.to_string()); + } + KnownTargetStatus::Removing(ref future) => { + let future = future.clone(); + // Avoid deadlocking between known_target.status and self.services + self.pending_async_insertions.fetch_add(1, Ordering::AcqRel); + let runtime_id = runtime_id.to_string(); + let this = self.clone(); + tokio::spawn(async move { + future.await; + this.add_target(synthetic_id, runtime_id.as_str(), target); + this.pending_async_insertions.fetch_sub(1, Ordering::AcqRel); + }); + return; + } + KnownTargetStatus::Alive | KnownTargetStatus::Pending => unreachable!(), + } + } else { + known_target.refcount += 1; + } + if !synthetic_id && known_target.synthetic_id { + known_target.synthetic_id = false; + *known_target.fetcher.runtime_id.lock().unwrap() = runtime_id.into(); + } + } + Entry::Vacant(e) => { + let runtime_id = if synthetic_id { + Self::generate_synthetic_id() + } else { + runtime_id.into() + }; + self.start_fetcher(e.insert(KnownTarget { + refcount: 1, + status: Arc::new(Mutex::new(KnownTargetStatus::Pending)), + synthetic_id, + runtimes: { + let mut set = HashSet::default(); + set.insert(runtime_id.to_string()); + set + }, + fetcher: Arc::new(SharedFetcher::new(target, runtime_id)), + })); + } + } + } + + pub fn add_runtime( + self: &Arc, + runtime_id: String, + notify_target: N, + target: &Arc, + ) { + trace!("Adding remote config runtime: {target:?} with runtime id {runtime_id}"); + match self.runtimes.lock().unwrap().entry(runtime_id) { + Entry::Occupied(mut runtime_entry) => { + let info = runtime_entry.get_mut(); + let primary_target = if info.targets.len() == 1 { + info.targets.keys().next().cloned() + } else { + None + }; + match info.targets.entry(target.clone()) { + Entry::Occupied(mut e) => *e.get_mut() += 1, + Entry::Vacant(e) => { + // it's the second usage here + if let Some(primary_target) = primary_target { + let mut services = self.services.lock().unwrap(); + let known_target = services.get_mut(&primary_target).unwrap(); + if !known_target.synthetic_id { + known_target.synthetic_id = true; + *known_target.fetcher.runtime_id.lock().unwrap() = + Self::generate_synthetic_id(); + } + } + e.insert(1); + self.add_target(true, runtime_entry.key(), target.clone()); + } + } + } + Entry::Vacant(e) => { + if self + .storage + .invariants() + .endpoint + .url + .scheme() + .map(|s| s.as_str() != "file") + == Some(true) + { + let info = RuntimeInfo { + notify_target, + targets: HashMap::from([(target.clone(), 1)]), + }; + self.add_target(info.targets.len() > 1, e.key(), target.clone()); + e.insert(info); + } + } + } + } + + pub fn delete_runtime(self: &Arc, runtime_id: &str, target: &Arc) { + trace!("Removing remote config runtime: {target:?} with runtime id {runtime_id}"); + { + let mut runtimes = self.runtimes.lock().unwrap(); + let last_removed = { + let info = match runtimes.get_mut(runtime_id) { + None => return, + Some(i) => i, + }; + match info.targets.entry(target.clone()) { + Entry::Occupied(mut e) => { + if *e.get() == 1 { + e.remove(); + } else { + *e.get_mut() -= 1; + return; + } + } + Entry::Vacant(_) => unreachable!("Missing target runtime"), + } + info.targets.is_empty() + }; + if last_removed { + runtimes.remove(runtime_id); + } + } + Self::remove_target(self, runtime_id, target); + } + + /// Sets the apply state on a stored file. + pub fn set_config_state(&self, file: &S::StoredFile, state: ConfigApplyState) { + self.storage.set_config_state(file, state) + } + + fn start_fetcher(self: &Arc, known_target: &KnownTarget) { + let this = self.clone(); + let fetcher = known_target.fetcher.clone(); + let status = known_target.status.clone(); + fetcher.interval.store( + self.remote_config_interval.load(Ordering::Relaxed), + Ordering::Relaxed, + ); + tokio::spawn(async move { + // Relatively primitive, no prioritization or anything. It is not expected that this + // semaphore is ever awaiting under standard usage. Can be improved if needed, e.g. + // sorted by amount of targets on the outstanding services or similar. + let _semaphore = this.fetcher_semaphore.acquire().await.unwrap(); + { + let mut status = status.lock().unwrap(); + if !matches!(*status, KnownTargetStatus::Pending) { + return; + } + *status = KnownTargetStatus::Alive; + } + + let (remove_future, remove_completer) = ManualFuture::new(); + let shared_future = remove_future.shared(); + + let inner_fetcher = fetcher.clone(); + let inner_this = this.clone(); + let fetcher_fut = fetcher + .run( + this.storage.clone(), + Box::new(move |files| { + let notify = inner_this + .storage + .storage + .fetched(&inner_fetcher.target, files); + + if notify { + // notify_targets is Hash + Eq + Clone, allowing us to deduplicate. Also + // avoid the lock during notifying + let mut notify_targets = HashSet::new(); + if let Some(runtimes) = inner_this + .target_runtimes + .lock() + .unwrap() + .get(&inner_fetcher.target) + { + for runtime_id in runtimes { + if let Some(runtime) = + inner_this.runtimes.lock().unwrap().get(runtime_id) + { + notify_targets.insert(runtime.notify_target.clone()); + } + } + } + + debug!("Notify {:?} about remote config changes", notify_targets); + for notify_target in notify_targets { + notify_target.notify(); + } + } + }), + ) + .shared(); + + loop { + { + let mut status = status.lock().unwrap(); + if let KnownTargetStatus::RemoveAt(instant) = *status { + // Voluntarily give up the semaphore for services in RemoveAt status if + // there are only few available permits + if this.fetcher_semaphore.available_permits() < 10 + || instant < Instant::now() + { + // We need to signal that we're in progress of removing to avoid race + // conditions + *status = KnownTargetStatus::Removing(shared_future.clone()); + // break here to drop mutex guard and avoid having status and services + // locked simultaneously + fetcher.cancel(); + break; + } + } + } // unlock mutex + + select! { + _ = tokio::time::sleep(Duration::from_nanos(fetcher.interval.load(Ordering::Relaxed))) => {}, + _ = fetcher_fut.clone() => { + break; + } + } + } + + this.storage.storage.expired(&fetcher.target); + + { + // scope lock before await + let mut services = this.services.lock().unwrap(); + services.remove(&fetcher.target); + if services.is_empty() && this.pending_async_insertions.load(Ordering::Relaxed) == 0 + { + this.storage.storage.dead(); + } + } + remove_completer.complete(()).await; + }); + } + + pub fn shutdown(&self) { + let services = self.services.lock().unwrap(); + for (target, service) in services.iter() { + let mut status = service.status.lock().unwrap(); + match *status { + KnownTargetStatus::Pending | KnownTargetStatus::Alive => { + error!("Trying to shutdown {:?} while still alive", target); + } + KnownTargetStatus::RemoveAt(_) => { + *status = KnownTargetStatus::RemoveAt(Instant::now()); + service.fetcher.cancel(); + } + KnownTargetStatus::Removing(_) => {} + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::fetch::fetcher::tests::*; + use crate::fetch::shared::tests::*; + use crate::fetch::test_server::RemoteConfigServer; + use crate::{RemoteConfigPath, Target}; + use manual_future::ManualFutureCompleter; + use std::hash::Hasher; + use std::sync::atomic::AtomicU8; + + #[derive(Clone)] + struct MultiFileStorage { + rc: RcFileStorage, + on_dead_completer: Arc>>>, + #[allow(clippy::type_complexity)] + recent_fetches: Arc, Vec>>>>, + awaiting_fetches: Arc, + awaited_fetched_done: Arc>>>, + expected_expirations: Arc, ManualFutureCompleter<()>>>>, + } + + impl MultiFileStorage { + pub fn await_fetches(&self, num: u8) -> ManualFuture<()> { + let (future, completer) = ManualFuture::new(); + + self.recent_fetches.lock().unwrap().clear(); + self.awaiting_fetches.store(num, Ordering::SeqCst); + *self.awaited_fetched_done.lock().unwrap() = Some(completer); + + future + } + + pub fn expect_expiration(&self, target: &Arc) -> ManualFuture<()> { + let (future, completer) = ManualFuture::new(); + self.expected_expirations + .lock() + .unwrap() + .insert(target.clone(), completer); + future + } + } + + impl MultiTargetHandlers for MultiFileStorage { + fn fetched(&self, target: &Arc, files: &[Arc]) -> bool { + match self.recent_fetches.lock().unwrap().entry(target.clone()) { + Entry::Occupied(_) => panic!("Double fetch without recent_fetches clear"), + Entry::Vacant(e) => { + e.insert(files.to_vec()); + } + } + + match self.awaiting_fetches.fetch_sub(1, Ordering::SeqCst) { + 2.. => {} + 1 => { + tokio::spawn( + self.awaited_fetched_done + .lock() + .unwrap() + .take() + .unwrap() + .complete(()), + ); + } + ..=0 => panic!("Got unexpected fetch"), + } + + true + } + + fn expired(&self, target: &Arc) { + tokio::spawn( + self.expected_expirations + .lock() + .unwrap() + .remove(target) + .unwrap() + .complete(()), + ); + } + + fn dead(&self) { + tokio::spawn( + self.on_dead_completer + .lock() + .unwrap() + .take() + .unwrap() + .complete(()), + ); + } + } + + impl FileStorage for MultiFileStorage { + type StoredFile = ::StoredFile; + + fn store( + &self, + version: u64, + path: Arc, + contents: Vec, + ) -> anyhow::Result> { + self.rc.store(version, path, contents) + } + + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()> { + self.rc.update(file, version, contents) + } + } + + #[derive(Default, Debug)] + struct NotifyState { + notifications: Mutex>, + } + + impl NotifyState { + fn assert_notified(&self, ids: &[u8]) { + let mut notified = std::mem::take(&mut *self.notifications.lock().unwrap()) + .into_iter() + .collect::>(); + notified.sort(); + assert_eq!(notified, ids); + } + } + + #[derive(Clone, Debug)] + struct Notifier { + id: u8, + state: Arc, + } + + impl Hash for Notifier { + fn hash(&self, state: &mut H) { + state.write_u8(self.id) + } + } + + impl PartialEq for Notifier { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } + } + + impl Eq for Notifier {} + + impl NotifyTarget for Notifier { + fn notify(&self) { + self.state.notifications.lock().unwrap().insert(self.id); + } + } + + static RT_ID_1: &str = "3b43524b-a70c-45dc-921d-34504e50c5eb"; + static RT_ID_2: &str = "ae588386-8464-43ba-bd3a-3e2d36b2c22c"; + static RT_ID_3: &str = "0125dff8-d9a7-4fd3-a0c2-0ca3b12816a1"; + + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_multi_fetcher() { + let server = RemoteConfigServer::spawn(); + let (on_dead, on_dead_completer) = ManualFuture::new(); + let storage = MultiFileStorage { + rc: RcFileStorage::default(), + on_dead_completer: Arc::new(Mutex::new(Some(on_dead_completer))), + recent_fetches: Default::default(), + awaiting_fetches: Default::default(), + awaited_fetched_done: Default::default(), + expected_expirations: Default::default(), + }; + let state = Arc::new(NotifyState::default()); + + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![DUMMY_TARGET.clone()], 1, "v1".to_string()), + ); + + let fut = storage.await_fetches(1); + + let fetcher = MultiTargetFetcher::::new( + storage.clone(), + server.dummy_invariants(), + ); + fetcher.remote_config_interval.store(1000, Ordering::SeqCst); + + fetcher.add_runtime( + RT_ID_1.to_string(), + Notifier { + id: 1, + state: state.clone(), + }, + &OTHER_TARGET, + ); + assert_eq!( + *fetcher + .services + .lock() + .unwrap() + .get(&*OTHER_TARGET) + .unwrap() + .fetcher + .runtime_id + .lock() + .unwrap(), + RT_ID_1 + ); + + fetcher.add_runtime( + RT_ID_1.to_string(), + Notifier { + id: 1, + state: state.clone(), + }, + &DUMMY_TARGET, + ); + fetcher.add_runtime( + RT_ID_2.to_string(), + Notifier { + id: 2, + state: state.clone(), + }, + &DUMMY_TARGET, + ); + + assert_eq!( + *fetcher + .services + .lock() + .unwrap() + .get(&*DUMMY_TARGET) + .unwrap() + .fetcher + .runtime_id + .lock() + .unwrap(), + RT_ID_2 + ); + assert_ne!( + *fetcher + .services + .lock() + .unwrap() + .get(&*OTHER_TARGET) + .unwrap() + .fetcher + .runtime_id + .lock() + .unwrap(), + RT_ID_1 + ); + + assert_eq!(fetcher.runtimes.lock().unwrap().len(), 2); // two runtimes + assert_eq!(fetcher.target_runtimes.lock().unwrap().len(), 2); // two fetchers + + fetcher.add_runtime( + RT_ID_3.to_string(), + Notifier { + id: 3, + state: state.clone(), + }, + &OTHER_TARGET, + ); + + fut.await; + state.assert_notified(&[1, 2]); + + let last_fetched: Vec<_> = storage + .recent_fetches + .lock() + .unwrap() + .get(&*DUMMY_TARGET) + .unwrap() + .iter() + .map(|p| p.store.data.clone()) + .collect(); + assert_eq!(last_fetched.len(), 1); + + let fut = storage.await_fetches(2); + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![OTHER_TARGET.clone()], 1, "v1".to_string()), + ); + + fut.await; + state.assert_notified(&[1, 2, 3]); + + let new_fetched: Vec<_> = storage + .recent_fetches + .lock() + .unwrap() + .get(&*OTHER_TARGET) + .unwrap() + .iter() + .map(|p| p.store.data.clone()) + .collect(); + assert_eq!( + storage + .recent_fetches + .lock() + .unwrap() + .get(&*OTHER_TARGET) + .unwrap() + .len(), + 1 + ); + if !Arc::ptr_eq(&new_fetched[0], &last_fetched[0]) { + assert_eq!( + *new_fetched[0].lock().unwrap(), + *last_fetched[0].lock().unwrap() + ); + } + + fetcher.delete_runtime(RT_ID_1, &OTHER_TARGET); + fetcher.delete_runtime(RT_ID_1, &DUMMY_TARGET); + fetcher.delete_runtime(RT_ID_2, &DUMMY_TARGET); + fetcher.delete_runtime(RT_ID_3, &OTHER_TARGET); + + fetcher.shutdown(); + storage.expect_expiration(&DUMMY_TARGET); + storage.expect_expiration(&OTHER_TARGET); + + on_dead.await + } +} diff --git a/remote-config/src/fetch/shared.rs b/remote-config/src/fetch/shared.rs new file mode 100644 index 000000000..8c5d266ac --- /dev/null +++ b/remote-config/src/fetch/shared.rs @@ -0,0 +1,620 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::fetch::{ + ConfigApplyState, ConfigClientState, ConfigFetcher, ConfigFetcherState, ConfigInvariants, + FileStorage, +}; +use crate::{RemoteConfigPath, Target}; +use std::collections::HashMap; +use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::select; +use tokio::time::sleep; +use tokio_util::sync::CancellationToken; +use tracing::error; + +/// Fetcher which does a run-loop and carefully manages state around files, with the following +/// guarantees: +/// - A file at a given RemoteConfigPath will not be recreated as long as it exists I.e. it will +/// always be drop()'ed before recreation. +/// - It does not leak files which are no longer in use, i.e. it refcounts across all remote config +/// clients sharing the same RefcountingStorage. +/// - The state is always valid, i.e. there will be no intermittently expired files. +pub struct SharedFetcher { + /// (env, service, version) tuple representing the basic remote config target + pub target: Arc, // could be theoretically also Mutex<>ed if needed + /// A unique runtime id. It must not be used by any other remote config client at the same + /// time. Is allowed to be changed at any time. + pub runtime_id: Arc>, + /// Each fetcher must have an unique id. Defaults to a random UUID. + pub client_id: String, + cancellation: CancellationToken, + /// Refetch interval in nanoseconds. + pub interval: AtomicU64, +} + +pub struct FileRefcountData { + /// Primary refcounter: + /// - When active (dropped_run_id == 0), the amount of runners holding it since the last + /// remote config fetch. + /// - When inactive (dropped_run_id > 0), the remaining amount of runners actively fetching + /// remote config at the point in time dropped_run_id represents. + rc: AtomicU32, + /// 0, or point in time (see RunnersGeneration) where the file was moved to inactive. + dropped_run_id: AtomicU64, + pub path: Arc, + pub version: u64, +} + +impl FileRefcountData { + pub fn new(version: u64, path: Arc) -> Self { + FileRefcountData { + rc: AtomicU32::new(0), + dropped_run_id: AtomicU64::new(0), + path, + version, + } + } +} + +pub trait RefcountedFile { + fn refcount(&self) -> &FileRefcountData; + + fn incref(&self) -> u32 { + self.refcount().rc.fetch_add(1, Ordering::AcqRel) + } + + fn delref(&self) -> u32 { + self.refcount().rc.fetch_sub(1, Ordering::AcqRel) + } + + fn setref(&self, val: u32) { + self.refcount().rc.store(val, Ordering::SeqCst) + } + + fn set_expiring_run_id(&self, val: u64) { + self.refcount().dropped_run_id.store(val, Ordering::SeqCst) + } + + fn get_expiring_run_id(&self) -> u64 { + self.refcount().dropped_run_id.load(Ordering::Relaxed) + } +} + +#[derive(Default)] +struct RunnersGeneration { + /// This atomic contains both run_id and runners count; saving us from needing a Mutex. + val: AtomicU64, +} + +/// Atomic structure to represent the exact amount of remote config fetching runners at a specific +/// point in time represented by the generation (run_id), an integer which is only ever incremented. +/// This data structure helps contain which inactive files are pending deletion. +impl RunnersGeneration { + const RUN_ID_SHIFT: i32 = 20; + + /// Increments run_id and increments active runners. Returns first run_id to watch for. + fn inc_runners(&self) -> u64 { + (self + .val + .fetch_add((1 << Self::RUN_ID_SHIFT) + 1, Ordering::SeqCst) + >> Self::RUN_ID_SHIFT) + + 1 + } + + /// Increments run_id and decrements active runners. Returns last run_id to watch for. + fn dec_runners(&self) -> u64 { + self.val + .fetch_add((1 << Self::RUN_ID_SHIFT) - 1, Ordering::SeqCst) + >> Self::RUN_ID_SHIFT + } + + /// Returns amount of active runners and current run_id. + fn runners_and_run_id(&self) -> (u32, u64) { + let val = self.val.load(Ordering::Acquire); + ( + (val & ((1 << Self::RUN_ID_SHIFT) - 1)) as u32, + val >> Self::RUN_ID_SHIFT, + ) + } +} + +pub struct RefcountingStorage +where + S::StoredFile: RefcountedFile, +{ + pub storage: S, + state: Arc>, + /// Stores recently expired files. When a file refcount drops to zero, they're no longer sent + /// via the remote config client. However, there may still be in-flight requests, with telling + /// the remote config server that we know about these files. Thus, as long as these requests + /// are being processed, we must retain the files, as these would not be resent, leaving us + /// with a potentially incomplete configuration. + #[allow(clippy::type_complexity)] + inactive: Arc, Arc>>>, + /// times ConfigFetcher::::fetch_once() is currently being run + run_id: Arc, +} + +impl Clone for RefcountingStorage +where + S::StoredFile: RefcountedFile, +{ + fn clone(&self) -> Self { + RefcountingStorage { + storage: self.storage.clone(), + state: self.state.clone(), + inactive: self.inactive.clone(), + run_id: self.run_id.clone(), + } + } +} + +impl RefcountingStorage +where + S::StoredFile: RefcountedFile, +{ + pub fn new(storage: S, mut state: ConfigFetcherState) -> Self { + state.expire_unused_files = false; + RefcountingStorage { + storage, + state: Arc::new(state), + inactive: Default::default(), + run_id: Default::default(), + } + } + + fn expire_file(&mut self, file: Arc) { + let mut expire_lock = self.state.files_lock(); + let mut inactive = self.inactive.lock().unwrap(); + if file.refcount().rc.load(Ordering::Relaxed) != 0 { + return; // Don't do anything if refcount was increased while acquiring the lock + } + expire_lock.mark_expiring(&file.refcount().path); + let (runners, run_id) = self.run_id.runners_and_run_id(); + if runners > 0 { + file.setref(runners); + file.set_expiring_run_id(run_id); + inactive.insert(file.refcount().path.clone(), file); + } else { + expire_lock.expire_file(&file.refcount().path); + } + } + + /// Sets the apply state on a stored file. + pub fn set_config_state(&self, file: &S::StoredFile, state: ConfigApplyState) { + self.state.set_config_state(&file.refcount().path, state) + } + + pub fn invariants(&self) -> &ConfigInvariants { + &self.state.invariants + } +} + +impl FileStorage for RefcountingStorage +where + S::StoredFile: RefcountedFile, +{ + type StoredFile = S::StoredFile; + + fn store( + &self, + version: u64, + path: Arc, + contents: Vec, + ) -> anyhow::Result> { + self.storage.store(version, path, contents) + } + + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()> { + self.storage.update(file, version, contents) + } +} + +impl SharedFetcher { + pub fn new(target: Arc, runtime_id: String) -> Self { + SharedFetcher { + target, + runtime_id: Arc::new(Mutex::new(runtime_id)), + client_id: uuid::Uuid::new_v4().to_string(), + cancellation: CancellationToken::new(), + interval: AtomicU64::new(5_000_000_000), + } + } + + /// Runs. + /// On successful fetches on_fetch() is called with the new configuration. + /// Should not be called more than once. + #[allow(clippy::type_complexity)] + pub async fn run( + &self, + storage: RefcountingStorage, + on_fetch: Box>)>, + ) where + S::StoredFile: RefcountedFile, + { + let state = storage.state.clone(); + let mut fetcher = ConfigFetcher::new(storage, state); + + let mut opaque_state = ConfigClientState::default(); + + let mut last_files: Vec> = vec![]; + + loop { + let first_run_id = fetcher.file_storage.run_id.inc_runners(); + + let runtime_id = self.runtime_id.lock().unwrap().clone(); + let fetched = fetcher + .fetch_once( + runtime_id.as_str(), + self.target.clone(), + self.client_id.as_str(), + &mut opaque_state, + ) + .await; + + let clean_inactive = || { + let run_range = first_run_id..=fetcher.file_storage.run_id.dec_runners(); + let mut inactive = fetcher.file_storage.inactive.lock().unwrap(); + inactive.retain(|_, v| { + if run_range.contains(&v.get_expiring_run_id()) && v.delref() == 1 { + fetcher + .file_storage + .state + .files_lock() + .expire_file(&v.refcount().path); + false + } else { + true + } + }); + }; + + match fetched { + Ok(None) => clean_inactive(), // nothing changed + Ok(Some(files)) => { + if !files.is_empty() || !last_files.is_empty() { + for file in files.iter() { + if file.get_expiring_run_id() != 0 { + let mut inactive = fetcher.file_storage.inactive.lock().unwrap(); + if inactive.remove(&file.refcount().path).is_some() { + file.setref(0); + file.set_expiring_run_id(0); + } + } + file.incref(); + } + + clean_inactive(); + + for file in last_files { + if file.delref() == 1 { + fetcher.file_storage.expire_file(file); + } + } + + last_files = files; + + on_fetch(&last_files); + } else { + clean_inactive(); + } + } + Err(e) => { + clean_inactive(); + error!("{:?}", e); + } + } + + select! { + _ = self.cancellation.cancelled() => { break; } + _ = sleep(Duration::from_nanos(self.interval.load(Ordering::Relaxed))) => {} + } + } + + for file in last_files { + if file.delref() == 1 { + fetcher.file_storage.expire_file(file); + } + } + } + + /// Note that due to the async logic, a cancellation does not guarantee a strict ordering: + /// A final on_fetch call from within the run() method may happen after the cancellation. + /// Cancelling from within on_fetch callback is always final. + pub fn cancel(&self) { + self.cancellation.cancel(); + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::fetch::fetcher::tests::*; + use crate::fetch::test_server::RemoteConfigServer; + use crate::Target; + use futures::future::join_all; + use lazy_static::lazy_static; + use std::sync::Arc; + + lazy_static! { + pub static ref OTHER_TARGET: Arc = Arc::new(Target { + service: "other".to_string(), + env: "env".to_string(), + app_version: "7.8.9".to_string(), + }); + } + + pub struct RcPathStore { + pub store: Arc, + refcounted: FileRefcountData, + } + + impl RefcountedFile for RcPathStore { + fn refcount(&self) -> &FileRefcountData { + &self.refcounted + } + } + + #[derive(Default, Clone)] + pub struct RcFileStorage(Arc); + + impl FileStorage for RcFileStorage { + type StoredFile = RcPathStore; + + fn store( + &self, + version: u64, + path: Arc, + contents: Vec, + ) -> anyhow::Result> { + Ok(Arc::new(RcPathStore { + store: self.0.store(version, path.clone(), contents)?, + refcounted: FileRefcountData::new(version, path), + })) + } + + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()> { + self.0.update(&file.store, version, contents) + } + } + + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_single_fetcher() { + let server = RemoteConfigServer::spawn(); + let storage = RcFileStorage::default(); + let rc_storage = RefcountingStorage::new( + storage.clone(), + ConfigFetcherState::new(server.dummy_invariants()), + ); + + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![DUMMY_TARGET.clone()], 1, "v1".to_string()), + ); + + let fetcher = SharedFetcher::new( + DUMMY_TARGET.clone(), + "3b43524b-a70c-45dc-921d-34504e50c5eb".to_string(), + ); + let iteration = AtomicU32::new(0); + let inner_fetcher = unsafe { &*(&fetcher as *const SharedFetcher) }; + let inner_storage = storage.clone(); + fetcher + .run( + rc_storage, + Box::new( + move |fetched| match iteration.fetch_add(1, Ordering::SeqCst) { + 0 => { + assert_eq!(fetched.len(), 1); + assert_eq!(fetched[0].store.data.lock().unwrap().contents, "v1"); + + server.files.lock().unwrap().insert( + PATH_SECOND.clone(), + (vec![DUMMY_TARGET.clone()], 1, "X".to_string()), + ); + } + 1 => { + assert_eq!(fetched.len(), 2); + + server.files.lock().unwrap().remove(&*PATH_SECOND); + } + 2 => { + assert_eq!(fetched.len(), 1); + assert_eq!(inner_storage.0.files.lock().unwrap().len(), 1); + let req = server.last_request.lock().unwrap(); + let req = req.as_ref().unwrap(); + let client = req.client.as_ref().unwrap(); + let state = client.state.as_ref().unwrap(); + assert!(!state.has_error); + + inner_fetcher.cancel(); + } + _ => panic!("Unexpected"), + }, + ), + ) + .await; + + assert!(storage.0.files.lock().unwrap().is_empty()); + } + + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_parallel_fetchers() { + let server = RemoteConfigServer::spawn(); + let storage = RcFileStorage::default(); + let rc_storage = RefcountingStorage::new( + storage.clone(), + ConfigFetcherState::new(server.dummy_invariants()), + ); + + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + ( + vec![DUMMY_TARGET.clone(), OTHER_TARGET.clone()], + 1, + "v1".to_string(), + ), + ); + server.files.lock().unwrap().insert( + PATH_SECOND.clone(), + (vec![DUMMY_TARGET.clone()], 1, "X".to_string()), + ); + + let server_1 = server.clone(); + let server_1_storage = storage.clone(); + let server_first_1 = move || { + assert_eq!(server_1_storage.0.files.lock().unwrap().len(), 2); + server_1.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![OTHER_TARGET.clone()], 1, "v1".to_string()), + ); + server_1.files.lock().unwrap().insert( + PATH_SECOND.clone(), + ( + vec![DUMMY_TARGET.clone(), OTHER_TARGET.clone()], + 1, + "X".to_string(), + ), + ); + }; + let server_first_2 = server_first_1.clone(); + + let server_2 = server.clone(); + let server_2_storage = storage.clone(); + let server_second_1 = move || { + assert_eq!(server_2_storage.0.files.lock().unwrap().len(), 2); + server_2.files.lock().unwrap().insert( + PATH_FIRST.clone(), + (vec![DUMMY_TARGET.clone()], 2, "v2".to_string()), + ); + server_2.files.lock().unwrap().remove(&*PATH_SECOND); + }; + let server_second_2 = server_second_1.clone(); + + let server_3 = server.clone(); + let server_3_storage = storage.clone(); + let server_3_rc_storage = rc_storage.clone(); + let server_third_1 = move || { + // It may happen that the other fetcher is _right now_ doing a fetch. + // This leads to a race condition: + // - If the other fetcher is currently fetching, then the file will be inactive and + // dropped once its fetching ended. + // - If there's no other fetching active, it'll immediately drop the file. + let (runners, _) = server_3_rc_storage.run_id.runners_and_run_id(); + let (expected_files, expected_inactive) = if runners == 0 { (1, 0) } else { (2, 1) }; + assert_eq!( + server_3_rc_storage.inactive.lock().unwrap().len(), + expected_inactive + ); + // one file should be expired by now + assert_eq!( + server_3_storage.0.files.lock().unwrap().len(), + expected_files + ); + server_3.files.lock().unwrap().clear(); + }; + let server_third_2 = server_third_1.clone(); + + let fetcher_1 = SharedFetcher::new( + DUMMY_TARGET.clone(), + "3b43524b-a70c-45dc-921d-34504e50c5eb".to_string(), + ); + let fetcher_2 = SharedFetcher::new( + OTHER_TARGET.clone(), + "ae588386-8464-43ba-bd3a-3e2d36b2c22c".to_string(), + ); + let iteration = Arc::new(AtomicU32::new(0)); + let iteration_1 = iteration.clone(); + let iteration_2 = iteration.clone(); + let inner_fetcher_1 = unsafe { &*(&fetcher_1 as *const SharedFetcher) }; + let inner_fetcher_2 = unsafe { &*(&fetcher_2 as *const SharedFetcher) }; + join_all(vec![ + fetcher_1.run( + rc_storage.clone(), + Box::new( + move |fetched| match iteration_1.fetch_add(1, Ordering::SeqCst) { + i @ 0 | i @ 1 => { + assert_eq!(fetched.len(), 2); + + if i == 1 { + server_first_1(); + } + } + i @ 2 | i @ 3 => { + assert_eq!(fetched.len(), 1); + assert_eq!(fetched[0].store.data.lock().unwrap().contents, "X"); + + if i == 3 { + server_second_1(); + } + } + i @ 4 | i @ 5 => { + assert_eq!(fetched.len(), 1); + assert_eq!(fetched[0].store.data.lock().unwrap().contents, "v2"); + + if i == 5 { + server_third_1(); + } + } + 6 => { + assert_eq!(fetched.len(), 0); + + inner_fetcher_1.cancel(); + } + _ => panic!("Unexpected"), + }, + ), + ), + fetcher_2.run( + rc_storage, + Box::new( + move |fetched| match iteration_2.fetch_add(1, Ordering::SeqCst) { + i @ 0 | i @ 1 => { + assert_eq!(fetched.len(), 1); + assert_eq!(fetched[0].store.data.lock().unwrap().contents, "v1"); + + if i == 1 { + server_first_2(); + } + } + i @ 2 | i @ 3 => { + assert_eq!(fetched.len(), 2); + + if i == 3 { + server_second_2(); + } + } + i @ 4 | i @ 5 => { + assert_eq!(fetched.len(), 0); + + if i == 5 { + server_third_2(); + } + + inner_fetcher_2.cancel(); + } + _ => panic!("Unexpected"), + }, + ), + ), + ]) + .await; + + assert!(storage.0.files.lock().unwrap().is_empty()); + } +} diff --git a/remote-config/src/fetch/single.rs b/remote-config/src/fetch/single.rs new file mode 100644 index 000000000..5c1a5421b --- /dev/null +++ b/remote-config/src/fetch/single.rs @@ -0,0 +1,104 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::fetch::{ + ConfigApplyState, ConfigClientState, ConfigFetcher, ConfigFetcherState, ConfigInvariants, + FileStorage, +}; +use crate::file_change_tracker::{Change, ChangeTracker, FilePath, UpdatedFiles}; +use crate::{RemoteConfigPath, Target}; +use std::sync::Arc; + +/// Simple implementation +pub struct SingleFetcher { + fetcher: ConfigFetcher, + target: Arc, + runtime_id: String, + client_id: String, + opaque_state: ConfigClientState, +} + +impl SingleFetcher { + pub fn new(sink: S, target: Target, runtime_id: String, invariants: ConfigInvariants) -> Self { + SingleFetcher { + fetcher: ConfigFetcher::new(sink, Arc::new(ConfigFetcherState::new(invariants))), + target: Arc::new(target), + runtime_id, + client_id: uuid::Uuid::new_v4().to_string(), + opaque_state: ConfigClientState::default(), + } + } + + pub fn with_client_id(mut self, client_id: String) -> Self { + self.client_id = client_id; + self + } + + /// Polls the current runtime config files. + pub async fn fetch_once(&mut self) -> anyhow::Result>>> { + self.fetcher + .fetch_once( + self.runtime_id.as_str(), + self.target.clone(), + self.client_id.as_str(), + &mut self.opaque_state, + ) + .await + } + + pub fn get_client_id(&self) -> &String { + &self.client_id + } + + /// Sets the apply state on a stored file. + pub fn set_config_state(&self, file: &RemoteConfigPath, state: ConfigApplyState) { + self.fetcher.set_config_state(file, state) + } +} + +pub struct SingleChangesFetcher +where + S::StoredFile: FilePath, +{ + changes: ChangeTracker, + pub fetcher: SingleFetcher, +} + +impl SingleChangesFetcher +where + S::StoredFile: FilePath, +{ + pub fn new(sink: S, target: Target, runtime_id: String, invariants: ConfigInvariants) -> Self { + SingleChangesFetcher { + changes: ChangeTracker::default(), + fetcher: SingleFetcher::new(sink, target, runtime_id, invariants), + } + } + + pub fn with_client_id(mut self, client_id: String) -> Self { + self.fetcher = self.fetcher.with_client_id(client_id); + self + } + + /// Polls for new changes + pub async fn fetch_changes(&mut self) -> anyhow::Result, R>>> + where + S: UpdatedFiles, + { + Ok(match self.fetcher.fetch_once().await? { + None => vec![], + Some(files) => self + .changes + .get_changes(files, self.fetcher.fetcher.file_storage.updated()), + }) + } + + pub fn get_client_id(&self) -> &String { + self.fetcher.get_client_id() + } + + /// Sets the apply state on a stored file. + pub fn set_config_state(&self, file: &S::StoredFile, state: ConfigApplyState) { + self.fetcher.set_config_state(file.path(), state) + } +} diff --git a/remote-config/src/fetch/test_server.rs b/remote-config/src/fetch/test_server.rs new file mode 100644 index 000000000..2928469ec --- /dev/null +++ b/remote-config/src/fetch/test_server.rs @@ -0,0 +1,218 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::fetch::ConfigInvariants; +use crate::targets::{TargetData, TargetsCustom, TargetsData, TargetsList}; +use crate::{RemoteConfigCapabilities, RemoteConfigPath, RemoteConfigProduct, Target}; +use base64::Engine; +use datadog_trace_protobuf::remoteconfig::{ + ClientGetConfigsRequest, ClientGetConfigsResponse, File, +}; +use ddcommon::Endpoint; +use http::{Request, Response}; +use hyper::service::{make_service_fn, service_fn}; +use hyper::{Body, Server}; +use serde_json::value::to_raw_value; +use sha2::{Digest, Sha256}; +use std::collections::HashMap; +use std::convert::Infallible; +use std::net::TcpListener; +use std::sync::{Arc, Mutex}; +use time::OffsetDateTime; +use tokio::select; +use tokio::sync::mpsc::Sender; + +pub struct RemoteConfigServer { + pub last_request: Mutex>, + #[allow(clippy::type_complexity)] + pub files: Mutex>, u64, String)>>, + pub next_response: Mutex>>, + pub endpoint: Endpoint, + #[allow(dead_code)] // stops receiver on drop + shutdown_complete_tx: Sender<()>, +} + +impl RemoteConfigServer { + pub fn spawn() -> Arc { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let (shutdown_complete_tx, mut shutdown_complete_rx) = tokio::sync::mpsc::channel::<()>(1); + let server = Arc::new(RemoteConfigServer { + last_request: Mutex::new(None), + files: Default::default(), + next_response: Mutex::new(None), + endpoint: Endpoint::from_slice(&format!("http://127.0.0.1:{port}/")), + shutdown_complete_tx, + }); + let this = server.clone(); + tokio::spawn(async move { + let service = make_service_fn(|_conn| { + let this = this.clone(); + async move { + Ok::<_, Infallible>(service_fn(move |req: Request| { + let this = this.clone(); + async move { + let body_bytes = hyper::body::to_bytes(req.into_body()).await.unwrap(); + let request: ClientGetConfigsRequest = serde_json::from_str( + &String::from_utf8(body_bytes.to_vec()).unwrap(), + ) + .unwrap(); + let response = + if let Some(response) = this.next_response.lock().unwrap().take() { + response + } else { + let known: HashMap<_, _> = request + .cached_target_files + .iter() + .map(|m| (m.path.clone(), m.hashes[0].hash.clone())) + .collect(); + let files = this.files.lock().unwrap(); + let applied_files: HashMap<_, _> = files + .iter() + .filter(|(_, (targets, _, _))| { + let tracer = request + .client + .as_ref() + .unwrap() + .client_tracer + .as_ref() + .unwrap(); + targets.iter().any(|t| { + t.service == tracer.service + && t.env == tracer.env + && t.app_version == tracer.app_version + }) + }) + .collect(); + let states = &request + .client + .as_ref() + .unwrap() + .state + .as_ref() + .unwrap() + .config_states; + if applied_files.len() == states.len() + && states.iter().all(|s| { + for (p, (_, v, _)) in applied_files.iter() { + if p.product.to_string() == s.product + && p.config_id == s.id + && *v == s.version + { + return true; + } + } + false + }) + { + Response::new(Body::from("{}")) + } else { + let target_info: Vec<_> = applied_files + .iter() + .map(|(p, (_, v, file))| { + ( + p.to_string(), + format!("{:x}", Sha256::digest(file)), + to_raw_value(v).unwrap(), + file.clone(), + ) + }) + .filter(|(p, hash, _, _)| { + if let Some(existing) = known.get(p) { + existing != hash + } else { + true + } + }) + .collect(); + let targets = TargetsList { + signatures: vec![], + signed: TargetsData { + _type: "", + custom: TargetsCustom { + agent_refresh_interval: Some(1000), + opaque_backend_state: "some state", + }, + expires: OffsetDateTime::from_unix_timestamp( + 253402300799, + ) + .unwrap(), + spec_version: "1.0.0", + targets: target_info + .iter() + .map(|(p, hash, version, _)| { + ( + p.as_str(), + TargetData { + custom: HashMap::from([( + "v", &**version, + )]), + hashes: HashMap::from([( + "sha256", + hash.as_str(), + )]), + length: 0, + }, + ) + }) + .collect(), + version: 1, + }, + }; + let response = ClientGetConfigsResponse { + roots: vec![], /* not checked */ + targets: base64::engine::general_purpose::STANDARD + .encode(serde_json::to_vec(&targets).unwrap()) + .into_bytes(), + target_files: target_info + .iter() + .map(|(p, _, _, file)| File { + path: p.to_string(), + raw: base64::engine::general_purpose::STANDARD + .encode(file) + .into_bytes(), + }) + .collect(), + client_configs: applied_files + .keys() + .map(|k| k.to_string()) + .collect(), + }; + Response::new(Body::from( + serde_json::to_vec(&response).unwrap(), + )) + } + }; + *this.last_request.lock().unwrap() = Some(request); + Ok::<_, Infallible>(response) + } + })) + } + }); + let server = Server::from_tcp(listener).unwrap().serve(service); + + select! { + server_result = server => { + if let Err(e) = server_result { + eprintln!("server connection error: {}", e); + } + }, + _ = shutdown_complete_rx.recv() => {}, + } + }); + server + } + + pub fn dummy_invariants(&self) -> ConfigInvariants { + ConfigInvariants { + language: "php".to_string(), + tracer_version: "1.2.3".to_string(), + endpoint: self.endpoint.clone(), + products: vec![ + RemoteConfigProduct::ApmTracing, + RemoteConfigProduct::LiveDebugger, + ], + capabilities: vec![RemoteConfigCapabilities::ApmTracingCustomTags], + } + } +} diff --git a/remote-config/src/file_change_tracker.rs b/remote-config/src/file_change_tracker.rs new file mode 100644 index 000000000..9600849d2 --- /dev/null +++ b/remote-config/src/file_change_tracker.rs @@ -0,0 +1,78 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::RemoteConfigPath; +use std::collections::HashSet; +use std::hash::{Hash, Hasher}; +use std::sync::Arc; + +pub trait FilePath { + fn path(&self) -> &RemoteConfigPath; +} + +pub trait UpdatedFiles { + fn updated(&self) -> Vec<(Arc, R)>; +} + +struct FilePathBasedArc(Arc); + +impl Hash for FilePathBasedArc { + fn hash(&self, state: &mut H) { + self.0.path().hash(state) + } +} + +impl PartialEq for FilePathBasedArc { + fn eq(&self, other: &Self) -> bool { + self.0.path() == other.0.path() + } +} + +impl Eq for FilePathBasedArc {} + +pub struct ChangeTracker { + last_files: HashSet>, +} + +impl Default for ChangeTracker { + fn default() -> Self { + ChangeTracker { + last_files: Default::default(), + } + } +} + +pub enum Change { + Add(S), + Update(S, R), + Remove(S), +} + +impl ChangeTracker { + pub fn get_changes( + &mut self, + files: Vec>, + updated: Vec<(Arc, R)>, + ) -> Vec, R>> { + let files = HashSet::from_iter(files.into_iter().map(FilePathBasedArc)); + let mut changes = vec![]; + + for file in files.difference(&self.last_files) { + changes.push(Change::Add(file.0.clone())); + } + + for file in self.last_files.difference(&files) { + changes.push(Change::Remove(file.0.clone())); + } + + for (updated_file, old_contents) in updated.into_iter() { + let file = FilePathBasedArc(updated_file); + if files.contains(&file) { + changes.push(Change::Update(file.0, old_contents)) + } + } + + self.last_files = files; + changes + } +} diff --git a/remote-config/src/file_storage.rs b/remote-config/src/file_storage.rs new file mode 100644 index 000000000..9060f3e13 --- /dev/null +++ b/remote-config/src/file_storage.rs @@ -0,0 +1,124 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::fetch::FileStorage; +use crate::file_change_tracker::{FilePath, UpdatedFiles}; +use crate::{RemoteConfigData, RemoteConfigPath}; +use std::ops::Deref; +use std::sync::{Arc, Mutex, MutexGuard}; + +/// A trivial local storage for remote config files. +pub struct RawFileStorage { + updated: Mutex>, P)>>, +} + +impl Default for RawFileStorage

{ + fn default() -> Self { + RawFileStorage { + updated: Mutex::default(), + } + } +} + +pub trait ParseFile +where + Self: Sized, +{ + fn parse(path: &RemoteConfigPath, contents: Vec) -> Self; +} + +impl UpdatedFiles, P> for RawFileStorage

{ + fn updated(&self) -> Vec<(Arc>, P)> { + std::mem::take(&mut *self.updated.lock().unwrap()) + } +} + +/// Mutable data: version and contents. +struct RawFileData

{ + version: u64, + contents: P, +} + +/// File contents and file metadata +pub struct RawFile

{ + path: Arc, + data: Mutex>, +} + +pub struct RawFileContentsGuard<'a, P>(MutexGuard<'a, RawFileData

>); + +impl<'a, P> Deref for RawFileContentsGuard<'a, P> { + type Target = P; + + fn deref(&self) -> &Self::Target { + &self.0.contents + } +} + +impl

RawFile

{ + /// Gets the contents behind a Deref impl (guarding a Mutex). + pub fn contents(&self) -> RawFileContentsGuard

{ + RawFileContentsGuard(self.data.lock().unwrap()) + } + + pub fn version(&self) -> u64 { + self.data.lock().unwrap().version + } +} + +impl

FilePath for RawFile

{ + fn path(&self) -> &RemoteConfigPath { + &self.path + } +} + +impl FileStorage for RawFileStorage

{ + type StoredFile = RawFile

; + + fn store( + &self, + version: u64, + path: Arc, + contents: Vec, + ) -> anyhow::Result> { + Ok(Arc::new(RawFile { + data: Mutex::new(RawFileData { + version, + contents: P::parse(&path, contents), + }), + path, + })) + } + + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()> { + let mut contents = P::parse(&file.path, contents); + let mut data = file.data.lock().unwrap(); + std::mem::swap(&mut data.contents, &mut contents); + self.updated.lock().unwrap().push((file.clone(), contents)); + data.version = version; + Ok(()) + } +} + +/// It simply stores the raw remote config file contents. +pub type SimpleFileStorage = RawFileStorage>; + +impl ParseFile for Vec { + fn parse(_path: &RemoteConfigPath, contents: Vec) -> Self { + contents + } +} + +/// Storing the remote config file contents in parsed form +pub type ParsedFileStorage = RawFileStorage>; + +impl ParseFile for anyhow::Result { + fn parse(path: &RemoteConfigPath, contents: Vec) -> Self { + RemoteConfigData::try_parse(path.product, contents.as_slice()) + } +} diff --git a/remote-config/src/lib.rs b/remote-config/src/lib.rs new file mode 100644 index 000000000..4818fcad4 --- /dev/null +++ b/remote-config/src/lib.rs @@ -0,0 +1,56 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +pub mod fetch; +pub mod file_change_tracker; +pub mod file_storage; +mod parse; +mod path; +mod targets; + +pub use parse::*; +pub use path::*; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct Target { + pub service: String, + pub env: String, + pub app_version: String, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum RemoteConfigCapabilities { + AsmActivation = 1, + AsmIpBlocking = 2, + AsmDdRules = 3, + AsmExclusions = 4, + AsmRequestBlocking = 5, + AsmResponseBlocking = 6, + AsmUserBlocking = 7, + AsmCustomRules = 8, + AsmCustomBlockingResponse = 9, + AsmTrustedIps = 10, + AsmApiSecuritySampleRate = 11, + ApmTracingSampleRate = 12, + ApmTracingLogsInjection = 13, + ApmTracingHttpHeaderTags = 14, + ApmTracingCustomTags = 15, + AsmProcessorOverrides = 16, + AsmCustomDataScanners = 17, + AsmExclusionData = 18, + ApmTracingEnabled = 19, + ApmTracingDataStreamsEnabled = 20, + AsmRaspSqli = 21, + AsmRaspLfi = 22, + AsmRaspSsrf = 23, + AsmRaspShi = 24, + AsmRaspXxe = 25, + AsmRaspRce = 26, + AsmRaspNosqli = 27, + AsmRaspXss = 28, + ApmTracingSampleRules = 29, + CsmActivation = 30, +} diff --git a/remote-config/src/parse.rs b/remote-config/src/parse.rs new file mode 100644 index 000000000..37cbd4063 --- /dev/null +++ b/remote-config/src/parse.rs @@ -0,0 +1,57 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::{RemoteConfigPath, RemoteConfigProduct, RemoteConfigSource}; +use datadog_dynamic_configuration::data::DynamicConfigFile; + +#[derive(Debug)] +pub enum RemoteConfigData { + DynamicConfig(DynamicConfigFile), + LiveDebugger(()), +} + +impl RemoteConfigData { + pub fn try_parse( + product: RemoteConfigProduct, + data: &[u8], + ) -> anyhow::Result { + Ok(match product { + RemoteConfigProduct::ApmTracing => { + RemoteConfigData::DynamicConfig(datadog_dynamic_configuration::parse_json(data)?) + } + RemoteConfigProduct::LiveDebugger => { + RemoteConfigData::LiveDebugger(/* placeholder */ ()) + } + }) + } +} + +impl From<&RemoteConfigData> for RemoteConfigProduct { + fn from(value: &RemoteConfigData) -> Self { + match value { + RemoteConfigData::DynamicConfig(_) => RemoteConfigProduct::ApmTracing, + RemoteConfigData::LiveDebugger(_) => RemoteConfigProduct::LiveDebugger, + } + } +} + +#[derive(Debug)] +pub struct RemoteConfigValue { + pub source: RemoteConfigSource, + pub data: RemoteConfigData, + pub config_id: String, + pub name: String, +} + +impl RemoteConfigValue { + pub fn try_parse(path: &str, data: &[u8]) -> anyhow::Result { + let path = RemoteConfigPath::try_parse(path)?; + let data = RemoteConfigData::try_parse(path.product, data)?; + Ok(RemoteConfigValue { + source: path.source, + data, + config_id: path.config_id.to_string(), + name: path.name.to_string(), + }) + } +} diff --git a/remote-config/src/path.rs b/remote-config/src/path.rs new file mode 100644 index 000000000..4c1eb2f11 --- /dev/null +++ b/remote-config/src/path.rs @@ -0,0 +1,243 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; +use std::borrow::Borrow; +use std::fmt::{Display, Formatter}; +use std::hash::{Hash, Hasher}; +use std::sync::Arc; + +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] +pub enum RemoteConfigSource { + Datadog(u64 /* org_id */), + Employee, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum RemoteConfigProduct { + ApmTracing, + LiveDebugger, +} + +impl Display for RemoteConfigProduct { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let str = match self { + RemoteConfigProduct::ApmTracing => "APM_TRACING", + RemoteConfigProduct::LiveDebugger => "LIVE_DEBUGGING", + }; + write!(f, "{}", str) + } +} + +#[derive(Debug, Clone, Eq, Hash, PartialEq)] +pub struct RemoteConfigPath { + pub source: RemoteConfigSource, + pub product: RemoteConfigProduct, + pub config_id: String, + pub name: String, +} + +#[derive(Debug, Clone, Eq, Hash, PartialEq)] +pub struct RemoteConfigPathRef<'a> { + pub source: RemoteConfigSource, + pub product: RemoteConfigProduct, + pub config_id: &'a str, + pub name: &'a str, +} + +impl RemoteConfigPath { + pub fn try_parse(path: &str) -> anyhow::Result { + let parts: Vec<_> = path.split('/').collect(); + Ok(RemoteConfigPathRef { + source: match parts[0] { + "datadog" => { + if parts.len() != 5 { + anyhow::bail!("{} is datadog and does not have exactly 5 parts", path); + } + RemoteConfigSource::Datadog(parts[1].parse()?) + } + "employee" => { + if parts.len() != 4 { + anyhow::bail!("{} is employee and does not have exactly 4 parts", path); + } + RemoteConfigSource::Employee + } + source => anyhow::bail!("Unknown source {}", source), + }, + product: match parts[parts.len() - 3] { + "APM_TRACING" => RemoteConfigProduct::ApmTracing, + "LIVE_DEBUGGING" => RemoteConfigProduct::LiveDebugger, + product => anyhow::bail!("Unknown product {}", product), + }, + config_id: parts[parts.len() - 2], + name: parts[parts.len() - 1], + }) + } +} + +impl<'a> Display for RemoteConfigPathRef<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.source { + RemoteConfigSource::Datadog(id) => write!( + f, + "datadog/{}/{}/{}/{}", + id, self.product, self.config_id, self.name + ), + RemoteConfigSource::Employee => { + write!( + f, + "employee/{}/{}/{}", + self.product, self.config_id, self.name + ) + } + } + } +} + +impl Display for RemoteConfigPath { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + RemoteConfigPathRef::from(self).fmt(f) + } +} + +impl<'a> From<&RemoteConfigPathRef<'a>> for RemoteConfigPath { + fn from(from: &RemoteConfigPathRef<'a>) -> RemoteConfigPath { + RemoteConfigPath { + source: from.source, + product: from.product, + config_id: from.config_id.to_owned(), + name: from.name.to_owned(), + } + } +} +impl<'a> From> for RemoteConfigPath { + fn from(from: RemoteConfigPathRef<'a>) -> RemoteConfigPath { + (&from).into() + } +} + +impl<'a> From<&'a RemoteConfigPath> for RemoteConfigPathRef<'a> { + fn from(from: &'a RemoteConfigPath) -> RemoteConfigPathRef<'a> { + RemoteConfigPathRef { + source: from.source, + product: from.product, + config_id: from.config_id.as_str(), + name: from.name.as_str(), + } + } +} + +impl RemoteConfigPathType for RemoteConfigPath { + fn source(&self) -> RemoteConfigSource { + self.source + } + + fn product(&self) -> RemoteConfigProduct { + self.product + } + + fn config_id(&self) -> &str { + self.config_id.as_str() + } + + fn name(&self) -> &str { + self.name.as_str() + } + + fn to_owned(&self) -> RemoteConfigPath { + self.clone() + } +} + +impl<'a> RemoteConfigPathType for &RemoteConfigPathRef<'a> { + fn source(&self) -> RemoteConfigSource { + self.source + } + + fn product(&self) -> RemoteConfigProduct { + self.product + } + + fn config_id(&self) -> &'a str { + self.config_id + } + + fn name(&self) -> &'a str { + self.name + } + + fn to_owned(&self) -> RemoteConfigPath { + (*self).into() + } +} + +impl<'a> RemoteConfigPathType for RemoteConfigPathRef<'a> { + fn source(&self) -> RemoteConfigSource { + self.source + } + + fn product(&self) -> RemoteConfigProduct { + self.product + } + + fn config_id(&self) -> &'a str { + self.config_id + } + + fn name(&self) -> &'a str { + self.name + } + + fn to_owned(&self) -> RemoteConfigPath { + self.into() + } +} + +pub trait RemoteConfigPathType { + fn source(&self) -> RemoteConfigSource; + fn product(&self) -> RemoteConfigProduct; + fn config_id(&self) -> &str; + fn name(&self) -> &str; + fn to_owned(&self) -> RemoteConfigPath; +} + +impl ToOwned for dyn RemoteConfigPathType + '_ { + type Owned = RemoteConfigPath; + + fn to_owned(&self) -> Self::Owned { + self.to_owned() + } +} + +impl<'a> Borrow for RemoteConfigPath { + fn borrow(&self) -> &(dyn RemoteConfigPathType + 'a) { + self + } +} + +impl<'a> Borrow for Arc { + fn borrow(&self) -> &(dyn RemoteConfigPathType + 'a) { + &**self + } +} + +impl Hash for dyn RemoteConfigPathType + '_ { + fn hash(&self, state: &mut H) { + self.source().hash(state); + self.product().hash(state); + self.config_id().hash(state); + self.name().hash(state); + } +} + +impl PartialEq for dyn RemoteConfigPathType + '_ { + fn eq(&self, other: &Self) -> bool { + self.config_id() == other.config_id() + && self.name() == other.name() + && self.source() == other.source() + && self.product() == other.product() + } +} + +impl Eq for dyn RemoteConfigPathType + '_ {} diff --git a/remote-config/src/targets.rs b/remote-config/src/targets.rs new file mode 100644 index 000000000..c0c07384d --- /dev/null +++ b/remote-config/src/targets.rs @@ -0,0 +1,65 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use serde::Deserialize; +use serde_json::value::RawValue; +use std::collections::HashMap; +use std::str::FromStr; +use time::OffsetDateTime; + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test"), derive(serde::Serialize))] +pub struct TargetsList<'a> { + #[serde(borrow)] + pub signatures: Vec>, + pub signed: TargetsData<'a>, +} + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test"), derive(serde::Serialize))] +pub struct TargetsSignature<'a> { + pub keyid: &'a str, + pub sig: &'a str, +} + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test"), derive(serde::Serialize))] +pub struct TargetsData<'a> { + pub _type: &'a str, + pub custom: TargetsCustom<'a>, + #[serde(with = "time::serde::iso8601")] + pub expires: OffsetDateTime, + pub spec_version: &'a str, + pub targets: HashMap<&'a str, TargetData<'a>>, + pub version: i64, +} + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test"), derive(serde::Serialize))] +pub struct TargetsCustom<'a> { + pub agent_refresh_interval: Option, + pub opaque_backend_state: &'a str, +} + +#[derive(Deserialize)] +#[cfg_attr(any(test, feature = "test"), derive(serde::Serialize))] +pub struct TargetData<'a> { + #[serde(borrow)] + pub custom: HashMap<&'a str, &'a RawValue>, + pub hashes: HashMap<&'a str, &'a str>, + pub length: u32, +} + +impl<'a> TargetsList<'a> { + pub fn try_parse(data: &'a [u8]) -> serde_json::error::Result { + serde_json::from_slice(data) + } +} + +impl<'a> TargetData<'a> { + pub fn try_parse_version(&self) -> Option { + self.custom + .get("v") + .and_then(|v| u64::from_str(v.get()).ok()) + } +} diff --git a/sidecar-ffi/Cargo.toml b/sidecar-ffi/Cargo.toml index 163deb527..68cc0aeba 100644 --- a/sidecar-ffi/Cargo.toml +++ b/sidecar-ffi/Cargo.toml @@ -18,6 +18,7 @@ datadog-ipc = { path = "../ipc" } ddcommon = { path = "../ddcommon" } ddcommon-ffi = { path = "../ddcommon-ffi", default-features = false } ddtelemetry-ffi = { path = "../ddtelemetry-ffi", default-features = false } +datadog-remote-config = { path = "../remote-config" } paste = "1" libc = "0.2" diff --git a/sidecar-ffi/cbindgen.toml b/sidecar-ffi/cbindgen.toml index 9413fc82f..dd0268147 100644 --- a/sidecar-ffi/cbindgen.toml +++ b/sidecar-ffi/cbindgen.toml @@ -34,4 +34,4 @@ must_use = "DDOG_CHECK_RETURN" [parse] parse_deps = true -include = ["ddcommon", "ddtelemetry", "datadog-sidecar", "ddtelemetry-ffi", "ddcommon-ffi", "datadog-ipc"] +include = ["ddcommon", "ddtelemetry", "datadog-sidecar", "ddtelemetry-ffi", "ddcommon-ffi", "datadog-ipc", "datadog-remote-config"] diff --git a/sidecar-ffi/src/lib.rs b/sidecar-ffi/src/lib.rs index 823ac4cb6..f91cf6ba3 100644 --- a/sidecar-ffi/src/lib.rs +++ b/sidecar-ffi/src/lib.rs @@ -4,6 +4,8 @@ use datadog_ipc::platform::{ FileBackedHandle, MappedMem, NamedShmHandle, PlatformHandle, ShmHandle, }; +use datadog_remote_config::fetch::ConfigInvariants; +use datadog_remote_config::{RemoteConfigCapabilities, RemoteConfigProduct, Target}; use datadog_sidecar::agent_remote_config::{ new_reader, reader_from_shm, AgentRemoteConfigEndpoint, AgentRemoteConfigWriter, }; @@ -15,6 +17,7 @@ use datadog_sidecar::service::{ blocking::{self, SidecarTransport}, InstanceId, QueueId, RuntimeMetadata, SerializedTracerHeaderTags, SessionConfig, SidecarAction, }; +use datadog_sidecar::shm_remote_config::RemoteConfigReader; use ddcommon::tag::Tag; use ddcommon::Endpoint; use ddcommon_ffi as ffi; @@ -33,6 +36,7 @@ use std::os::unix::prelude::FromRawFd; #[cfg(windows)] use std::os::windows::io::{FromRawHandle, RawHandle}; use std::slice; +use std::sync::Arc; use std::time::Duration; #[repr(C)] @@ -189,6 +193,56 @@ pub extern "C" fn ddog_agent_remote_config_reader_drop(_: Box>) { } +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn ddog_remote_config_reader_for_endpoint<'a>( + language: &ffi::CharSlice<'a>, + tracer_version: &ffi::CharSlice<'a>, + endpoint: &Endpoint, + service_name: ffi::CharSlice, + env_name: ffi::CharSlice, + app_version: ffi::CharSlice, + remote_config_products: *const RemoteConfigProduct, + remote_config_products_count: usize, + remote_config_capabilities: *const RemoteConfigCapabilities, + remote_config_capabilities_count: usize, +) -> Box { + Box::new(RemoteConfigReader::new( + &ConfigInvariants { + language: language.to_utf8_lossy().into(), + tracer_version: tracer_version.to_utf8_lossy().into(), + endpoint: endpoint.clone(), + products: slice::from_raw_parts(remote_config_products, remote_config_products_count) + .to_vec(), + capabilities: slice::from_raw_parts( + remote_config_capabilities, + remote_config_capabilities_count, + ) + .to_vec(), + }, + &Arc::new(Target { + service: service_name.to_utf8_lossy().into(), + env: env_name.to_utf8_lossy().into(), + app_version: app_version.to_utf8_lossy().into(), + }), + )) +} + +#[no_mangle] +pub extern "C" fn ddog_remote_config_read<'a>( + reader: &'a mut RemoteConfigReader, + data: &mut ffi::CharSlice<'a>, +) -> bool { + let (new, contents) = reader.read(); + // c_char may be u8 or i8 depending on target... convert it. + let contents: &[c_char] = unsafe { std::mem::transmute::<&[u8], &[c_char]>(contents) }; + *data = contents.into(); + new +} + +#[no_mangle] +pub extern "C" fn ddog_remote_config_reader_drop(_: Box) {} + #[no_mangle] pub extern "C" fn ddog_sidecar_transport_drop(_: Box) {} @@ -375,7 +429,7 @@ pub unsafe extern "C" fn ddog_sidecar_telemetry_flushServiceData( /// Enqueues a list of actions to be performed. #[no_mangle] #[allow(clippy::missing_safety_doc)] -pub unsafe extern "C" fn ddog_sidecar_telemetry_end( +pub unsafe extern "C" fn ddog_sidecar_lifecycle_end( transport: &mut Box, instance_id: &InstanceId, queue_id: &QueueId, @@ -429,22 +483,37 @@ pub unsafe extern "C" fn ddog_sidecar_session_set_config( session_id: ffi::CharSlice, agent_endpoint: &Endpoint, dogstatsd_endpoint: &Endpoint, - flush_interval_milliseconds: u64, - telemetry_heartbeat_interval_millis: u64, + language: ffi::CharSlice, + tracer_version: ffi::CharSlice, + flush_interval_milliseconds: u32, + telemetry_heartbeat_interval_millis: u32, force_flush_size: usize, force_drop_size: usize, log_level: ffi::CharSlice, log_path: ffi::CharSlice, + #[allow(unused)] // On FFI layer we cannot conditionally compile, so we need the arg + remote_config_notify_function: *mut c_void, + remote_config_products: *const RemoteConfigProduct, + remote_config_products_count: usize, + remote_config_capabilities: *const RemoteConfigCapabilities, + remote_config_capabilities_count: usize, ) -> MaybeError { + #[cfg(unix)] + let remote_config_notify_target = libc::getpid(); + #[cfg(windows)] + let remote_config_notify_target = remote_config_notify_function; try_c!(blocking::set_session_config( transport, + remote_config_notify_target, session_id.to_utf8_lossy().into(), &SessionConfig { endpoint: agent_endpoint.clone(), dogstatsd_endpoint: dogstatsd_endpoint.clone(), - flush_interval: Duration::from_millis(flush_interval_milliseconds), + language: language.to_utf8_lossy().into(), + tracer_version: tracer_version.to_utf8_lossy().into(), + flush_interval: Duration::from_millis(flush_interval_milliseconds as u64), telemetry_heartbeat_interval: Duration::from_millis( - telemetry_heartbeat_interval_millis + telemetry_heartbeat_interval_millis as u64 ), force_flush_size, force_drop_size, @@ -453,7 +522,17 @@ pub unsafe extern "C" fn ddog_sidecar_session_set_config( config::FromEnv::log_method() } else { LogMethod::File(String::from(log_path.to_utf8_lossy()).into()) - } + }, + remote_config_products: slice::from_raw_parts( + remote_config_products, + remote_config_products_count + ) + .to_vec(), + remote_config_capabilities: slice::from_raw_parts( + remote_config_capabilities, + remote_config_capabilities_count + ) + .to_vec(), }, )); @@ -540,6 +619,28 @@ pub unsafe extern "C" fn ddog_sidecar_send_trace_v04_bytes( MaybeError::None } +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn ddog_sidecar_set_remote_config_data( + transport: &mut Box, + instance_id: &InstanceId, + queue_id: &QueueId, + service_name: ffi::CharSlice, + env_name: ffi::CharSlice, + app_version: ffi::CharSlice, +) -> MaybeError { + try_c!(blocking::set_remote_config_data( + transport, + instance_id, + queue_id, + service_name.to_utf8_lossy().into(), + env_name.to_utf8_lossy().into(), + app_version.to_utf8_lossy().into(), + )); + + MaybeError::None +} + /// Dumps the current state of the sidecar. #[no_mangle] #[allow(clippy::missing_safety_doc)] diff --git a/sidecar-ffi/tests/sidecar.rs b/sidecar-ffi/tests/sidecar.rs index 25dd11f9c..1ca319b4b 100644 --- a/sidecar-ffi/tests/sidecar.rs +++ b/sidecar-ffi/tests/sidecar.rs @@ -12,6 +12,7 @@ macro_rules! assert_maybe_no_error { } use ddcommon::Endpoint; +use std::ptr::{null, null_mut}; use std::time::Duration; #[cfg(unix)] use std::{ @@ -90,12 +91,19 @@ fn test_ddog_sidecar_register_app() { ..Default::default() }, &Endpoint::default(), + "".into(), + "".into(), 1000, - 60000, 1000000, 10000000, + 10000000, "".into(), "".into(), + null_mut(), + null(), + 0, + null(), + 0, ); let meta = ddog_sidecar_runtimeMeta_build( @@ -135,12 +143,19 @@ fn test_ddog_sidecar_register_app() { ..Default::default() }, &Endpoint::default(), + "".into(), + "".into(), 1000, - 60000, 1000000, 10000000, + 10000000, "".into(), "".into(), + null_mut(), + null(), + 0, + null(), + 0, ); //TODO: Shutdown the service diff --git a/sidecar/Cargo.toml b/sidecar/Cargo.toml index 7ca427256..202c7d381 100644 --- a/sidecar/Cargo.toml +++ b/sidecar/Cargo.toml @@ -24,6 +24,7 @@ ddtelemetry = { path = "../ddtelemetry", features = ["tracing"] } datadog-trace-protobuf = { path = "../trace-protobuf" } datadog-trace-utils = { path = "../trace-utils" } datadog-trace-normalization = { path = "../trace-normalization" } +datadog-remote-config = { path = "../remote-config" } futures = { version = "0.3", default-features = false } manual_future = "0.1.1" @@ -37,12 +38,15 @@ datadog-ipc-macros = { path = "../ipc/macros" } rand = "0.8.3" regex = { version = "1" } -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } serde_with = "3.6.0" bincode = { version = "1.3.3" } +serde_json = "1.0" rmp-serde = "1.1.1" +base64 = "0.21.0" spawn_worker = { path = "../spawn_worker" } zwohash = "0.1.2" +sha2 = "0.10" sys-info = { version = "0.9.0" } tokio = { version = "1.35.1", features = [ "fs", @@ -98,7 +102,9 @@ microseh = "0.1.1" libc = { version = "0.2" } tempfile = { version = "3.3" } httpmock = "0.7.0" +datadog-remote-config = { path = "../remote-config", features = ["test"] } datadog-trace-utils = { path = "../trace-utils", features = ["test-utils"] } +datadog-dynamic-configuration = { path = "../dynamic-configuration", features = ["test"] } [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ diff --git a/sidecar/src/entry.rs b/sidecar/src/entry.rs index 77a4f3406..51a48cea3 100644 --- a/sidecar/src/entry.rs +++ b/sidecar/src/entry.rs @@ -98,6 +98,7 @@ where // Await everything else to completion _ = telemetry_handle.await; + server.shutdown(); _ = server.trace_flusher.join().await; Ok(()) @@ -113,9 +114,6 @@ where #[cfg(feature = "tokio-console")] console_subscriber::init(); - #[cfg(unix)] - let mut builder = tokio::runtime::Builder::new_current_thread(); - #[cfg(windows)] let mut builder = tokio::runtime::Builder::new_multi_thread(); let runtime = builder.enable_all().build()?; let _g = runtime.enter(); diff --git a/sidecar/src/lib.rs b/sidecar/src/lib.rs index f4aee9414..197b286f2 100644 --- a/sidecar/src/lib.rs +++ b/sidecar/src/lib.rs @@ -10,6 +10,7 @@ pub mod log; pub mod one_way_shared_memory; mod self_telemetry; pub mod setup; +pub mod shm_remote_config; mod tracer; mod watchdog; diff --git a/sidecar/src/one_way_shared_memory.rs b/sidecar/src/one_way_shared_memory.rs index 7382d2bc5..5949e5db0 100644 --- a/sidecar/src/one_way_shared_memory.rs +++ b/sidecar/src/one_way_shared_memory.rs @@ -207,6 +207,18 @@ impl>> OneWayShmWriter { handle.replace(mapped); } + pub fn as_slice(&self) -> &[u8] { + let handle = self.handle.lock().unwrap(); + let mapped = handle.as_ref().unwrap(); + let data = unsafe { &*(mapped.as_slice() as *const [u8] as *const RawData) }; + if data.meta.size > 0 { + let slice = data.as_slice(); + &slice[..slice.len() - 1] // ignore the trailing zero + } else { + b"" + } + } + pub fn size(&self) -> usize { self.handle .lock() diff --git a/sidecar/src/service/blocking.rs b/sidecar/src/service/blocking.rs index a016b73b1..f1c057689 100644 --- a/sidecar/src/service/blocking.rs +++ b/sidecar/src/service/blocking.rs @@ -191,6 +191,8 @@ pub fn register_service_and_flush_queued_actions( /// # Arguments /// /// * `transport` - The transport used for communication. +/// * `remote_config_notify_function` (windows): a function pointer to be invoked +/// * `pid` (unix): the pid of the remote process /// * `session_id` - The ID of the session. /// * `config` - The configuration to be set. /// @@ -199,11 +201,19 @@ pub fn register_service_and_flush_queued_actions( /// An `io::Result<()>` indicating the result of the operation. pub fn set_session_config( transport: &mut SidecarTransport, + #[cfg(unix)] pid: libc::pid_t, + #[cfg(windows)] remote_config_notify_function: *mut libc::c_void, session_id: String, config: &SessionConfig, ) -> io::Result<()> { + #[cfg(unix)] + let remote_config_notify_target = pid; + #[cfg(windows)] + let remote_config_notify_target = + crate::service::remote_configs::RemoteConfigNotifyFunction(remote_config_notify_function); transport.send(SidecarInterfaceRequest::SetSessionConfig { session_id, + remote_config_notify_target, config: config.clone(), }) } @@ -261,6 +271,39 @@ pub fn send_trace_v04_shm( }) } +/// Sets the state of the current remote config operation. +/// The queue id is shared with telemetry and the associated data will be freed upon a +/// `Lifecycle::Stop` event. +/// +/// # Arguments +/// +/// * `transport` - The transport used for communication. +/// * `instance_id` - The ID of the instance. +/// * `queue_id` - The unique identifier for the action in the queue. +/// * `service_name` - The name of the service. +/// * `env_name` - The name of the environment. +/// * `app_version` - The metadata of the runtime. +/// +/// # Returns +/// +/// An `io::Result<()>` indicating the result of the operation. +pub fn set_remote_config_data( + transport: &mut SidecarTransport, + instance_id: &InstanceId, + queue_id: &QueueId, + service_name: String, + env_name: String, + app_version: String, +) -> io::Result<()> { + transport.send(SidecarInterfaceRequest::SetRemoteConfigData { + instance_id: instance_id.clone(), + queue_id: *queue_id, + service_name, + env_name, + app_version, + }) +} + /// Sends DogStatsD actions. /// /// # Arguments diff --git a/sidecar/src/service/mod.rs b/sidecar/src/service/mod.rs index 1d612069f..8100ea29b 100644 --- a/sidecar/src/service/mod.rs +++ b/sidecar/src/service/mod.rs @@ -4,6 +4,7 @@ // imports for structs defined in this file use crate::config; use crate::service::telemetry::enqueued_telemetry_data::EnqueuedTelemetryData; +use datadog_remote_config::{RemoteConfigCapabilities, RemoteConfigProduct}; use ddcommon::tag::Tag; use ddcommon::Endpoint; use ddtelemetry::metrics::MetricContext; @@ -29,6 +30,7 @@ use sidecar_interface::{SidecarInterface, SidecarInterfaceRequest, SidecarInterf pub mod blocking; mod instance_id; mod queue_id; +mod remote_configs; mod request_identification; mod runtime_info; mod runtime_metadata; @@ -43,12 +45,16 @@ pub(crate) mod tracing; pub struct SessionConfig { pub endpoint: Endpoint, pub dogstatsd_endpoint: Endpoint, + pub language: String, + pub tracer_version: String, pub flush_interval: Duration, pub telemetry_heartbeat_interval: Duration, pub force_flush_size: usize, pub force_drop_size: usize, pub log_level: String, pub log_file: config::LogMethod, + pub remote_config_products: Vec, + pub remote_config_capabilities: Vec, } #[derive(Debug, Deserialize, Serialize)] diff --git a/sidecar/src/service/remote_configs.rs b/sidecar/src/service/remote_configs.rs new file mode 100644 index 000000000..e2d3499e9 --- /dev/null +++ b/sidecar/src/service/remote_configs.rs @@ -0,0 +1,126 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::shm_remote_config::{ShmRemoteConfigs, ShmRemoteConfigsGuard}; +use datadog_remote_config::fetch::{ConfigInvariants, NotifyTarget}; +use std::collections::hash_map::Entry; +use std::fmt::Debug; +use std::sync::{Arc, Mutex}; +use zwohash::HashMap; + +#[cfg(windows)] +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +pub struct RemoteConfigNotifyFunction(pub *mut libc::c_void); +#[cfg(windows)] +unsafe impl Send for RemoteConfigNotifyFunction {} +#[cfg(windows)] +unsafe impl Sync for RemoteConfigNotifyFunction {} +#[cfg(windows)] +impl Default for RemoteConfigNotifyFunction { + fn default() -> Self { + RemoteConfigNotifyFunction(std::ptr::null_mut()) + } +} + +#[cfg(windows)] +impl serde::Serialize for RemoteConfigNotifyFunction { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_u64(self.0 as u64) + } +} + +#[cfg(windows)] +impl<'de> serde::Deserialize<'de> for RemoteConfigNotifyFunction { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + >::deserialize(deserializer) + .map(|p| RemoteConfigNotifyFunction(p as *mut libc::c_void)) + } +} + +#[derive(Clone, Hash, Eq, PartialEq)] +#[cfg_attr(windows, derive(Debug))] +pub struct RemoteConfigNotifyTarget { + #[cfg(unix)] + pub pid: libc::pid_t, + #[cfg(windows)] + pub process_handle: crate::service::sidecar_server::ProcessHandle, + #[cfg(windows)] + // contains address in that process address space of the notification function + pub notify_function: RemoteConfigNotifyFunction, +} + +#[cfg(unix)] +impl Debug for RemoteConfigNotifyTarget { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.pid.fmt(f) + } +} + +impl NotifyTarget for RemoteConfigNotifyTarget { + #[cfg(not(windows))] + fn notify(&self) { + unsafe { libc::kill(self.pid, libc::SIGVTALRM) }; + } + + #[cfg(windows)] + #[allow(clippy::missing_transmute_annotations)] + fn notify(&self) { + unsafe { + let dummy = 0; + winapi::um::processthreadsapi::CreateRemoteThread( + self.process_handle.0, + std::ptr::null_mut(), + 0, + Some(std::mem::transmute(self.notify_function.0)), + &dummy as *const i32 as winapi::shared::minwindef::LPVOID, + 0, + std::ptr::null_mut(), + ); + } + } +} + +#[derive(Default, Clone)] +pub struct RemoteConfigs( + Arc>>>, +); +pub type RemoteConfigsGuard = ShmRemoteConfigsGuard; + +impl RemoteConfigs { + pub fn add_runtime( + &self, + invariants: ConfigInvariants, + runtime_id: String, + notify_target: RemoteConfigNotifyTarget, + env: String, + service: String, + app_version: String, + ) -> RemoteConfigsGuard { + match self.0.lock().unwrap().entry(invariants) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + let this = self.0.clone(); + let invariants = e.key().clone(); + e.insert(ShmRemoteConfigs::new( + invariants.clone(), + Box::new(move || { + this.lock().unwrap().remove(&invariants); + }), + )) + } + } + .add_runtime(runtime_id, notify_target, env, service, app_version) + } + + pub fn shutdown(&self) { + for (_, rc) in self.0.lock().unwrap().drain() { + rc.shutdown(); + } + } +} diff --git a/sidecar/src/service/runtime_info.rs b/sidecar/src/service/runtime_info.rs index f0ccd2fc5..4a4817845 100644 --- a/sidecar/src/service/runtime_info.rs +++ b/sidecar/src/service/runtime_info.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::service::{ + remote_configs::RemoteConfigsGuard, telemetry::{AppInstance, AppOrQueue}, InstanceId, QueueId, }; @@ -26,17 +27,26 @@ pub(crate) struct SharedAppManualFut { /// `RuntimeInfo` is a struct that contains information about a runtime. /// It contains a map of apps and a map of app or actions. -/// Each app is represented by a shared future that may contain an `Option`. -/// Each action is represented by an `AppOrQueue` enum. Combining apps and actions are necessary -/// because service and env names are not known until later in the initialization process. #[derive(Clone, Default)] pub(crate) struct RuntimeInfo { pub(crate) apps: Arc>, - app_or_actions: Arc>>, + applications: Arc>>, #[cfg(feature = "tracing")] pub(crate) instance_id: InstanceId, } +/// `ActiveApplications` is a struct the contains information about a known in flight application. +/// Telemetry lifecycles (see `app_or_actions`) and remote_config `remote_config_guard` are bound to +/// it. +/// Each app is represented by a shared future that may contain an `Option`. +/// Each action is represented by an `AppOrQueue` enum. Combining apps and actions are necessary +/// because service and env names are not known until later in the initialization process. +#[derive(Default)] +pub(crate) struct ActiveApplication { + pub app_or_actions: AppOrQueue, + pub remote_config_guard: Option, +} + impl RuntimeInfo { /// Retrieves the `AppInstance` for a given service name and environment name. /// @@ -113,14 +123,14 @@ impl RuntimeInfo { self.apps.lock().unwrap() } - /// Locks the app or actions map and returns a mutable reference to it. + /// Locks the applications map and returns a mutable reference to it. /// /// # Returns /// - /// * `MutexGuard>` - A mutable reference to the app or actions - /// map. - pub(crate) fn lock_app_or_actions(&self) -> MutexGuard> { - self.app_or_actions.lock().unwrap() + /// * `MutexGuard>` - A mutable reference to the + /// applications map. + pub(crate) fn lock_applications(&self) -> MutexGuard> { + self.applications.lock().unwrap() } } diff --git a/sidecar/src/service/session_info.rs b/sidecar/src/service/session_info.rs index e0e2f0c2f..7acc3e816 100644 --- a/sidecar/src/service/session_info.rs +++ b/sidecar/src/service/session_info.rs @@ -1,11 +1,13 @@ // Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 +use std::sync::atomic::AtomicI32; use std::{ collections::HashMap, sync::{Arc, Mutex, MutexGuard}, }; +use datadog_remote_config::fetch::ConfigInvariants; use futures::future; use tracing::{enabled, info, Level}; @@ -17,16 +19,38 @@ use crate::service::{InstanceId, RuntimeInfo}; /// /// It contains a list of runtimes, session configuration, tracer configuration, and log guards. /// It also has methods to manage the runtimes and configurations. -#[derive(Default, Clone)] +#[derive(Default)] pub(crate) struct SessionInfo { runtimes: Arc>>, pub(crate) session_config: Arc>>, tracer_config: Arc>, dogstatsd: Arc>, + remote_config_invariants: Arc>>, + #[cfg(windows)] + pub(crate) remote_config_notify_function: + Arc>, pub(crate) log_guard: Arc, MultiWriterGuard<'static>)>>>, #[cfg(feature = "tracing")] pub(crate) session_id: String, + pub(crate) pid: Arc, +} + +impl Clone for SessionInfo { + fn clone(&self) -> Self { + SessionInfo { + runtimes: self.runtimes.clone(), + session_config: self.session_config.clone(), + tracer_config: self.tracer_config.clone(), + dogstatsd: self.dogstatsd.clone(), + remote_config_invariants: self.remote_config_invariants.clone(), + #[cfg(windows)] + remote_config_notify_function: self.remote_config_notify_function.clone(), + log_guard: self.log_guard.clone(), + session_id: self.session_id.clone(), + pid: self.pid.clone(), + } + } } impl SessionInfo { @@ -154,7 +178,16 @@ impl SessionInfo { { f(&mut self.get_dogstatsd()); } + + pub fn set_remote_config_invariants(&self, invariants: ConfigInvariants) { + *self.remote_config_invariants.lock().unwrap() = Some(invariants); + } + + pub fn get_remote_config_invariants(&self) -> MutexGuard> { + self.remote_config_invariants.lock().unwrap() + } } + #[cfg(test)] mod tests { use super::*; diff --git a/sidecar/src/service/sidecar_interface.rs b/sidecar/src/service/sidecar_interface.rs index 6ea137a39..eb8b2fbc9 100644 --- a/sidecar/src/service/sidecar_interface.rs +++ b/sidecar/src/service/sidecar_interface.rs @@ -10,6 +10,14 @@ use anyhow::Result; use datadog_ipc::platform::ShmHandle; use datadog_ipc::tarpc; +// This is a bit weird, but depending on the OS we're interested in different things... +// and the macro expansion is not going to be happy with #[cfg()] instructions inside them. +// So we'll just define a type, a pid on unix, a function pointer on windows. +#[cfg(unix)] +type RemoteConfigNotifyTarget = libc::pid_t; +#[cfg(windows)] +type RemoteConfigNotifyTarget = crate::service::remote_configs::RemoteConfigNotifyFunction; + /// The `SidecarInterface` trait defines the necessary methods for the sidecar service. /// /// These methods include operations such as enqueueing actions, registering services, setting @@ -53,8 +61,13 @@ pub trait SidecarInterface { /// # Arguments /// /// * `session_id` - The ID of the session. + /// * `pid` - The pid of the sidecar client. /// * `config` - The configuration to be set. - async fn set_session_config(session_id: String, config: SessionConfig); + async fn set_session_config( + session_id: String, + remote_config_notify_target: RemoteConfigNotifyTarget, + config: SessionConfig, + ); /// Shuts down a runtime. /// @@ -98,6 +111,22 @@ pub trait SidecarInterface { headers: SerializedTracerHeaderTags, ); + /// Sets contextual data for the remote config client. + /// + /// # Arguments + /// * `instance_id` - The ID of the instance. + /// * `queue_id` - The unique identifier for the trace context. + /// * `service_name` - The name of the service. + /// * `env_name` - The name of the environment. + /// * `app_version` - The application version. + async fn set_remote_config_data( + instance_id: InstanceId, + queue_id: QueueId, + service_name: String, + env_name: String, + app_version: String, + ); + /// Sends DogStatsD actions. /// /// # Arguments diff --git a/sidecar/src/service/sidecar_server.rs b/sidecar/src/service/sidecar_server.rs index 48a1be66f..fb65646b3 100644 --- a/sidecar/src/service/sidecar_server.rs +++ b/sidecar/src/service/sidecar_server.rs @@ -40,10 +40,13 @@ use tokio::task::{JoinError, JoinHandle}; use crate::config::get_product_endpoint; use crate::dogstatsd::DogStatsDAction; +use crate::service::remote_configs::{RemoteConfigNotifyTarget, RemoteConfigs}; +use crate::service::runtime_info::ActiveApplication; use crate::service::telemetry::enqueued_telemetry_stats::EnqueuedTelemetryStats; use crate::service::tracing::trace_flusher::TraceFlusherStats; use datadog_ipc::platform::FileBackedHandle; use datadog_ipc::tarpc::server::{Channel, InFlightRequest}; +use datadog_remote_config::fetch::ConfigInvariants; use datadog_trace_utils::tracer_header_tags::TracerHeaderTags; type NoResponse = Ready<()>; @@ -62,6 +65,7 @@ struct SidecarStats { active_apps: u32, enqueued_apps: u32, enqueued_telemetry_data: EnqueuedTelemetryStats, + remote_config_clients: u32, telemetry_metrics_contexts: u32, telemetry_worker: TelemetryWorkerStats, telemetry_worker_errors: u32, @@ -69,6 +73,15 @@ struct SidecarStats { log_filter: TemporarilyRetainedMapStats, } +#[cfg(windows)] +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +pub struct ProcessHandle(pub winapi::um::winnt::HANDLE); + +#[cfg(windows)] +unsafe impl Send for ProcessHandle {} +#[cfg(windows)] +unsafe impl Sync for ProcessHandle {} + /// The `SidecarServer` struct represents a server that handles sidecar operations. /// /// It maintains a list of active sessions and a counter for each session. @@ -87,6 +100,11 @@ pub struct SidecarServer { Arc>>>, /// Keeps track of the number of submitted payloads. pub submitted_payloads: Arc, + /// All remote config handling + remote_configs: RemoteConfigs, + /// The ProcessHandle tied to the connection + #[cfg(windows)] + process_handle: Option, } impl SidecarServer { @@ -99,7 +117,17 @@ impl SidecarServer { /// # Arguments /// /// * `async_channel`: An `AsyncChannel` that represents the connection to the client. - pub async fn accept_connection(self, async_channel: AsyncChannel) { + #[cfg_attr(not(windows), allow(unused_mut))] + pub async fn accept_connection(mut self, async_channel: AsyncChannel) { + #[cfg(windows)] + { + self.process_handle = async_channel + .metadata + .lock() + .unwrap() + .process_handle() + .map(|p| ProcessHandle(p as winapi::um::winnt::HANDLE)); + } let server = tarpc::server::BaseChannel::new( tarpc::server::Config { pending_response_buffer: 10000, @@ -143,7 +171,7 @@ impl SidecarServer { async fn process_interceptor_response( &self, - result: Result<(HashSet, HashSet), tokio::task::JoinError>, + result: Result<(HashSet, HashSet), JoinError>, ) { match result { Ok((sessions, instances)) => { @@ -368,7 +396,7 @@ impl SidecarServer { .map(|s| { s.lock_runtimes() .values() - .map(|r| r.lock_app_or_actions().len() as u32) + .map(|r| r.lock_applications().len() as u32) .sum::() }) .sum(), @@ -378,9 +406,9 @@ impl SidecarServer { s.lock_runtimes() .values() .map(|r| { - r.lock_app_or_actions() + r.lock_applications() .values() - .filter(|a| matches!(a, AppOrQueue::Queue(_))) + .filter(|a| matches!(a.app_or_actions, AppOrQueue::Queue(_))) .count() as u32 }) .sum::() @@ -392,9 +420,9 @@ impl SidecarServer { s.lock_runtimes() .values() .map(|r| { - r.lock_app_or_actions() + r.lock_applications() .values() - .filter_map(|a| match a { + .filter_map(|a| match &a.app_or_actions { AppOrQueue::Queue(q) => Some(q.stats()), _ => None, }) @@ -403,6 +431,20 @@ impl SidecarServer { .sum() }) .sum(), + remote_config_clients: sessions + .values() + .map(|s| { + s.lock_runtimes() + .values() + .map(|r| { + r.lock_applications() + .values() + .filter_map(|a| a.remote_config_guard.as_ref()) + .count() as u32 + }) + .sum::() + }) + .sum(), telemetry_metrics_contexts: sessions .values() .map(|s| { @@ -431,6 +473,10 @@ impl SidecarServer { log_writer: MULTI_LOG_WRITER.stats(), } } + + pub fn shutdown(&self) { + self.remote_configs.shutdown(); + } } impl SidecarInterface for SidecarServer { @@ -444,47 +490,69 @@ impl SidecarInterface for SidecarServer { actions: Vec, ) -> Self::EnqueueActionsFut { let rt_info = self.get_runtime(&instance_id); - let mut queue = rt_info.lock_app_or_actions(); - match queue.entry(queue_id) { - Entry::Occupied(mut entry) => match entry.get_mut() { - AppOrQueue::Queue(ref mut data) => { - data.process(actions); - } - AppOrQueue::App(service_future) => { - let service_future = service_future.clone(); - // drop on stop - if actions.iter().any(|action| { - matches!( - action, - SidecarAction::Telemetry(TelemetryActions::Lifecycle( - LifecycleAction::Stop - )) - ) - }) { - entry.remove(); + let mut applications = rt_info.lock_applications(); + match applications.entry(queue_id) { + Entry::Occupied(mut entry) => { + let value = entry.get_mut(); + match value.app_or_actions { + AppOrQueue::Inactive => { + value.app_or_actions = + AppOrQueue::Queue(EnqueuedTelemetryData::processed(actions)); } - let apps = rt_info.apps.clone(); - tokio::spawn(async move { - let service = service_future.await; - let app_future = if let Some(fut) = apps - .lock() - .expect("Unable to acquire lock on apps") - .get(&service) - { - fut.clone() - } else { - return; - }; - if let Some(mut app) = app_future.await { - let actions = - EnqueuedTelemetryData::process_immediately(actions, &mut app).await; - app.telemetry.send_msgs(actions).await.ok(); + AppOrQueue::Queue(ref mut data) => { + data.process(actions); + } + AppOrQueue::App(ref service_future) => { + let service_future = service_future.clone(); + // drop on stop + if actions.iter().any(|action| { + matches!( + action, + SidecarAction::Telemetry(TelemetryActions::Lifecycle( + LifecycleAction::Stop + )) + ) + }) { + entry.remove(); } - }); + let apps = rt_info.apps.clone(); + tokio::spawn(async move { + let service = service_future.await; + let app_future = if let Some(fut) = apps + .lock() + .expect("Unable to acquire lock on apps") + .get(&service) + { + fut.clone() + } else { + return; + }; + if let Some(mut app) = app_future.await { + let actions = + EnqueuedTelemetryData::process_immediately(actions, &mut app) + .await; + app.telemetry.send_msgs(actions).await.ok(); + } + }); + } } - }, + } Entry::Vacant(entry) => { - entry.insert(AppOrQueue::Queue(EnqueuedTelemetryData::processed(actions))); + if actions.len() != 1 + || !matches!( + actions[0], + SidecarAction::Telemetry(TelemetryActions::Lifecycle( + LifecycleAction::Stop + )) + ) + { + entry.insert(ActiveApplication { + app_or_actions: AppOrQueue::Queue(EnqueuedTelemetryData::processed( + actions, + )), + ..Default::default() + }); + } } } @@ -505,12 +573,17 @@ impl SidecarInterface for SidecarServer { let (future, completer) = ManualFuture::new(); let app_or_queue = { let rt_info = self.get_runtime(&instance_id); - let mut app_or_actions = rt_info.lock_app_or_actions(); - match app_or_actions.get(&queue_id) { - Some(AppOrQueue::Queue(_)) => { - app_or_actions.insert(queue_id, AppOrQueue::App(future.shared())) - } - None => Some(AppOrQueue::Queue(EnqueuedTelemetryData::default())), + let mut applications = rt_info.lock_applications(); + match applications.get_mut(&queue_id) { + Some(ActiveApplication { + app_or_actions: ref mut app @ AppOrQueue::Queue(_), + .. + }) => Some(std::mem::replace(app, AppOrQueue::App(future.shared()))), + None + | Some(ActiveApplication { + app_or_actions: AppOrQueue::Inactive, + .. + }) => Some(AppOrQueue::Queue(EnqueuedTelemetryData::default())), _ => None, } }; @@ -546,7 +619,7 @@ impl SidecarInterface for SidecarServer { matches!(action, TelemetryActions::Lifecycle(LifecycleAction::Stop)) }) { self.get_runtime(&instance_id) - .lock_app_or_actions() + .lock_applications() .remove(&queue_id); } @@ -566,13 +639,22 @@ impl SidecarInterface for SidecarServer { self, _: Context, session_id: String, + #[cfg(unix)] pid: libc::pid_t, + #[cfg(windows)] + remote_config_notify_function: crate::service::remote_configs::RemoteConfigNotifyFunction, config: SessionConfig, ) -> Self::SetSessionConfigFut { let session = self.get_session(&session_id); + #[cfg(unix)] + { + session.pid.store(pid, Ordering::Relaxed); + } + #[cfg(windows)] + { + *session.remote_config_notify_function.lock().unwrap() = remote_config_notify_function; + } session.modify_telemetry_config(|cfg| { cfg.telemetry_hearbeat_interval = config.telemetry_heartbeat_interval; - }); - session.modify_telemetry_config(|cfg| { let endpoint = get_product_endpoint(ddtelemetry::config::PROD_INTAKE_SUBDOMAIN, &config.endpoint); cfg.set_endpoint(endpoint).ok(); @@ -590,6 +672,13 @@ impl SidecarInterface for SidecarServer { .set_endpoint(config.dogstatsd_endpoint.clone()) .ok(); }); + session.set_remote_config_invariants(ConfigInvariants { + language: config.language, + tracer_version: config.tracer_version, + endpoint: config.endpoint, + products: config.remote_config_products, + capabilities: config.remote_config_capabilities, + }); self.trace_flusher .interval_ms .store(config.flush_interval.as_millis() as u64, Ordering::Relaxed); @@ -701,6 +790,54 @@ impl SidecarInterface for SidecarServer { no_response() } + type SetRemoteConfigDataFut = NoResponse; + + fn set_remote_config_data( + self, + _: Context, + instance_id: InstanceId, + queue_id: QueueId, + service_name: String, + env_name: String, + app_version: String, + ) -> Self::SetRemoteConfigDataFut { + let session = self.get_session(&instance_id.session_id); + #[cfg(windows)] + let notify_target = if let Some(handle) = self.process_handle { + RemoteConfigNotifyTarget { + process_handle: handle, + notify_function: *session.remote_config_notify_function.lock().unwrap(), + } + } else { + return no_response(); + }; + #[cfg(unix)] + let notify_target = RemoteConfigNotifyTarget { + pid: session.pid.load(Ordering::Relaxed), + }; + let runtime_info = session.get_runtime(&instance_id.runtime_id); + runtime_info + .lock_applications() + .entry(queue_id) + .or_default() + .remote_config_guard = Some( + self.remote_configs.add_runtime( + session + .get_remote_config_invariants() + .as_ref() + .expect("Expecting remote config invariants to be set early") + .clone(), + instance_id.runtime_id, + notify_target, + env_name, + service_name, + app_version, + ), + ); + + no_response() + } + type SendDogstatsdActionsFut = NoResponse; fn send_dogstatsd_actions( diff --git a/sidecar/src/service/telemetry/mod.rs b/sidecar/src/service/telemetry/mod.rs index a609f5d6c..99d61a218 100644 --- a/sidecar/src/service/telemetry/mod.rs +++ b/sidecar/src/service/telemetry/mod.rs @@ -11,7 +11,10 @@ pub mod enqueued_telemetry_data; pub mod enqueued_telemetry_stats; #[allow(clippy::large_enum_variant)] +#[derive(Default)] pub(crate) enum AppOrQueue { + #[default] + Inactive, App(Shared>), Queue(EnqueuedTelemetryData), } diff --git a/sidecar/src/shm_remote_config.rs b/sidecar/src/shm_remote_config.rs new file mode 100644 index 000000000..62f51468d --- /dev/null +++ b/sidecar/src/shm_remote_config.rs @@ -0,0 +1,681 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache +// License Version 2.0. This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021-Present Datadog, Inc. + +use crate::one_way_shared_memory::{ + open_named_shm, OneWayShmReader, OneWayShmWriter, ReaderOpener, +}; +use crate::primary_sidecar_identifier; +use base64::prelude::BASE64_URL_SAFE_NO_PAD; +use base64::Engine; +use datadog_ipc::platform::{FileBackedHandle, MappedMem, NamedShmHandle}; +use datadog_remote_config::fetch::{ + ConfigInvariants, FileRefcountData, FileStorage, MultiTargetFetcher, MultiTargetHandlers, + NotifyTarget, RefcountedFile, +}; +use datadog_remote_config::{RemoteConfigPath, RemoteConfigValue, Target}; +use priority_queue::PriorityQueue; +use sha2::{Digest, Sha224}; +use std::cmp::Reverse; +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::default::Default; +use std::ffi::CString; +use std::hash::{Hash, Hasher}; +use std::io; +#[cfg(windows)] +use std::io::Write; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use tokio::time::Instant; +use tracing::{debug, error, trace, warn}; +use zwohash::ZwoHasher; + +pub struct RemoteConfigWriter(OneWayShmWriter); +pub struct RemoteConfigReader(OneWayShmReader); + +fn path_for_remote_config(id: &ConfigInvariants, target: &Arc) -> CString { + // We need a stable hash so that the outcome is independent of the process + let mut hasher = ZwoHasher::default(); + id.hash(&mut hasher); + target.hash(&mut hasher); + // datadog remote config, on macos we're restricted to 31 chars + CString::new(format!( + "/ddrc{}-{}", + primary_sidecar_identifier(), + hasher.finish() + )) + .unwrap() +} + +impl RemoteConfigReader { + pub fn new(id: &ConfigInvariants, target: &Arc) -> RemoteConfigReader { + let path = path_for_remote_config(id, target); + RemoteConfigReader(OneWayShmReader::new(open_named_shm(&path).ok(), path)) + } + + pub fn read(&mut self) -> (bool, &[u8]) { + self.0.read() + } +} + +impl RemoteConfigWriter { + pub fn new(id: &ConfigInvariants, target: &Arc) -> io::Result { + Ok(RemoteConfigWriter(OneWayShmWriter::::new( + path_for_remote_config(id, target), + )?)) + } + + pub fn write(&self, contents: &[u8]) { + self.0.write(contents) + } +} + +impl ReaderOpener for OneWayShmReader { + fn open(&self) -> Option> { + open_named_shm(&self.extra).ok() + } +} + +#[derive(Clone)] +struct ConfigFileStorage { + invariants: ConfigInvariants, + /// All writers + writers: Arc, RemoteConfigWriter>>>, + #[allow(clippy::type_complexity)] + on_dead: Arc>>>, +} + +struct StoredShmFile { + handle: Mutex, + refcount: FileRefcountData, +} + +impl RefcountedFile for StoredShmFile { + fn refcount(&self) -> &FileRefcountData { + &self.refcount + } +} + +impl FileStorage for ConfigFileStorage { + type StoredFile = StoredShmFile; + + fn store( + &self, + version: u64, + path: Arc, + file: Vec, + ) -> anyhow::Result> { + Ok(Arc::new(StoredShmFile { + handle: Mutex::new(store_shm(version, &path, file)?), + refcount: FileRefcountData::new(version, path), + })) + } + + fn update( + &self, + file: &Arc, + version: u64, + contents: Vec, + ) -> anyhow::Result<()> { + *file.handle.lock().unwrap() = store_shm(version, &file.refcount.path, contents)?; + Ok(()) + } +} + +fn store_shm( + version: u64, + path: &RemoteConfigPath, + file: Vec, +) -> anyhow::Result { + let name = format!("ddrc{}-{}", primary_sidecar_identifier(), version,); + // as much signal as possible to be collision free + let hashed_path = BASE64_URL_SAFE_NO_PAD.encode(Sha224::digest(path.to_string())); + #[cfg(target_os = "macos")] + let sliced_path = &hashed_path[..30 - name.len()]; + #[cfg(not(target_os = "macos"))] + let sliced_path = &hashed_path; + let name = format!("/{}-{}", name, sliced_path); + let len = file.len(); + #[cfg(windows)] + let len = len + 4; + let mut handle = NamedShmHandle::create(CString::new(name)?, len)?.map()?; + + #[cfg_attr(not(windows), allow(unused_mut))] + let mut target_slice = handle.as_slice_mut(); + #[cfg(windows)] + { + target_slice.write_all(&(file.len() as u32).to_ne_bytes())?; + } + target_slice.copy_from_slice(file.as_slice()); + + Ok(handle.into()) +} + +impl MultiTargetHandlers for ConfigFileStorage { + fn fetched(&self, target: &Arc, files: &[Arc]) -> bool { + let mut writers = self.writers.lock().unwrap(); + let writer = match writers.entry(target.clone()) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => e.insert(match RemoteConfigWriter::new(&self.invariants, target) { + Ok(w) => w, + Err(e) => { + let msg = format!("Failed acquiring a remote config shm writer: {:?}", e); + error!(msg); + return false; + } + }), + }; + + let len = files + .iter() + .map(|f| f.handle.lock().unwrap().get_path().len() + 2) + .sum(); + let mut serialized = Vec::with_capacity(len); + for file in files.iter() { + serialized.extend_from_slice(file.handle.lock().unwrap().get_path()); + serialized.push(b':'); + serialized.extend_from_slice( + BASE64_URL_SAFE_NO_PAD + .encode(file.refcount.path.to_string()) + .as_bytes(), + ); + serialized.push(b'\n'); + } + + if writer.0.as_slice() != serialized { + writer.write(&serialized); + + debug!( + "Active configuration files are: {}", + String::from_utf8_lossy(&serialized) + ); + + true + } else { + false + } + } + + fn expired(&self, target: &Arc) { + if let Some(writer) = self.writers.lock().unwrap().remove(target) { + // clear to signal it's no longer being fetched + writer.write(&[]); + } + } + + fn dead(&self) { + (self + .on_dead + .lock() + .unwrap() + .take() + .expect("The MultiTargetHandler must not be used anymore once on_dead is called"))( + ); + } +} + +pub struct ShmRemoteConfigsGuard { + target: Arc, + runtime_id: String, + remote_configs: ShmRemoteConfigs, +} + +impl Drop for ShmRemoteConfigsGuard { + fn drop(&mut self) { + self.remote_configs + .0 + .delete_runtime(&self.runtime_id, &self.target); + } +} + +#[derive(Clone)] +pub struct ShmRemoteConfigs( + Arc>, +); + +// we collect services per env, so that we always query, for each runtime + env, all the services +// adding runtimes increases amount of services, removing services after a while + +// one request per (runtime_id, RemoteConfigIdentifier) tuple: extra_services are all services +// pertaining to that env refcounting RemoteConfigIdentifier tuples by their unique runtime_id + +impl ShmRemoteConfigs { + pub fn new(invariants: ConfigInvariants, on_dead: Box) -> Self { + let storage = ConfigFileStorage { + invariants: invariants.clone(), + writers: Default::default(), + on_dead: Arc::new(Mutex::new(Some(on_dead))), + }; + ShmRemoteConfigs(MultiTargetFetcher::new(storage, invariants)) + } + + pub fn is_dead(&self) -> bool { + self.0.is_dead() + } + + pub fn add_runtime( + &self, + runtime_id: String, + notify_target: N, + env: String, + service: String, + app_version: String, + ) -> ShmRemoteConfigsGuard { + let target = Arc::new(Target { + service, + env, + app_version, + }); + self.0 + .add_runtime(runtime_id.clone(), notify_target, &target); + ShmRemoteConfigsGuard { + target, + runtime_id, + remote_configs: self.clone(), + } + } + + pub fn shutdown(&self) { + self.0.shutdown(); + } +} + +fn read_config(path: &str) -> anyhow::Result { + if let [shm_path, rc_path] = &path.split(':').collect::>()[..] { + let mapped = NamedShmHandle::open(&CString::new(*shm_path)?)?.map()?; + let rc_path = String::from_utf8(BASE64_URL_SAFE_NO_PAD.decode(rc_path)?)?; + let data = mapped.as_slice(); + #[cfg(windows)] + let data = &data[4..(4 + u32::from_ne_bytes((&data[0..4]).try_into()?) as usize)]; + RemoteConfigValue::try_parse(&rc_path, data) + } else { + anyhow::bail!( + "could not read config; {} does not have exactly one colon", + path + ); + } +} + +/// Manages configs. +/// Returns changes to configurations. +/// Switching targets is supported; Remove and Add operations will be yielded upon the next +/// fetch_update() call according to the difference. +/// It is guaranteed that no two configurations sharing the same RemoteConfigPath are applied at +/// once. They will always be Remove()d first, then Add()ed again upon update. +pub struct RemoteConfigManager { + invariants: ConfigInvariants, + active_target: Option>, + active_reader: Option, + encountered_targets: HashMap, (RemoteConfigReader, Vec)>, + unexpired_targets: PriorityQueue, Reverse>, + active_configs: HashMap, + last_read_configs: Vec, + check_configs: Vec, +} + +#[derive(Debug)] +pub enum RemoteConfigUpdate { + None, + Add(RemoteConfigValue), + Remove(RemoteConfigPath), +} + +impl RemoteConfigManager { + pub fn new(invariants: ConfigInvariants) -> RemoteConfigManager { + RemoteConfigManager { + invariants, + active_target: None, + active_reader: None, + encountered_targets: Default::default(), + unexpired_targets: Default::default(), + active_configs: Default::default(), + last_read_configs: Default::default(), + check_configs: vec![], + } + } + + /// Polls one configuration change. + /// Has to be polled repeatedly until None is returned. + pub fn fetch_update(&mut self) -> RemoteConfigUpdate { + if let Some(ref target) = self.active_target { + let reader = self + .active_reader + .get_or_insert_with(|| RemoteConfigReader::new(&self.invariants, target)); + + let (changed, data) = reader.read(); + if changed { + 'fetch_new: { + let mut configs = vec![]; + if !data.is_empty() { + let mut i = 0; + let mut start = 0; + while i < data.len() { + if data[i] == b'\n' { + match std::str::from_utf8(&data[start..i]) { + Ok(s) => configs.push(s.to_string()), + Err(e) => { + warn!("Failed reading received configurations {e:?}"); + break 'fetch_new; + } + } + start = i + 1; + } + i += 1; + } + } + self.last_read_configs = configs; + self.check_configs = self.active_configs.keys().cloned().collect(); + } + + while let Some((_, Reverse(instant))) = self.unexpired_targets.peek() { + if *instant < Instant::now() - Duration::from_secs(3666) { + let (target, _) = self.unexpired_targets.pop().unwrap(); + self.encountered_targets.remove(&target); + } + } + } + } + + while let Some(config) = self.check_configs.pop() { + if !self.last_read_configs.contains(&config) { + trace!("Removing remote config file {config}"); + if let Some(path) = self.active_configs.remove(&config) { + return RemoteConfigUpdate::Remove(path); + } + } + } + + while let Some(config) = self.last_read_configs.pop() { + if let Entry::Vacant(entry) = self.active_configs.entry(config) { + match read_config(entry.key()) { + Ok(parsed) => { + trace!("Adding remote config file {}: {:?}", entry.key(), parsed); + entry.insert(RemoteConfigPath { + source: parsed.source, + product: (&parsed.data).into(), + config_id: parsed.config_id.clone(), + name: parsed.name.clone(), + }); + return RemoteConfigUpdate::Add(parsed); + } + Err(e) => warn!( + "Failed reading remote config file {}; skipping: {:?}", + entry.key(), + e + ), + } + } + } + + RemoteConfigUpdate::None + } + + fn set_target(&mut self, target: Option>) { + let mut current_configs = std::mem::take(&mut self.last_read_configs); + if let Some(old_target) = std::mem::replace(&mut self.active_target, target) { + if let Some(reader) = self.active_reader.take() { + // Reconstruct currently active configurations + if self.check_configs.is_empty() { + current_configs.extend(self.active_configs.keys().cloned()); + } + self.encountered_targets + .insert(old_target.clone(), (reader, current_configs)); + self.unexpired_targets + .push(old_target, Reverse(Instant::now())); + } + } + if let Some(ref target) = self.active_target { + if let Some((reader, last_fetch)) = self.encountered_targets.remove(target) { + self.active_reader = Some(reader); + self.last_read_configs = last_fetch; + self.unexpired_targets.remove(target); + } + } + } + + /// Sets the currently active target. + pub fn track_target(&mut self, target: &Arc) { + self.set_target(Some(target.clone())); + self.check_configs = self.active_configs.keys().cloned().collect(); + } + + /// Resets the currently active target. The next configuration change polls will emit Remove() + /// for all current tracked active configurations. + pub fn reset_target(&mut self) { + self.set_target(None); + self.check_configs = self.active_configs.keys().cloned().collect(); + } + + pub fn get_target(&self) -> Option<&Arc> { + self.active_target.as_ref() + } + + /// Resets everything, giving up the target and all tracked state of active configurations. + pub fn reset(&mut self) { + self.set_target(None); + self.check_configs.clear(); + self.active_configs.clear(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use datadog_dynamic_configuration::{data::tests::dummy_dynamic_config, Configs}; + use datadog_remote_config::fetch::test_server::RemoteConfigServer; + use datadog_remote_config::{RemoteConfigData, RemoteConfigProduct, RemoteConfigSource}; + use lazy_static::lazy_static; + use manual_future::ManualFuture; + + lazy_static! { + static ref PATH_FIRST: RemoteConfigPath = RemoteConfigPath { + source: RemoteConfigSource::Employee, + product: RemoteConfigProduct::ApmTracing, + config_id: "1234".to_string(), + name: "config".to_string(), + }; + static ref PATH_SECOND: RemoteConfigPath = RemoteConfigPath { + source: RemoteConfigSource::Employee, + product: RemoteConfigProduct::ApmTracing, + config_id: "9876".to_string(), + name: "config".to_string(), + }; + static ref DUMMY_TARGET: Arc = Arc::new(Target { + service: "service".to_string(), + env: "env".to_string(), + app_version: "1.3.5".to_string(), + }); + } + + #[derive(Debug, Clone)] + struct NotifyDummy(Arc>); + + impl Hash for NotifyDummy { + fn hash(&self, _state: &mut H) {} + } + + impl Eq for NotifyDummy {} + + impl PartialEq for NotifyDummy { + fn eq(&self, _other: &Self) -> bool { + true + } + } + + impl NotifyTarget for NotifyDummy { + fn notify(&self) { + let channel = self.0.clone(); + tokio::spawn(async move { + channel.send(()).await.unwrap(); + }); + } + } + + #[tokio::test] + #[cfg_attr(miri, ignore)] + async fn test_shm_updates() { + let server = RemoteConfigServer::spawn(); + + let (on_dead, on_dead_completer) = ManualFuture::new(); + let shm = ShmRemoteConfigs::new( + server.dummy_invariants(), + Box::new(|| { + tokio::spawn(on_dead_completer.complete(())); + }), + ); + + let mut manager = RemoteConfigManager::new(server.dummy_invariants()); + + server.files.lock().unwrap().insert( + PATH_FIRST.clone(), + ( + vec![DUMMY_TARGET.clone()], + 1, + serde_json::to_string(&dummy_dynamic_config(true)).unwrap(), + ), + ); + + // Nothing yet. (No target) + assert!(matches!(manager.fetch_update(), RemoteConfigUpdate::None)); + + manager.track_target(&DUMMY_TARGET); + // remote end has not fetched anything yet + assert!(matches!(manager.fetch_update(), RemoteConfigUpdate::None)); + + let (sender, mut receiver) = tokio::sync::mpsc::channel(1); + + let shm_guard = shm.add_runtime( + "3b43524b-a70c-45dc-921d-34504e50c5eb".to_string(), + NotifyDummy(Arc::new(sender)), + DUMMY_TARGET.env.to_string(), + DUMMY_TARGET.service.to_string(), + DUMMY_TARGET.app_version.to_string(), + ); + + receiver.recv().await; + + if let RemoteConfigUpdate::Add(update) = manager.fetch_update() { + assert_eq!(update.config_id, PATH_FIRST.config_id); + assert_eq!(update.source, PATH_FIRST.source); + assert_eq!(update.name, PATH_FIRST.name); + if let RemoteConfigData::DynamicConfig(data) = update.data { + assert!(matches!( + >::from(data.lib_config)[0], + Configs::TracingEnabled(true) + )); + } else { + unreachable!(); + } + } else { + unreachable!(); + } + + // just one update + assert!(matches!(manager.fetch_update(), RemoteConfigUpdate::None)); + + { + let mut files = server.files.lock().unwrap(); + files.insert( + PATH_FIRST.clone(), + ( + vec![DUMMY_TARGET.clone()], + 2, + serde_json::to_string(&dummy_dynamic_config(false)).unwrap(), + ), + ); + files.insert( + PATH_SECOND.clone(), + ( + vec![DUMMY_TARGET.clone()], + 1, + serde_json::to_string(&dummy_dynamic_config(true)).unwrap(), + ), + ); + } + + receiver.recv().await; + + // files must be first removed; avoids (in practice) two concurring settings to overlap + let x = manager.fetch_update(); + if let RemoteConfigUpdate::Remove(update) = x { + assert_eq!(&update, &*PATH_FIRST); + } else { + unreachable!(); + } + + // then the adds + let was_second = if let RemoteConfigUpdate::Add(update) = manager.fetch_update() { + update.config_id == PATH_SECOND.config_id + } else { + unreachable!(); + }; + if let RemoteConfigUpdate::Add(update) = manager.fetch_update() { + assert_eq!( + &update.config_id, + if was_second { + &PATH_FIRST.config_id + } else { + &PATH_SECOND.config_id + } + ); + } else { + unreachable!(); + }; + + // And done + assert!(matches!(manager.fetch_update(), RemoteConfigUpdate::None)); + + // Reset will keep old targets for a while in memory + manager.reset_target(); + + // and start to remove + let was_second = if let RemoteConfigUpdate::Remove(update) = manager.fetch_update() { + update == *PATH_SECOND + } else { + unreachable!(); + }; + + manager.track_target(&DUMMY_TARGET); + // If we re-track it's added again immediately + if let RemoteConfigUpdate::Add(update) = manager.fetch_update() { + assert_eq!( + &update.config_id, + if was_second { + &PATH_SECOND.config_id + } else { + &PATH_FIRST.config_id + } + ); + } else { + unreachable!(); + }; + + assert!(matches!(manager.fetch_update(), RemoteConfigUpdate::None)); + + drop(shm_guard); + shm.shutdown(); + + on_dead.await; + + // After proper shutdown it must be like all configs were removed + let was_second = if let RemoteConfigUpdate::Remove(update) = manager.fetch_update() { + update == *PATH_SECOND + } else { + unreachable!(); + }; + if let RemoteConfigUpdate::Remove(update) = manager.fetch_update() { + assert_eq!( + &update, + if was_second { + &*PATH_FIRST + } else { + &*PATH_SECOND + } + ); + } else { + unreachable!(); + }; + + assert!(matches!(manager.fetch_update(), RemoteConfigUpdate::None)); + } +} diff --git a/tools/docker/Dockerfile.build b/tools/docker/Dockerfile.build index 1d2168792..0f684792c 100644 --- a/tools/docker/Dockerfile.build +++ b/tools/docker/Dockerfile.build @@ -83,9 +83,11 @@ COPY "ddcommon-ffi/Cargo.toml" "ddcommon-ffi/" COPY "ddtelemetry/Cargo.toml" "ddtelemetry/" COPY "ddtelemetry-ffi/Cargo.toml" "ddtelemetry-ffi/" COPY "ddsketch/Cargo.toml" "ddsketch/" +COPY "dynamic-configuration/Cargo.toml" "dynamic-configuration/" COPY "profiling/Cargo.toml" "profiling/" COPY "profiling-ffi/Cargo.toml" "profiling-ffi/" COPY "profiling-replayer/Cargo.toml" "profiling-replayer/" +COPY "remote-config/Cargo.toml" "remote-config/" COPY "sidecar/Cargo.toml" "sidecar/" COPY "sidecar/macros/Cargo.toml" "sidecar/macros/" COPY "sidecar-ffi/Cargo.toml" "sidecar-ffi/" diff --git a/trace-protobuf/build.rs b/trace-protobuf/build.rs index 869e452ab..f713e2eb0 100644 --- a/trace-protobuf/build.rs +++ b/trace-protobuf/build.rs @@ -119,6 +119,44 @@ fn generate_protobuf() { "#[serde(rename = \"DBType\")]", ); + config.type_attribute( + "ClientGetConfigsResponse", + "#[derive(Deserialize, Serialize)]", + ); + config.type_attribute("File", "#[derive(Deserialize, Serialize)]"); + config.type_attribute( + "ClientGetConfigsRequest", + "#[derive(Deserialize, Serialize)]", + ); + config.type_attribute("Client", "#[derive(Deserialize, Serialize)]"); + config.field_attribute( + "Client.client_agent", + "#[serde(skip_serializing_if = \"Option::is_none\")]", + ); + config.type_attribute("ClientState", "#[derive(Deserialize, Serialize)]"); + config.type_attribute("ClientTracer", "#[derive(Deserialize, Serialize)]"); + config.type_attribute("ClientAgent", "#[derive(Deserialize, Serialize)]"); + config.type_attribute("ConfigState", "#[derive(Deserialize, Serialize)]"); + config.type_attribute("TargetFileMeta", "#[derive(Deserialize, Serialize)]"); + config.type_attribute("TargetFileHash", "#[derive(Deserialize, Serialize)]"); + + config.field_attribute("File.raw", "#[serde(with = \"serde_bytes\")]"); + config.field_attribute( + "ClientGetConfigsResponse.roots", + "#[serde(with = \"crate::serde\")]", + ); + config.field_attribute( + "ClientGetConfigsResponse.targets", + "#[serde(with = \"serde_bytes\")]", + ); + config.field_attribute("ClientGetConfigsResponse.targets", "#[serde(default)]"); + config.field_attribute("ClientGetConfigsResponse.roots", "#[serde(default)]"); + config.field_attribute("ClientGetConfigsResponse.target_files", "#[serde(default)]"); + config.field_attribute( + "ClientGetConfigsResponse.client_configs", + "#[serde(default)]", + ); + config .compile_protos( &[ @@ -126,6 +164,7 @@ fn generate_protobuf() { "src/pb/tracer_payload.proto", "src/pb/span.proto", "src/pb/stats.proto", + "src/pb/remoteconfig.proto", ], &["src/pb/"], ) @@ -133,10 +172,15 @@ fn generate_protobuf() { // add license, serde imports, custom deserializer code to the top of the protobuf rust structs // file - let add_to_top = "// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ + let license = "// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ // SPDX-License-Identifier: Apache-2.0 -use serde::{Deserialize, Deserializer, Serialize}; +" + .as_bytes(); + + let null_deser = &[ + license, + "use serde::{Deserialize, Deserializer, Serialize}; fn deserialize_null_into_default<'de, D, T>(deserializer: D) -> Result where @@ -152,9 +196,21 @@ pub fn is_default(t: &T) -> bool { } " - .as_bytes(); + .as_bytes(), + ] + .concat(); + + let serde_uses = &[ + license, + "use serde::{Deserialize, Serialize}; + +" + .as_bytes(), + ] + .concat(); - prepend_to_file(add_to_top, &output_path.join("pb.rs")); + prepend_to_file(null_deser, &output_path.join("pb.rs")); + prepend_to_file(serde_uses, &output_path.join("remoteconfig.rs")); } #[cfg(feature = "generate-protobuf")] diff --git a/trace-protobuf/src/lib.rs b/trace-protobuf/src/lib.rs index 8bf9c14fd..6b8e63f1e 100644 --- a/trace-protobuf/src/lib.rs +++ b/trace-protobuf/src/lib.rs @@ -3,6 +3,8 @@ #[rustfmt::skip] pub mod pb; +pub mod remoteconfig; +mod serde; #[cfg(test)] mod pb_test; diff --git a/trace-protobuf/src/pb/remoteconfig.proto b/trace-protobuf/src/pb/remoteconfig.proto new file mode 100644 index 000000000..7b1aa7f89 --- /dev/null +++ b/trace-protobuf/src/pb/remoteconfig.proto @@ -0,0 +1,89 @@ +syntax = "proto3"; + +package remoteconfig; + +option go_package = "pkg/proto/pbgo/core"; // golang + +// Backend definitions + +message File { + string path = 1; + bytes raw = 2; +} + +// Client definitions + +message Client { + ClientState state = 1; + string id = 2; + repeated string products = 3; + reserved 4, 5; + bool is_tracer = 6; + ClientTracer client_tracer = 7; + bool is_agent = 8; + ClientAgent client_agent = 9; + uint64 last_seen = 10; + bytes capabilities = 11; +} + +message ClientTracer { + string runtime_id = 1; + string language = 2; + string tracer_version = 3; + string service = 4; + repeated string extra_services = 8; + string env = 5; + string app_version = 6; + repeated string tags = 7; +} + +message ClientAgent { + string name = 1; + string version = 2; + string cluster_name = 3; + string cluster_id = 4; + repeated string cws_workloads = 5; +} + +message ConfigState { + string id = 1; + uint64 version = 2; + string product = 3; + uint64 apply_state = 4; + string apply_error = 5; +} + +message ClientState { + uint64 root_version = 1; + uint64 targets_version = 2; + repeated ConfigState config_states = 3; + bool has_error = 4; + string error = 5; + bytes backend_client_state = 6; +} + +// Client queries + +message TargetFileHash { + string algorithm = 1; + reserved 2; // old hash format + string hash = 3; +} + +message TargetFileMeta { + string path = 1; + int64 length = 2; + repeated TargetFileHash hashes = 3; +} + +message ClientGetConfigsRequest { + Client client = 1; + repeated TargetFileMeta cached_target_files = 2; +} + +message ClientGetConfigsResponse { + repeated bytes roots = 1; + bytes targets = 2; + repeated File target_files = 3; + repeated string client_configs = 4; +} diff --git a/trace-protobuf/src/remoteconfig.rs b/trace-protobuf/src/remoteconfig.rs new file mode 100644 index 000000000..d7c7b05d7 --- /dev/null +++ b/trace-protobuf/src/remoteconfig.rs @@ -0,0 +1,155 @@ +// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct File { + #[prost(string, tag = "1")] + pub path: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + #[serde(with = "serde_bytes")] + pub raw: ::prost::alloc::vec::Vec, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Client { + #[prost(message, optional, tag = "1")] + pub state: ::core::option::Option, + #[prost(string, tag = "2")] + pub id: ::prost::alloc::string::String, + #[prost(string, repeated, tag = "3")] + pub products: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(bool, tag = "6")] + pub is_tracer: bool, + #[prost(message, optional, tag = "7")] + pub client_tracer: ::core::option::Option, + #[prost(bool, tag = "8")] + pub is_agent: bool, + #[prost(message, optional, tag = "9")] + #[serde(skip_serializing_if = "Option::is_none")] + pub client_agent: ::core::option::Option, + #[prost(uint64, tag = "10")] + pub last_seen: u64, + #[prost(bytes = "vec", tag = "11")] + pub capabilities: ::prost::alloc::vec::Vec, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClientTracer { + #[prost(string, tag = "1")] + pub runtime_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub language: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub tracer_version: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub service: ::prost::alloc::string::String, + #[prost(string, repeated, tag = "8")] + pub extra_services: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(string, tag = "5")] + pub env: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub app_version: ::prost::alloc::string::String, + #[prost(string, repeated, tag = "7")] + pub tags: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClientAgent { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub version: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub cluster_name: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub cluster_id: ::prost::alloc::string::String, + #[prost(string, repeated, tag = "5")] + pub cws_workloads: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConfigState { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub version: u64, + #[prost(string, tag = "3")] + pub product: ::prost::alloc::string::String, + #[prost(uint64, tag = "4")] + pub apply_state: u64, + #[prost(string, tag = "5")] + pub apply_error: ::prost::alloc::string::String, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClientState { + #[prost(uint64, tag = "1")] + pub root_version: u64, + #[prost(uint64, tag = "2")] + pub targets_version: u64, + #[prost(message, repeated, tag = "3")] + pub config_states: ::prost::alloc::vec::Vec, + #[prost(bool, tag = "4")] + pub has_error: bool, + #[prost(string, tag = "5")] + pub error: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "6")] + pub backend_client_state: ::prost::alloc::vec::Vec, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TargetFileHash { + #[prost(string, tag = "1")] + pub algorithm: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub hash: ::prost::alloc::string::String, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TargetFileMeta { + #[prost(string, tag = "1")] + pub path: ::prost::alloc::string::String, + #[prost(int64, tag = "2")] + pub length: i64, + #[prost(message, repeated, tag = "3")] + pub hashes: ::prost::alloc::vec::Vec, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClientGetConfigsRequest { + #[prost(message, optional, tag = "1")] + pub client: ::core::option::Option, + #[prost(message, repeated, tag = "2")] + pub cached_target_files: ::prost::alloc::vec::Vec, +} +#[derive(Deserialize, Serialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClientGetConfigsResponse { + #[prost(bytes = "vec", repeated, tag = "1")] + #[serde(with = "crate::serde")] + #[serde(default)] + pub roots: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", tag = "2")] + #[serde(with = "serde_bytes")] + #[serde(default)] + pub targets: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + #[serde(default)] + pub target_files: ::prost::alloc::vec::Vec, + #[prost(string, repeated, tag = "4")] + #[serde(default)] + pub client_configs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} diff --git a/trace-protobuf/src/serde.rs b/trace-protobuf/src/serde.rs new file mode 100644 index 000000000..b9dc683b0 --- /dev/null +++ b/trace-protobuf/src/serde.rs @@ -0,0 +1,61 @@ +// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use serde::{Deserializer, Serializer}; +use serde_bytes::ByteBuf; + +pub trait Deserialize<'de>: Sized { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>; +} + +impl<'de> Deserialize<'de> for Vec> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + .map(|v: Vec| v.into_iter().map(ByteBuf::into_vec).collect()) + } +} + +impl<'de> Deserialize<'de> for Vec { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + serde::Deserialize::deserialize(deserializer) + } +} + +pub fn deserialize<'de, T, D>(deserializer: D) -> Result +where + T: Deserialize<'de>, + D: Deserializer<'de>, +{ + Deserialize::deserialize(deserializer) +} + +pub trait Serialize: Sized { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer; +} + +impl Serialize for &Vec> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self.iter()) + } +} + +pub fn serialize(value: T, serializer: S) -> Result +where + T: Serialize, + S: Serializer, +{ + value.serialize(serializer) +} diff --git a/trace-utils/Cargo.toml b/trace-utils/Cargo.toml index 5e4c34fcd..b6ffeb828 100644 --- a/trace-utils/Cargo.toml +++ b/trace-utils/Cargo.toml @@ -37,6 +37,8 @@ rmpv = { version = "1.3.0", default-features = false } rmp = { version = "0.8.14", default-features = false } testcontainers = { version = "0.17.0", optional = true } cargo_metadata = { version = "0.18.1", optional = true } +# Dependency of cargo metadata, but 0.1.8 requires too new of a rust version. +cargo-platform = { version = "=0.1.7", optional = true } [dev-dependencies] bolero = "0.10.1" @@ -47,4 +49,4 @@ serde_json = "1.0" tokio = { version = "1", features = ["macros", "rt-multi-thread"] } [features] -test-utils = ["httpmock", "testcontainers", "cargo_metadata"] +test-utils = ["httpmock", "testcontainers", "cargo_metadata", "cargo-platform"]