From 59ee7fa31e841f36ccb17f66b6885b881f28660e Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Mon, 12 May 2025 17:13:26 +0200 Subject: [PATCH 1/5] WIP --- .gitignore | 1 + Cargo.lock | 3575 ++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 5 + Justfile | 2 +- src/lib.rs | 45 +- src/lua.rs | 342 ++++- src/plugin.rs | 376 ++++- src/plugin_api.h | 11 + src/rpc.rs | 43 + src/stingray_sdk.rs | 265 +++- 10 files changed, 4592 insertions(+), 73 deletions(-) create mode 100644 src/rpc.rs diff --git a/.gitignore b/.gitignore index dcb1b49..1fbff5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.wineprefix .envrc /target /msvc diff --git a/Cargo.lock b/Cargo.lock index a571545..a26d22f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,68 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,13 +73,223 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http 0.2.12", + "log", + "url", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bindgen" version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cexpr", "clang-sys", "itertools", @@ -31,12 +303,83 @@ dependencies = [ "syn", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[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 = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "regex-automata 0.4.7", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +dependencies = [ + "shlex", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -52,6 +395,47 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -63,13 +447,277 @@ dependencies = [ "libloading", ] +[[package]] +name = "color-eyre" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "data-encoding-macro" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" +dependencies = [ + "data-encoding", + "syn", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dt-p2p" version = "0.1.0" dependencies = [ + "bincode", "bindgen", + "bstr", + "color-eyre", "libc", + "libp2p", "log", + "tokio", +] + +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2", + "subtle", + "zeroize", ] [[package]] @@ -78,12 +726,713 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.58.0", +] + +[[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.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "h2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + +[[package]] +name = "hickory-proto" +version = "0.25.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d00147af6310f4392a31680db52a3ed45a2e0f68eb18e8c3fe5537ecc96d9e2" +dependencies = [ + "async-recursion", + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.1", + "socket2", + "thiserror 2.0.12", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762f69ebdbd4ddb2e975cd24690bf21fe6b2604039189c26acddbc427f12887" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.1", + "resolv-conf", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tracing", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http 1.3.1", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.3.1", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if-addrs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "if-watch" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" +dependencies = [ + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-proto", + "netlink-sys", + "rtnetlink", + "system-configuration", + "tokio", + "windows 0.53.0", +] + +[[package]] +name = "igd-next" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b0d7d4541def58a37bf8efc559683f21edce7c82f0d866c93ac21f7e098f93" +dependencies = [ + "async-trait", + "attohttpc", + "bytes", + "futures", + "http 1.3.1", + "http-body-util", + "hyper", + "hyper-util", + "log", + "rand 0.8.5", + "tokio", + "url", + "xmltree", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.3", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + [[package]] name = "itertools" version = "0.12.1" @@ -93,6 +1442,28 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.172" @@ -106,7 +1477,359 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "libp2p" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72dc443ddd0254cb49a794ed6b6728400ee446a0f7ab4a07d0209ee98de20e9" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom 0.2.16", + "libp2p-allow-block-list", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-dns", + "libp2p-gossipsub", + "libp2p-identity", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-noise", + "libp2p-ping", + "libp2p-quic", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-upnp", + "libp2p-yamux", + "multiaddr", + "pin-project", + "rw-stream-sink", + "thiserror 2.0.12", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38944b7cb981cc93f2f0fb411ff82d0e983bd226fbcc8d559639a3a73236568b" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe9323175a17caa8a2ed4feaf8a548eeef5e0b72d03840a0eab4bcb0210ce1c" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", +] + +[[package]] +name = "libp2p-core" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193c75710ba43f7504ad8f58a62ca0615b1d7e572cb0f1780bc607252c39e9ef" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr", + "multihash", + "multistream-select", + "once_cell", + "parking_lot", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink", + "thiserror 2.0.12", + "tracing", + "unsigned-varint 0.8.0", + "web-time", +] + +[[package]] +name = "libp2p-dns" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b780a1150214155b0ed1cdf09fbd2e1b0442604f9146a431d1b21d23eef7bd7" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d558548fa3b5a8e9b66392f785921e363c57c05dcadfda4db0d41ae82d313e4a" +dependencies = [ + "async-channel", + "asynchronous-codec", + "base64", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-timer", + "getrandom 0.2.16", + "hashlink", + "hex_fmt", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.5", + "regex", + "sha2", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb68ea10844211a59ce46230909fd0ea040e8a192454d4cc2ee0d53e12280eb" +dependencies = [ + "bs58", + "ed25519-dalek", + "hkdf", + "multihash", + "quick-protobuf", + "rand 0.8.5", + "sha2", + "thiserror 2.0.12", + "tracing", + "zeroize", +] + +[[package]] +name = "libp2p-mdns" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d0ba095e1175d797540e16b62e7576846b883cb5046d4159086837b36846cc" +dependencies = [ + "futures", + "hickory-proto", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "smallvec", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-metrics" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce58c64292e87af624fcb86465e7dd8342e46a388d71e8fec0ab37ee789630a" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-gossipsub", + "libp2p-identity", + "libp2p-ping", + "libp2p-swarm", + "pin-project", + "prometheus-client", + "web-time", +] + +[[package]] +name = "libp2p-noise" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcc133e0f3cea07acde6eb8a9665cb11b600bd61110b010593a0210b8153b16" +dependencies = [ + "asynchronous-codec", + "bytes", + "futures", + "libp2p-core", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand 0.8.5", + "snow", + "static_assertions", + "thiserror 2.0.12", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "libp2p-ping" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2529993ff22deb2504c0130a58b60fb77f036be555053922db1a0490b5798b" +dependencies = [ + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.5", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-quic" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41432a159b00424a0abaa2c80d786cddff81055ac24aa127e0cf375f7858d880" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "quinn", + "rand 0.8.5", + "ring", + "rustls", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-swarm" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803399b4b6f68adb85e63ab573ac568154b193e9a640f03e0f2890eabbcb37f8" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "lru", + "multistream-select", + "once_cell", + "rand 0.8.5", + "smallvec", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-tcp" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65346fb4d36035b23fec4e7be4c320436ba53537ce9b6be1d1db1f70c905cad0" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-tls" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42bbf5084fb44133267ad4caaa72a253d68d709edd2ed1cf9b42431a8ead8fd5" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core", + "libp2p-identity", + "rcgen", + "ring", + "rustls", + "rustls-webpki 0.101.7", + "thiserror 2.0.12", + "x509-parser", + "yasna", +] + +[[package]] +name = "libp2p-upnp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d457b9ecceb66e7199f049926fad447f1f17f040e8d29d690c086b4cab8ed14a" +dependencies = [ + "futures", + "futures-timer", + "igd-next", + "libp2p-core", + "libp2p-swarm", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-yamux" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f15df094914eb4af272acf9adaa9e287baa269943f32ea348ba29cfb9bfc60d8" +dependencies = [ + "either", + "futures", + "libp2p-core", + "thiserror 2.0.12", + "tracing", + "yamux 0.12.1", + "yamux 0.13.4", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", ] [[package]] @@ -115,6 +1838,43 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.3", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" @@ -127,6 +1887,180 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "moka" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "loom", + "parking_lot", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "multiaddr" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "libp2p-identity", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.8.0", + "url", +] + +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" +dependencies = [ + "core2", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "netlink-packet-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +dependencies = [ + "anyhow", + "byteorder", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror 1.0.69", +] + +[[package]] +name = "netlink-proto" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72452e012c2f8d612410d89eea01e2d9b56205274abb35d53f60200b2ec41d60" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror 2.0.12", +] + +[[package]] +name = "netlink-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -137,6 +2071,263 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "prettyplease" version = "0.2.20" @@ -149,13 +2340,114 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] +[[package]] +name = "prometheus-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec", + "bytes", + "quick-protobuf", + "thiserror 1.0.69", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +dependencies = [ + "bytes", + "cfg_aliases", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.12", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.1", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -165,6 +2457,93 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "regex" version = "1.10.6" @@ -173,8 +2552,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -185,21 +2573,221 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "resolv-conf" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7c8f7f733062b66dc1c63f9db168ac0b97a9210e247fa90fdc9ad08f51b302" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rtnetlink" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" +dependencies = [ + "futures", + "log", + "netlink-packet-core", + "netlink-packet-route", + "netlink-packet-utils", + "netlink-proto", + "netlink-sys", + "nix", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc-hash" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.1", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -207,50 +2795,752 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] -name = "syn" -version = "2.0.72" +name = "signature" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core 0.6.4", + "ring", + "rustc_version", + "sha2", + "subtle", +] + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-util" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsigned-varint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" + +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" +dependencies = [ + "windows-core 0.53.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +dependencies = [ + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -263,26 +3553,277 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "xml-rs" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "yamux" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot", + "pin-project", + "rand 0.8.5", + "static_assertions", + "web-time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index bd898ab..d206684 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,13 @@ edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bincode = "2.0.1" +bstr = "1.12.0" +color-eyre = "0.6.4" libc = "0.2.144" +libp2p = { version = "0.55.0", features = ["tokio", "tcp", "noise", "yamux", "ping", "gossipsub"] } log = { version = "0.4.27", features = ["release_max_level_info"] } +tokio = { version = "1.45.0", features = ["macros", "rt", "sync"] } [build-dependencies] bindgen = "0.71.0" diff --git a/Justfile b/Justfile index 5db704c..8368693 100644 --- a/Justfile +++ b/Justfile @@ -7,7 +7,7 @@ image_name := "dt-p2p-builder" steam_library := env("steam_library") game_dir := steam_library / "steamapps" / "common" / "Warhammer 40,000 DARKTIDE" -log_dir := env("appdata") / "Fatshark" / "Darktide" / "console_logs" +log_dir := env("APPDATA") / "Fatshark" / "Darktide" / "console_logs" proton_dir := env("HOME") / ".steam" / "steam" diff --git a/src/lib.rs b/src/lib.rs index 8466250..57ffed6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,25 @@ -use std::ffi::{CString, c_char}; -use std::sync::OnceLock; +use std::ffi::{CStr, c_char}; +use std::sync::{OnceLock, RwLock}; mod lua; mod plugin; +mod rpc; mod stingray_sdk; +use log::error; use plugin::Plugin; use stingray_sdk::{GetApiFunction, LoggingApi, LuaApi, PluginApi, PluginApiID}; /// The name that the plugin is registered to the engine as. /// Must be unique across all plugins. -pub const PLUGIN_NAME: &str = "dt_p2p"; +pub const PLUGIN_NAME: &CStr = c"dt_p2p"; /// The module that Lua functions are assigned to. -pub const MODULE_NAME: &str = "dt_p2p"; +pub const MODULE_NAME: &CStr = c"dt_p2p"; -static PLUGIN: OnceLock = OnceLock::new(); +const CHANNEL_BUFFER_SIZE: usize = 100; +const EVENTS_PER_TICK: usize = 25; + +static PLUGIN: OnceLock> = OnceLock::new(); static LOGGER: OnceLock = OnceLock::new(); static LUA: OnceLock = OnceLock::new(); @@ -30,10 +35,22 @@ macro_rules! global { }}; } +/// A macro to make accessing the plugin instance as mutable a little more convenient. +#[macro_export] +macro_rules! plugin_mut { + () => {{ + let lock = $crate::PLUGIN.get().and_then(|l| l.write().ok()); + if cfg!(debug_assertions) { + lock.expect("failed to acquire lock on plugin global") + } else { + unsafe { lock.unwrap_unchecked() } + } + }}; +} + #[unsafe(no_mangle)] pub extern "C" fn get_name() -> *const c_char { - let s = CString::new(PLUGIN_NAME).expect("Failed to create CString from plugin name"); - s.as_ptr() + PLUGIN_NAME.as_ptr() } #[unsafe(no_mangle)] @@ -44,19 +61,27 @@ pub extern "C" fn setup_game(get_engine_api: GetApiFunction) { let _ = LUA.get_or_init(|| LuaApi::get(get_engine_api)); - let plugin = PLUGIN.get_or_init(Plugin::new); + let plugin = match Plugin::new() { + Ok(plugin) => plugin, + Err(err) => { + error!("Failed to initialize plugin:\n{:?}", err); + return; + } + }; + plugin.setup_game(); + PLUGIN.set(RwLock::new(plugin)); } #[unsafe(no_mangle)] pub extern "C" fn shutdown_game() { - let plugin = global!(PLUGIN); + let plugin = plugin_mut!(); plugin.shutdown_game(); } #[unsafe(no_mangle)] pub extern "C" fn update_game(dt: f32) { - let plugin = global!(PLUGIN); + let mut plugin = plugin_mut!(); plugin.update_game(dt); } diff --git a/src/lua.rs b/src/lua.rs index b4ad22a..c045a51 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,16 +1,334 @@ -use crate::stingray_sdk::lua_State; -use crate::{LUA, global}; +use std::collections::HashMap; +use std::panic::catch_unwind; -pub extern "C" fn do_something(l: *mut lua_State) -> i32 { - let lua = global!(LUA); +use bstr::BStr; +use bstr::ByteSlice as _; +use color_eyre::Result; +use color_eyre::eyre; +use color_eyre::eyre::Context as _; - if let Some(name) = lua.tolstring(l, 1) { - lua.pushstring( - l, - format!("[do_something] Hello from Rust, {}", name.to_string_lossy()), - ); - 1 - } else { - 0 +use crate::plugin::Identifier; +use crate::plugin::Plugin; +use crate::stingray_sdk::LUA_REGISTRYINDEX; +use crate::stingray_sdk::{LuaState, LuaType, lua_State}; +use crate::{LUA, global, plugin_mut}; + +pub const NAMESPACE_SEPARATOR: char = '.'; + +static RPC_CALLBACK_KEY: &str = "dt-p2p.rpc-callbacks"; + +// As a minor optimization, only `catch_unwind` in debug mode. +#[cfg(debug_assertions)] +fn lua_wrapper(l: *mut lua_State, f: F) -> i32 +where + F: FnOnce(&mut Plugin, &LuaState) -> Result + std::panic::UnwindSafe, +{ + let lua = LuaState::new(l, global!(LUA)); + + let res = catch_unwind(|| { + let mut plugin = plugin_mut!(); + f(&mut plugin, &lua) + }); + match res { + Ok(Ok(i)) => i, + Ok(Err(err)) => lua.lib_error(format!("{:?}", err)), + Err(err) => lua.lib_error(format!("{:?}", err)), } } + +#[cfg(not(debug_assertions))] +fn lua_wrapper(l: *mut lua_State, f: F) -> i32 +where + F: FnOnce(&mut Plugin, &LuaState) -> Result, +{ + let lua = LuaState::new(l, global!(LUA)); + let plugin = plugin_mut!(); + + let res = f(&mut plugin, &lua); + match res { + Ok(i) => i, + Err(err) => lua.lib_error(format!("{:?}", err)), + } +} + +/// Returns the namespace and name for a RPC. +/// +/// The namespace may either be part of the name, separated by `NAMESPACE_SEPARATOR` +/// or omitted, in which case the mod name is used as fallback. +fn get_identifier<'a>(lua: &'a LuaState) -> Result> { + lua.getfield(1, c"name"); + if !lua.isstring(-1) { + eyre::bail!("bad argument #1, not a mod object"); + } + + let mod_name = lua.tostring(-1); + let name = lua.tostring(2); + + let (namespace, name) = name + .split_once_str(&[NAMESPACE_SEPARATOR as u8]) + .map(|(namespace, name)| (BStr::new(namespace), BStr::new(name))) + .unwrap_or((mod_name, name)); + + Ok(Identifier::new(namespace, name)) +} + +// Called with `(mod: table, name: string, opts: table)` +pub extern "C" fn create_rpc(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + lua.getfield(1, c"version"); + if !lua.istable(1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + if !lua.isstring(2) { + eyre::bail!("bad argument #2, expected a string"); + } + + if !lua.istable(3) { + eyre::bail!("bad argument #3, expected a table"); + } + + let _version = match lua.r#type(-1) { + LuaType::Nil => { + eyre::bail!("bad argument #1, mod object doesn't provide a 'version' field"); + } + LuaType::Number => lua.tostring(-1), + LuaType::String => { + let version = lua.tostring(-1); + // TODO: parse as date or semver-like + version + } + x => { + eyre::bail!("invalid type {} for 'version' field", x) + } + }; + + let id = get_identifier(lua).wrap_err("failed to determine RPC name")?; + plugin.create_rpc(id); + + Ok(0) + }) +} + +type LuaMap<'a> = HashMap, LuaValue<'a>>; + +#[derive(bincode::BorrowDecode, bincode::Encode, PartialEq)] +enum LuaKey<'a> { + String(&'a [u8]), + Number(f64), +} + +impl<'a> Eq for LuaKey<'a> {} + +impl<'a> std::hash::Hash for LuaKey<'a> { + fn hash(&self, state: &mut H) { + match self { + LuaKey::String(s) => s.hash(state), + LuaKey::Number(n) => (*n as u128).hash(state), + } + } +} + +#[derive(bincode::BorrowDecode, bincode::Encode)] +pub enum LuaValue<'a> { + Nil, + Boolean(bool), + Number(f64), + String(&'a [u8]), + Table(LuaMap<'a>), +} + +impl<'a> LuaValue<'a> { + fn parse_table(lua: &'a LuaState, idx: i32) -> Result { + let mut values = LuaMap::default(); + // + // `nil` as initial key tells `lua_next` to pick the first key. + lua.pushnil(); + + loop { + if lua.next(idx) <= 0 { + break; + } + + let key = match lua.r#type(-2) { + LuaType::Number => LuaKey::Number(lua.tonumber(-2)), + LuaType::String => LuaKey::String(lua.tostring(-2)), + t => eyre::bail!("Unsupported type {} for args table key", t), + }; + + let value = Self::parse(lua, -1)?; + + values.insert(key, value); + + // Pop the value, but keep the key so `lua_next` knows where to continue + lua.pop(); + } + + // Pop the last key + lua.pop(); + + Ok(LuaValue::Table(values)) + } + + pub fn parse(lua: &'a LuaState, idx: i32) -> Result { + match lua.r#type(idx) { + LuaType::None | LuaType::Nil => Ok(LuaValue::Nil), + LuaType::Boolean => Ok(LuaValue::Boolean(lua.toboolean(-1))), + LuaType::Number => Ok(LuaValue::Number(lua.tonumber(-1))), + LuaType::String => Ok(LuaValue::String(lua.tostring(-1))), + LuaType::Table => Self::parse_table(lua, -1), + x => eyre::bail!("Unknown or unsupported Lua type {}", x), + } + } + + pub fn push(&self, lua: &LuaState) { + match self { + LuaValue::Nil => lua.pushnil(), + LuaValue::Boolean(bool) => lua.pushboolean(*bool), + LuaValue::Number(num) => lua.pushnumber(*num), + LuaValue::String(s) => lua.pushstring(*s), + LuaValue::Table(table) => Self::push_table(lua, table), + } + } + + fn push_table(lua: &LuaState, table: &LuaMap) { + let (narr, nrec) = table.iter().fold((0, 0), |(narr, nrec), (k, _)| match k { + LuaKey::String(_) => (narr, nrec + 1), + LuaKey::Number(_) => (narr + 1, nrec), + }); + + lua.createtable(narr, nrec); + let tbl_index = lua.gettop(); + + for (k, v) in table.iter() { + match k { + LuaKey::String(s) => lua.pushstring(*s), + LuaKey::Number(num) => lua.pushnumber(*num), + } + + v.push(lua); + + lua.settable(tbl_index); + } + } +} + +// Called with `(mod: table, name: string, args: table)` +pub extern "C" fn send_rpc(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + if !lua.istable(1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + if !lua.isstring(2) { + eyre::bail!("bad argument #2, expected a string"); + } + + if !lua.istable(3) { + eyre::bail!("bad argument #3, expected a table"); + } + + let id = get_identifier(lua).wrap_err("failed to determine RPC name")?; + let args = LuaValue::parse_table(lua, 3).wrap_err("Failed to parse args table")?; + + plugin.send_rpc(id, args).wrap_err("Failed to send RPC")?; + + Ok(0) + }) +} + +// Called with `(mod: table, name: string, callback: Fn(args))` +pub extern "C" fn receive_rpc(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + if !lua.istable(1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + if !lua.isstring(2) { + eyre::bail!("bad argument #2, expected a string"); + } + + if !lua.isfunction(3) { + eyre::bail!("bad argument #3, expected a function"); + } + + let id = get_identifier(lua).wrap_err("failed to determine RPC name")?; + + // We will utilize Lua's _references_ to store the callback functions. Since we're doing + // the bookkeeping on the Rust side, we don't need to worry about any structured layout on + // the Lua side. + + lua.pushvalue(3); + let fn_ref = lua.lib_ref(LUA_REGISTRYINDEX); + + plugin.add_rpc_listener(id, fn_ref); + + Ok(0) + }) +} + +// Called with `(mod: table, callback: Fn(peer_id))` +pub extern "C" fn on_peer_connected(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + if !lua.istable(1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + if !lua.isfunction(2) { + eyre::bail!("bad argument #2, expected a function"); + } + + lua.getfield(1, c"name"); + if !lua.isstring(-1) { + eyre::bail!("bad argument #1, not a mod object"); + } + + let mod_name = lua.tostring(-1); + lua.pushvalue(3); + let fn_ref = lua.lib_ref(LUA_REGISTRYINDEX); + + plugin.add_connect_listener(mod_name, fn_ref); + + Ok(0) + }) +} + +// Called with `(mod: table, callback: Fn(peer_id))` +pub extern "C" fn on_peer_disconnected(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + if !lua.istable(1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + if !lua.isfunction(2) { + eyre::bail!("bad argument #2, expected a function"); + } + + lua.getfield(1, c"name"); + if !lua.isstring(-1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + let mod_name = lua.tostring(-1); + lua.pushvalue(3); + let fn_ref = lua.lib_ref(LUA_REGISTRYINDEX); + + plugin.add_disconnect_listener(mod_name, fn_ref); + + Ok(0) + }) +} + +// Called with `(dt: float)` +pub extern "C" fn update(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + if !lua.isnumber(1) { + eyre::bail!("bad argument #1, expected a number"); + } + + let dt = lua.tonumber(1); + plugin.lua_update(dt, lua)?; + + Ok(0) + }) +} diff --git a/src/plugin.rs b/src/plugin.rs index 9f85d92..5f1e266 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,26 +1,382 @@ -use log::info; +use std::collections::HashMap; +use std::hash::{DefaultHasher, Hash as _, Hasher as _}; +use std::thread; +use std::thread::JoinHandle; -use crate::{LUA, MODULE_NAME, PLUGIN_NAME, global, lua}; +use bstr::{BStr, BString, ByteSlice}; +use color_eyre::eyre::Context as _; +use color_eyre::{Result, eyre}; +use libp2p::futures::StreamExt; +use libp2p::gossipsub::{AllowAllSubscriptionFilter, Event, IdentityTransform, TopicHash}; +use libp2p::swarm::SwarmEvent; +use libp2p::{gossipsub, noise, tcp, yamux}; +use tokio::sync::mpsc::Receiver; +use tokio::sync::mpsc::error::TryRecvError; +use tokio::sync::mpsc::{self, UnboundedSender}; -pub(crate) struct Plugin {} +use crate::lua::{LuaValue, NAMESPACE_SEPARATOR}; +use crate::rpc::{RPC, RPCMessage}; +use crate::stingray_sdk::{LUA_REGISTRYINDEX, LuaRef, LuaState}; +use crate::{CHANNEL_BUFFER_SIZE, EVENTS_PER_TICK, lua}; +use crate::{LUA, MODULE_NAME, global}; + +#[derive(Clone, Copy, Debug)] +pub struct Identifier<'a> { + name: &'a BStr, + namespace: &'a BStr, +} + +impl<'a> Identifier<'a> { + pub fn new(namespace: &'a BStr, name: &'a BStr) -> Self { + Self { namespace, name } + } + + pub(crate) fn to_topic(self) -> TopicHash { + TopicHash::from_raw(format!("{}", self)) + } +} + +impl std::fmt::Display for Identifier<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}{}", self.namespace, NAMESPACE_SEPARATOR, self.name) + } +} + +#[derive(Debug)] +struct NamespacedMap { + map: HashMap>, +} + +impl NamespacedMap { + pub fn insert(&mut self, id: Identifier, val: T) { + if !self.map.contains_key(id.namespace) { + self.map.insert(id.namespace.to_owned(), Default::default()); + } + + let map = self + .map + .get_mut(id.namespace) + .expect("entry is verified to exist"); + map.insert(id.name.to_owned(), val); + } + + pub fn get(&self, id: &Identifier) -> Option<&T> { + self.map.get(id.namespace).and_then(|map| map.get(id.name)) + } +} + +impl Default for NamespacedMap { + fn default() -> Self { + Self { + map: Default::default(), + } + } +} + +enum Task {} + +pub(crate) struct Plugin { + swarm_thread: JoinHandle>, + event_rx: Receiver>, + send_tx: UnboundedSender, + rpcs: HashMap, + connect_listeners: HashMap, + disconnect_listeners: HashMap, +} impl Plugin { - pub fn new() -> Self { - Self {} + pub fn new() -> Result { + let mut swarm = libp2p::SwarmBuilder::with_new_identity() + .with_tokio() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + ) + .wrap_err("Failed to configure transport")? + .with_behaviour(|key| { + let message_id_fn = |msg: &gossipsub::Message| { + let mut s = DefaultHasher::new(); + msg.data.hash(&mut s); + gossipsub::MessageId::from(s.finish().to_string()) + }; + + let config = gossipsub::ConfigBuilder::default() + .validation_mode(gossipsub::ValidationMode::Strict) + .message_id_fn(message_id_fn) + .build() + .wrap_err("Failed to create gossipsub config")?; + + // TODO: Benchmark if compression would be beneficial. + let behavior: gossipsub::Behaviour = + gossipsub::Behaviour::new( + gossipsub::MessageAuthenticity::Signed(key.clone()), + config, + )?; + + Ok(behavior) + }) + .wrap_err("Failed to configure behavior")? + .build(); + + swarm + .listen_on( + "/ipv4/0.0.0.0/tcp/0" + .parse() + .expect("listen address invalid"), + ) + .wrap_err("failed to listen on IPv4 socket")?; + + // TODO: Connect to first hard coded relay server(s), which should then + // fan out to online peers. + // Maybe a cheap server (e.g. AWS free tier instance) is already enough to handle all + // session negotiations. If not, then a system is needed where each mod user also becomes + // available for that, and the hosted server merely acts as load balancer between them. + // + // swarm.dial(RELAY_SERVER) + + let (event_tx, event_rx) = mpsc::channel::>(CHANNEL_BUFFER_SIZE); + // Since the `Sender` will be on the sync side, and we want to avoid blocking, we make this + // unbounded to limit the chance for it to actually block. + let (send_tx, rpc_rx) = mpsc::unbounded_channel::(); + + let swarm_thread = thread::Builder::new() + .name("p2p-swarm".into()) + .spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .build() + .wrap_err("Failed to create tokio runtime")?; + + let mut swarm = swarm; + let mut rpc_rx = rpc_rx; + + rt.block_on(async move { + loop { + tokio::select! { + event = swarm.select_next_some() => { + event_tx.send(event).await.wrap_err("Failed to queue event")?; + } + msg = rpc_rx.recv() => { + let Some(msg) = msg else { + eyre::bail!("RPC queue closed prematurely"); + }; + swarm.behaviour_mut().publish(msg.topic, msg.data).wrap_err("Failed to send RPC")?; + } + } + } + }) + }) + .wrap_err("Failed to create p2p-swarm thread")?; + + Ok(Self { + swarm_thread, + event_rx, + send_tx, + rpcs: Default::default(), + connect_listeners: Default::default(), + disconnect_listeners: Default::default(), + }) } pub fn setup_game(&self) { - info!("[setup_game] Hello, world! This is {}!", PLUGIN_NAME); - let lua = global!(LUA); - lua.add_module_function(MODULE_NAME, "do_something", lua::do_something); + lua.add_module_function(MODULE_NAME, c"update", lua::update); + + lua.add_module_function(MODULE_NAME, c"create_rpc", lua::create_rpc); + lua.add_module_function(MODULE_NAME, c"send_rpc", lua::send_rpc); + lua.add_module_function(MODULE_NAME, c"receive_rpc", lua::receive_rpc); + + // TODO: Handle mod reloads + lua.add_module_function(MODULE_NAME, c"on_peer_connected", lua::on_peer_connected); + lua.add_module_function( + MODULE_NAME, + c"on_peer_disconnected", + lua::on_peer_disconnected, + ); + + log::info!("Plugin initialized"); } pub fn shutdown_game(&self) { - info!("[shutdown_game] Goodbye, world!"); + // TODO: Find a way to send a close command, and make it blocking. } - pub fn update_game(&self, _dt: f32) {} + // WARN: Due to how the instance of `Plugin` is currently stored and + // accessed by Lua functions, things will likely break if we attempt to get a `lua_State` here + // and trigger out own Lua functions. + pub fn update_game(&mut self, _dt: f32) {} + + pub fn lua_update(&mut self, _dt: f64, lua: &LuaState) -> Result<()> { + if self.swarm_thread.is_finished() { + eyre::bail!("p2p-swarm thread terminated prematurely",); + // TODO: Move `self.swarm_thread` into a data structure that I can move it out of here, + // so that I can call `.join` and get the error it ended with. + } + + // Limit the amount of events we handle per tick to avoid potential large spikes in + // frame time. + // TODO: Add a system to monitor the amount of incoming vs processed events, and add + // warnings when this cannot catch up. + // TODO: Check if it might become necessary to create a more elaborate system that can + // change this limit dynamically based on the amount of incoming messages. + // This must be able to eventually catch up. + for _ in 0..EVENTS_PER_TICK { + let event = match self.event_rx.try_recv() { + Ok(event) => event, + Err(TryRecvError::Empty) => break, + Err(TryRecvError::Disconnected) => { + eyre::bail!("p2p-swarm channel disconnected prematurely"); + } + }; + + match event { + SwarmEvent::Behaviour(Event::Message { + propagation_source, + message_id, + message: msg, + }) => { + log::debug!("Received message {message_id} from {propagation_source}"); + let Some(rpc) = self.rpcs.get(&msg.topic) else { + log::error!("Receive message for unknown topic {}", msg.topic); + continue; + }; + + let Ok((args, _)) = bincode::borrow_decode_from_slice::, _>( + &msg.data, + bincode::config::standard(), + ) else { + log::error!( + "Failed to decode data for message {message_id} on topic {}", + msg.topic + ); + continue; + }; + + args.push(lua); + let args_index = lua.gettop(); + + for fn_ref in rpc.listeners() { + lua.rawgeti(LUA_REGISTRYINDEX, *fn_ref); + lua.pushvalue(args_index); + lua.pcall(1, 0).wrap_err_with(|| { + format!("Failed to call listener for RPC '{}'", msg.topic) + })?; + } + } + SwarmEvent::Behaviour(Event::GossipsubNotSupported { peer_id }) => { + log::warn!( + "Peer {peer_id} does not support Gossipsub. Are they really a dt-p2p user?" + ); + } + SwarmEvent::ConnectionEstablished { + peer_id, + connection_id, + endpoint: _, + num_established, + concurrent_dial_errors: _, + established_in, + } => { + log::info!( + "Connection {} established with {} in {} ms. Total: {}", + connection_id, + peer_id, + established_in.as_millis(), + num_established + ); + // TODO: Establish mods shared with this peer + // TODO: Call `on_peer_connected` listeners for the corresponding mods + } + SwarmEvent::ConnectionClosed { + peer_id, + connection_id, + endpoint: _, + num_established, + cause, + } => { + log::info!( + "Connection {} with {} closed for reason {:?}. Total: {}", + connection_id, + peer_id, + cause, + num_established + ); + // TODO: Call `on_peer_disconnected` listeners for active mods + // TODO: Re-establish active mods + // With a peer dropping out, the amount of active mods may change if there is + // now only a single peer left for a mod. + } + SwarmEvent::IncomingConnectionError { + connection_id, + local_addr: _, + send_back_addr: _, + error, + } => { + log::error!("Error on incoming connection {connection_id}: {error}"); + } + SwarmEvent::OutgoingConnectionError { + connection_id, + peer_id: _, + error, + } => { + log::error!("Error on outgoing connection {connection_id}: {error}"); + } + SwarmEvent::ListenerError { listener_id, error } => { + log::error!("Listener {listener_id} failed: {error}"); + } + SwarmEvent::NewListenAddr { + listener_id, + address, + } => { + log::debug!("Listening on {address} with ID {listener_id}"); + } + // TODO: Maybe add tracing information for the events we don't handle + _ => {} + } + } + + Ok(()) + } + + pub(crate) fn create_rpc(&mut self, id: Identifier) { + let rpc = RPC::new(); + self.rpcs.insert(id.to_topic(), rpc); + } + + pub(crate) fn send_rpc(&self, id: Identifier, args: LuaValue<'_>) -> Result<()> { + if !self.rpcs.contains_key(&id.to_topic()) { + eyre::bail!("RPC '{}' does not exist", id); + } + + let args = bincode::encode_to_vec(args, bincode::config::standard()) + .wrap_err("Failed to encode RPC args")?; + + let msg = RPCMessage::new(id, args); + self.send_tx + .send(msg) + .wrap_err("Failed to queue RPC call")?; + + Ok(()) + } + + pub(crate) fn add_rpc_listener(&mut self, id: Identifier, fn_ref: i32) -> Result<()> { + let Some(rpc) = self.rpcs.get_mut(&id.to_topic()) else { + eyre::bail!("RPC '{}' does not exist", id); + }; + + rpc.add_listener(fn_ref); + + Ok(()) + } + + pub(crate) fn add_connect_listener(&mut self, mod_name: &BStr, fn_ref: i32) { + let key = TopicHash::from_raw(mod_name.to_str_lossy()); + self.connect_listeners.insert(key, fn_ref); + } + + pub(crate) fn add_disconnect_listener(&mut self, mod_name: &BStr, fn_ref: i32) { + let key = TopicHash::from_raw(mod_name.to_str_lossy()); + self.disconnect_listeners.insert(key, fn_ref); + } } impl std::fmt::Debug for Plugin { diff --git a/src/plugin_api.h b/src/plugin_api.h index 6cb4c3c..9b1dcb5 100644 --- a/src/plugin_api.h +++ b/src/plugin_api.h @@ -155,6 +155,17 @@ typedef int (*lua_Writer)(lua_State *L, const void *p, size_t sz, void *ud); typedef void *(*lua_Alloc)(void *ud, void *ptr, size_t osize, size_t nsize); typedef struct luaL_Reg luaL_Reg; +#define LUA_REGISTRYINDEX (-10000) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) + +#define LUA_OK 0 +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + /* Interface to access Lua services. */ diff --git a/src/rpc.rs b/src/rpc.rs new file mode 100644 index 0000000..eaff863 --- /dev/null +++ b/src/rpc.rs @@ -0,0 +1,43 @@ +use std::collections::HashSet; + +use libp2p::gossipsub::TopicHash; + +use crate::plugin::Identifier; +use crate::stingray_sdk::LuaRef; + +#[derive(Debug)] +pub(crate) struct RPC { + listeners: HashSet, +} + +impl RPC { + pub fn new() -> Self { + Self { + listeners: Default::default(), + } + } + + pub(crate) fn add_listener(&mut self, fn_ref: LuaRef) { + self.listeners.insert(fn_ref); + } + + pub(crate) fn listeners(&self) -> impl Iterator { + self.listeners.iter() + } +} + +#[derive(Debug)] +pub(crate) struct RPCMessage { + pub topic: TopicHash, + pub data: Vec, +} + +impl RPCMessage { + pub(crate) fn new(id: Identifier, data: impl Into>) -> Self { + let topic = id.to_topic(); + Self { + topic, + data: data.into(), + } + } +} diff --git a/src/stingray_sdk.rs b/src/stingray_sdk.rs index 9fde865..c310280 100644 --- a/src/stingray_sdk.rs +++ b/src/stingray_sdk.rs @@ -11,13 +11,22 @@ mod bindings { use std::ffi::CStr; use std::ffi::CString; use std::os::raw::c_char; +use std::os::raw::c_int; use std::os::raw::c_void; pub use bindings::GetApiFunction; +use bindings::LUA_OK; pub use bindings::PluginApi; pub use bindings::PluginApiID; use bindings::lua_CFunction; +use bindings::lua_Integer; +use bindings::lua_Number; pub use bindings::lua_State; +pub use bindings::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX, LUA_REGISTRYINDEX}; + +use bstr::BStr; +use color_eyre::Result; +use color_eyre::eyre; use log::Level; impl std::default::Default for PluginApi { @@ -131,6 +140,17 @@ impl log::Log for LoggingApi { fn flush(&self) {} } +#[repr(i32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LuaStatus { + Ok = bindings::LUA_OK as i32, + Yield = bindings::LUA_YIELD as i32, + ErrRun = bindings::LUA_ERRRUN as i32, + ErrSyntax = bindings::LUA_ERRSYNTAX as i32, + ErrMem = bindings::LUA_ERRMEM as i32, + ErrErr = bindings::LUA_ERRERR as i32, +} + #[repr(i32)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LuaType { @@ -183,10 +203,38 @@ impl std::fmt::Display for LuaType { } } +pub type LuaRef = i32; + pub struct LuaApi { add_module_function: unsafe extern "C" fn(*const c_char, *const c_char, lua_CFunction), - tolstring: unsafe extern "C" fn(*mut lua_State, i32, *mut usize) -> *const c_char, + createtable: unsafe extern "C" fn(*mut lua_State, i32, i32), + getfield: unsafe extern "C" fn(*mut lua_State, i32, *const c_char), + gettable: unsafe extern "C" fn(*mut lua_State, i32), + gettop: unsafe extern "C" fn(*mut lua_State) -> i32, + isnumber: unsafe extern "C" fn(*mut lua_State, i32) -> c_int, + isnil: unsafe extern "C" fn(*mut lua_State, i32) -> c_int, + isstring: unsafe extern "C" fn(*mut lua_State, i32) -> c_int, + istable: unsafe extern "C" fn(*mut lua_State, i32) -> c_int, + lib_argerror: unsafe extern "C" fn(*mut lua_State, i32, *const c_char) -> i32, + lib_checklstring: unsafe extern "C" fn(*mut lua_State, i32, *mut usize) -> *const c_char, + lib_error: unsafe extern "C" fn(*mut lua_State, *const c_char, ...) -> i32, + lib_ref: unsafe extern "C" fn(*mut lua_State, i32) -> i32, + next: unsafe extern "C" fn(*mut lua_State, i32) -> i32, + objlen: unsafe extern "C" fn(*mut lua_State, i32) -> usize, + pcall: unsafe extern "C" fn(*mut lua_State, i32, i32, i32) -> i32, + pop: unsafe extern "C" fn(*mut lua_State), + pushboolean: unsafe extern "C" fn(*mut lua_State, i32), + pushinteger: unsafe extern "C" fn(*mut lua_State, lua_Integer), + pushnil: unsafe extern "C" fn(*mut lua_State), + pushnumber: unsafe extern "C" fn(*mut lua_State, lua_Number), pushstring: unsafe extern "C" fn(*mut lua_State, *const c_char), + pushvalue: unsafe extern "C" fn(*mut lua_State, i32), + rawgeti: unsafe extern "C" fn(*mut lua_State, i32, i32), + r#type: unsafe extern "C" fn(*mut lua_State, i32) -> i32, + settable: unsafe extern "C" fn(*mut lua_State, i32), + toboolean: unsafe extern "C" fn(*mut lua_State, i32) -> i32, + tolstring: unsafe extern "C" fn(*mut lua_State, i32, *mut usize) -> *const c_char, + tonumber: unsafe extern "C" fn(*mut lua_State, i32) -> f64, } impl LuaApi { @@ -199,40 +247,211 @@ impl LuaApi { unsafe { Self { add_module_function: (*api).add_module_function.unwrap_unchecked(), - tolstring: (*api).tolstring.unwrap_unchecked(), + createtable: (*api).createtable.unwrap_unchecked(), + getfield: (*api).getfield.unwrap_unchecked(), + gettable: (*api).gettable.unwrap_unchecked(), + gettop: (*api).gettop.unwrap_unchecked(), + isnumber: (*api).isnumber.unwrap_unchecked(), + isnil: (*api).isnil.unwrap_unchecked(), + isstring: (*api).isstring.unwrap_unchecked(), + istable: (*api).istable.unwrap_unchecked(), + lib_argerror: (*api).lib_argerror.unwrap_unchecked(), + lib_checklstring: (*api).lib_checklstring.unwrap_unchecked(), + lib_error: (*api).lib_error.unwrap_unchecked(), + lib_ref: (*api).lib_ref.unwrap_unchecked(), + next: (*api).next.unwrap_unchecked(), + objlen: (*api).objlen.unwrap_unchecked(), + pcall: (*api).pcall.unwrap_unchecked(), + pop: (*api).pop.unwrap_unchecked(), + pushboolean: (*api).pushboolean.unwrap_unchecked(), + pushinteger: (*api).pushinteger.unwrap_unchecked(), + pushnil: (*api).pushnil.unwrap_unchecked(), + pushnumber: (*api).pushnumber.unwrap_unchecked(), pushstring: (*api).pushstring.unwrap_unchecked(), + pushvalue: (*api).pushvalue.unwrap_unchecked(), + rawgeti: (*api).rawgeti.unwrap_unchecked(), + r#type: (*api).type_.unwrap_unchecked(), + settable: (*api).settable.unwrap_unchecked(), + toboolean: (*api).toboolean.unwrap_unchecked(), + tolstring: (*api).tolstring.unwrap_unchecked(), + tonumber: (*api).tonumber.unwrap_unchecked(), } } } pub fn add_module_function( &self, - module: impl Into>, - name: impl Into>, + module: impl AsRef, + name: impl AsRef, cb: extern "C" fn(*mut lua_State) -> i32, ) { - let module = CString::new(module).expect("Invalid CString"); - let name = CString::new(name).expect("Invalid CString"); - - unsafe { (self.add_module_function)(module.as_ptr(), name.as_ptr(), Some(cb)) } - } - - pub fn tolstring(&self, L: *mut lua_State, idx: i32) -> Option<&CStr> { - let mut len: usize = 0; - - let c = unsafe { (self.tolstring)(L, idx, &mut len as *mut _) }; - - if len == 0 { - None - } else { - // Safety: As long as `len > 0`, Lua guarantees the constraints that `CStr::from_ptr` - // requires. - Some(unsafe { CStr::from_ptr(c) }) + unsafe { + (self.add_module_function)(module.as_ref().as_ptr(), name.as_ref().as_ptr(), Some(cb)) } } +} - pub fn pushstring(&self, L: *mut lua_State, s: impl Into>) { +/// A wrapper that combines a lua_State and a LuaApi to make calling functions more convenient. +pub struct LuaState<'a> { + l: *mut lua_State, + api: &'a LuaApi, +} + +impl<'a> LuaState<'a> { + pub fn new(l: *mut lua_State, api: &'a LuaApi) -> Self { + Self { l, api } + } + + pub fn gettop(&self) -> i32 { + unsafe { (self.api.gettop)(self.l) } + } + + pub fn pushvalue(&self, idx: i32) { + unsafe { (self.api.pushvalue)(self.l, idx) } + } + + pub fn isnil(&self, idx: i32) -> bool { + let is_nil = unsafe { (self.api.isnil)(self.l, idx) }; + is_nil > 0 + } + + pub fn isnumber(&self, idx: i32) -> bool { + let is_number = unsafe { (self.api.isnumber)(self.l, idx) }; + is_number > 0 + } + + pub fn isstring(&self, idx: i32) -> bool { + let is_string = unsafe { (self.api.isstring)(self.l, idx) }; + is_string > 0 + } + + pub fn isfunction(&self, idx: i32) -> bool { + let is_fn = unsafe { (self.api.isfunction)(self.l, idx) }; + is_fn > 0 + } + + pub fn istable(&self, idx: i32) -> bool { + let is_table = unsafe { (self.api.istable)(self.l, idx) }; + is_table > 0 + } + + pub fn r#type(&self, idx: i32) -> LuaType { + let t = unsafe { (self.api.r#type)(self.l, idx) }; + t.into() + } + + pub fn tonumber(&self, idx: i32) -> f64 { + unsafe { (self.api.tonumber)(self.l, idx) } + } + + pub fn toboolean(&self, idx: i32) -> bool { + let n = unsafe { (self.api.toboolean)(self.l, idx) }; + n != 0 + } + + pub fn tostring(&self, idx: i32) -> &BStr { + let bytes = unsafe { + let mut len = 0usize; + // `c_char` is `i8` by default, but printable characters are all > 0, so we don't care. + let c = (self.api.tolstring)(self.l, idx, &mut len) as *const u8; + std::slice::from_raw_parts(c, len) + }; + BStr::new(bytes) + } + + pub fn objlen(&self, idx: i32) -> usize { + unsafe { (self.api.objlen)(self.l, idx) } + } + + pub fn pushnil(&self) { + unsafe { (self.api.pushnil)(self.l) }; + } + + pub fn pushnumber(&self, n: f64) { + unsafe { (self.api.pushnumber)(self.l, n) }; + } + + pub fn pushinteger(&self, n: isize) { + unsafe { (self.api.pushinteger)(self.l, n) }; + } + + pub fn pushstring(&self, s: impl Into>) { let s = CString::new(s).expect("Invalid CString"); - unsafe { (self.pushstring)(L, s.as_ptr()) } + unsafe { (self.api.pushstring)(self.l, s.as_ptr()) }; + } + + pub fn pushboolean(&self, b: bool) { + unsafe { (self.api.pushboolean)(self.l, b as i32) } + } + + pub fn gettable(&self, idx: i32) { + unsafe { (self.api.gettable)(self.l, idx) } + } + + pub fn getfield(&self, idx: i32, k: impl AsRef) { + unsafe { (self.api.getfield)(self.l, idx, k.as_ref().as_ptr()) } + } + + pub fn createtable(&self, narr: i32, nrec: i32) { + unsafe { (self.api.createtable)(self.l, narr, nrec) } + } + + pub fn settable(&self, idx: i32) { + unsafe { (self.api.settable)(self.l, idx) } + } + + pub fn rawgeti(&self, idx: i32, n: i32) { + unsafe { (self.api.rawgeti)(self.l, idx, n) } + } + + pub fn call(&self, nargs: i32, nresults: i32) { + self.pcall(nargs, nresults).unwrap() + } + + pub fn pcall(&self, nargs: i32, nresults: i32) -> Result<()> { + // TODO: Re-create the engine's error handler function to populate the stack trace and + // local variables. + let res = unsafe { (self.api.pcall)(self.l, nargs, nresults, 0) }; + if res as u32 == LUA_OK { + return Ok(()); + } + + let err = self.tostring(-1); + eyre::bail!("pcall failed: {}", err) + } + + pub fn next(&self, idx: i32) -> i32 { + unsafe { (self.api.next)(self.l, idx) } + } + + pub fn lib_argerror(&self, narg: i32, msg: impl AsRef) -> i32 { + unsafe { (self.api.lib_argerror)(self.l, narg, msg.as_ref().as_ptr()) } + } + + pub fn lib_checklstring(&self, idx: i32) -> &BStr { + let bytes = unsafe { + let mut len = 0usize; + // `c_char` is `i8` by default, but printable characters are all > 0, so we don't care. + let c = (self.api.lib_checklstring)(self.l, idx, &mut len) as *const u8; + std::slice::from_raw_parts(c, len) + }; + BStr::new(bytes) + } + + // Lua's `luaL_error` does have printf-like formatting capabilities, + // but since we can just use `format!()`, we don't need to bother handling the varargs here. + pub fn lib_error(&self, msg: impl Into>) -> i32 { + let s = CString::new(msg).expect("Invalid CString"); + unsafe { (self.api.lib_error)(self.l, s.as_ptr()) } + } + + pub fn lib_ref(&self, t: i32) -> LuaRef { + unsafe { (self.api.lib_ref)(self.l, t) } + } + + // NOTE: This is not like the standard `lua_pop`, it only pops one value at a time. + // If more values need to be popped, use `settop(-x)`. + pub fn pop(&self) { + unsafe { (self.api.pop)(self.l) }; } } From 3b9d652b7a7017e0feeab7d9bc5e6f332535ef85 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Fri, 30 May 2025 11:53:37 +0200 Subject: [PATCH 2/5] WIP --- src/lib.rs | 4 +- src/lua.rs | 207 ++++++++++++------- src/plugin.rs | 477 +++++++++++++++++++++++++++++++++++--------- src/rpc.rs | 19 -- src/stingray_sdk.rs | 21 +- 5 files changed, 541 insertions(+), 187 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 57ffed6..78ef962 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,9 @@ pub extern "C" fn setup_game(get_engine_api: GetApiFunction) { }; plugin.setup_game(); - PLUGIN.set(RwLock::new(plugin)); + PLUGIN + .set(RwLock::new(plugin)) + .expect("Failed to set global plugin instance"); } #[unsafe(no_mangle)] diff --git a/src/lua.rs b/src/lua.rs index c045a51..7570734 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ffi::CStr; use std::panic::catch_unwind; use bstr::BStr; @@ -8,6 +9,7 @@ use color_eyre::eyre; use color_eyre::eyre::Context as _; use crate::plugin::Identifier; +use crate::plugin::ModCallbacks; use crate::plugin::Plugin; use crate::stingray_sdk::LUA_REGISTRYINDEX; use crate::stingray_sdk::{LuaState, LuaType, lua_State}; @@ -15,25 +17,34 @@ use crate::{LUA, global, plugin_mut}; pub const NAMESPACE_SEPARATOR: char = '.'; -static RPC_CALLBACK_KEY: &str = "dt-p2p.rpc-callbacks"; - // As a minor optimization, only `catch_unwind` in debug mode. #[cfg(debug_assertions)] fn lua_wrapper(l: *mut lua_State, f: F) -> i32 where F: FnOnce(&mut Plugin, &LuaState) -> Result + std::panic::UnwindSafe, { - let lua = LuaState::new(l, global!(LUA)); + let lua = global!(LUA); - let res = catch_unwind(|| { - let mut plugin = plugin_mut!(); - f(&mut plugin, &lua) - }); - match res { - Ok(Ok(i)) => i, - Ok(Err(err)) => lua.lib_error(format!("{:?}", err)), - Err(err) => lua.lib_error(format!("{:?}", err)), + // We need to drop as many things as possible before the `lua_error` call + // will longjmp and thereby ignoring Rust's cleanup. + { + let lua = LuaState::new(l, lua); + + let res = catch_unwind(|| { + let mut plugin = plugin_mut!(); + f(&mut plugin, &lua) + }); + match res { + Ok(Ok(i)) => { + return i; + } + Ok(Err(err)) => lua.pushstring(format!("{:?}", err)), + Err(err) => lua.pushstring(format!("{:?}", err)), + } } + + lua.error(l); + 0 } #[cfg(not(debug_assertions))] @@ -41,14 +52,25 @@ fn lua_wrapper(l: *mut lua_State, f: F) -> i32 where F: FnOnce(&mut Plugin, &LuaState) -> Result, { - let lua = LuaState::new(l, global!(LUA)); - let plugin = plugin_mut!(); + let lua = global!(LUA); - let res = f(&mut plugin, &lua); - match res { - Ok(i) => i, - Err(err) => lua.lib_error(format!("{:?}", err)), + // We need to drop as many things as possible before the `lua_error` call + // will longjmp and thereby ignoring Rust's cleanup. + { + let lua = LuaState::new(l, lua); + + let mut plugin = plugin_mut!(); + match f(&mut plugin, &lua) { + Ok(Ok(i)) => { + return i; + } + Ok(Err(err)) => lua.pushstring(format!("{:?}", err)), + Err(err) => lua.pushstring(format!("{:?}", err)), + } } + + lua.error(l); + 0 } /// Returns the namespace and name for a RPC. @@ -72,6 +94,64 @@ fn get_identifier<'a>(lua: &'a LuaState) -> Result> { Ok(Identifier::new(namespace, name)) } +// Called with `(mod: table, callbacks: table)` +pub extern "C" fn register_mod(l: *mut lua_State) -> i32 { + lua_wrapper(l, |plugin, lua| { + if !lua.istable(1) { + eyre::bail!("bad argument #1, expected a mod object"); + } + + let name = { + lua.getfield(1, c"name"); + if !lua.isstring(-1) { + eyre::bail!("bad argument #1, not a mod object"); + } + + lua.tostring(-1) + }; + + let callbacks = match lua.r#type(2) { + LuaType::Nil => ModCallbacks::default(), + LuaType::Table => { + let get_callback = |name: &CStr| { + lua.getfield(2, name); + + match lua.r#type(-1) { + LuaType::Nil => Ok(None), + LuaType::Function => Ok(Some(lua.lib_ref(LUA_REGISTRYINDEX))), + x => { + eyre::bail!( + "bad argument #2, expected a function for field {}, got {}", + name.to_string_lossy(), + x + ); + } + } + }; + + ModCallbacks { + on_session_joined: get_callback(c"on_session_joined")?, + on_session_left: get_callback(c"on_session_left")?, + on_user_joined: get_callback(c"on_user_joined")?, + on_user_left: get_callback(c"on_user_left")?, + } + } + x => { + eyre::bail!("bad argument #2, expected a table got {}", x); + } + }; + + plugin.register_mod(name, callbacks); + + // TODO: Register unload and disable handlers? + // Will likely have to monkey-patch the mod object. + // DMF doesn't expose a good way to hook into it, and it wouldn't be feasible to expect a + // DMF update to allow it. + + Ok(0) + }) +} + // Called with `(mod: table, name: string, opts: table)` pub extern "C" fn create_rpc(l: *mut lua_State) -> i32 { lua_wrapper(l, |plugin, lua| { @@ -99,7 +179,10 @@ pub extern "C" fn create_rpc(l: *mut lua_State) -> i32 { version } x => { - eyre::bail!("invalid type {} for 'version' field", x) + eyre::bail!( + "invalid type {} for 'version' field, must be number or a version string", + x + ) } }; @@ -113,14 +196,14 @@ pub extern "C" fn create_rpc(l: *mut lua_State) -> i32 { type LuaMap<'a> = HashMap, LuaValue<'a>>; #[derive(bincode::BorrowDecode, bincode::Encode, PartialEq)] -enum LuaKey<'a> { +pub enum LuaKey<'a> { String(&'a [u8]), Number(f64), } -impl<'a> Eq for LuaKey<'a> {} +impl Eq for LuaKey<'_> {} -impl<'a> std::hash::Hash for LuaKey<'a> { +impl std::hash::Hash for LuaKey<'_> { fn hash(&self, state: &mut H) { match self { LuaKey::String(s) => s.hash(state), @@ -141,7 +224,7 @@ pub enum LuaValue<'a> { impl<'a> LuaValue<'a> { fn parse_table(lua: &'a LuaState, idx: i32) -> Result { let mut values = LuaMap::default(); - // + // `nil` as initial key tells `lua_next` to pick the first key. lua.pushnil(); @@ -156,7 +239,7 @@ impl<'a> LuaValue<'a> { t => eyre::bail!("Unsupported type {} for args table key", t), }; - let value = Self::parse(lua, -1)?; + let value = Self::get_from_stack(lua, -1)?; values.insert(key, value); @@ -170,7 +253,8 @@ impl<'a> LuaValue<'a> { Ok(LuaValue::Table(values)) } - pub fn parse(lua: &'a LuaState, idx: i32) -> Result { + /// Gets the value from the stack at `idx` + pub fn get_from_stack(lua: &'a LuaState, idx: i32) -> Result { match lua.r#type(idx) { LuaType::None | LuaType::Nil => Ok(LuaValue::Nil), LuaType::Boolean => Ok(LuaValue::Boolean(lua.toboolean(-1))), @@ -181,7 +265,8 @@ impl<'a> LuaValue<'a> { } } - pub fn push(&self, lua: &LuaState) { + /// Pushes the value onto a Lua stack + pub fn push_to_stack(&self, lua: &LuaState) { match self { LuaValue::Nil => lua.pushnil(), LuaValue::Boolean(bool) => lua.pushboolean(*bool), @@ -206,7 +291,7 @@ impl<'a> LuaValue<'a> { LuaKey::Number(num) => lua.pushnumber(*num), } - v.push(lua); + v.push_to_stack(lua); lua.settable(tbl_index); } @@ -261,73 +346,47 @@ pub extern "C" fn receive_rpc(l: *mut lua_State) -> i32 { lua.pushvalue(3); let fn_ref = lua.lib_ref(LUA_REGISTRYINDEX); - plugin.add_rpc_listener(id, fn_ref); + plugin + .add_rpc_listener(id, fn_ref) + .wrap_err("Failed to add RPC listener")?; Ok(0) }) } -// Called with `(mod: table, callback: Fn(peer_id))` -pub extern "C" fn on_peer_connected(l: *mut lua_State) -> i32 { +// Called with `(server_name: string, peer_id: string, player_id: string)` +pub extern "C" fn join_session(l: *mut lua_State) -> i32 { lua_wrapper(l, |plugin, lua| { - if !lua.istable(1) { - eyre::bail!("bad argument #1, expected a mod object"); + if !lua.isstring(1) { + eyre::bail!("bad argument #1, expected a string"); } - if !lua.isfunction(2) { - eyre::bail!("bad argument #2, expected a function"); + if !lua.isstring(2) { + eyre::bail!("bad argument #2, expected a string"); } - lua.getfield(1, c"name"); - if !lua.isstring(-1) { - eyre::bail!("bad argument #1, not a mod object"); + if !lua.isstring(3) { + eyre::bail!("bad argument #3, expected a string"); } - let mod_name = lua.tostring(-1); - lua.pushvalue(3); - let fn_ref = lua.lib_ref(LUA_REGISTRYINDEX); + let server_name = lua.tostring(1); + let peer_id = lua.tostring(2); + let player_id = lua.tostring(3); - plugin.add_connect_listener(mod_name, fn_ref); + plugin + .join_session(lua, server_name, peer_id, player_id) + .wrap_err("Failed to join session")?; Ok(0) }) } -// Called with `(mod: table, callback: Fn(peer_id))` -pub extern "C" fn on_peer_disconnected(l: *mut lua_State) -> i32 { +// Called with `()` +pub extern "C" fn leave_session(l: *mut lua_State) -> i32 { lua_wrapper(l, |plugin, lua| { - if !lua.istable(1) { - eyre::bail!("bad argument #1, expected a mod object"); - } - - if !lua.isfunction(2) { - eyre::bail!("bad argument #2, expected a function"); - } - - lua.getfield(1, c"name"); - if !lua.isstring(-1) { - eyre::bail!("bad argument #1, expected a mod object"); - } - - let mod_name = lua.tostring(-1); - lua.pushvalue(3); - let fn_ref = lua.lib_ref(LUA_REGISTRYINDEX); - - plugin.add_disconnect_listener(mod_name, fn_ref); - - Ok(0) - }) -} - -// Called with `(dt: float)` -pub extern "C" fn update(l: *mut lua_State) -> i32 { - lua_wrapper(l, |plugin, lua| { - if !lua.isnumber(1) { - eyre::bail!("bad argument #1, expected a number"); - } - - let dt = lua.tonumber(1); - plugin.lua_update(dt, lua)?; + plugin + .leave_session(lua) + .wrap_err("Failed to leave session")?; Ok(0) }) diff --git a/src/plugin.rs b/src/plugin.rs index 5f1e266..e7f4045 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,25 +1,38 @@ use std::collections::HashMap; -use std::hash::{DefaultHasher, Hash as _, Hasher as _}; +use std::hash::{DefaultHasher, Hash, Hasher as _}; +use std::mem; +use std::ops::Deref; use std::thread; use std::thread::JoinHandle; -use bstr::{BStr, BString, ByteSlice}; +use bstr::{BStr, BString}; +use color_eyre::Result; +use color_eyre::eyre; use color_eyre::eyre::Context as _; -use color_eyre::{Result, eyre}; +use libp2p::PeerId; use libp2p::futures::StreamExt; -use libp2p::gossipsub::{AllowAllSubscriptionFilter, Event, IdentityTransform, TopicHash}; +use libp2p::gossipsub; +use libp2p::gossipsub::{ + AllowAllSubscriptionFilter, Event, IdentTopic, IdentityTransform, Message, TopicHash, +}; +use libp2p::noise; use libp2p::swarm::SwarmEvent; -use libp2p::{gossipsub, noise, tcp, yamux}; +use libp2p::tcp; +use libp2p::yamux; +use tokio::sync::mpsc; use tokio::sync::mpsc::Receiver; +use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::error::TryRecvError; -use tokio::sync::mpsc::{self, UnboundedSender}; +use crate::lua; use crate::lua::{LuaValue, NAMESPACE_SEPARATOR}; -use crate::rpc::{RPC, RPCMessage}; +use crate::rpc::RPC; use crate::stingray_sdk::{LUA_REGISTRYINDEX, LuaRef, LuaState}; -use crate::{CHANNEL_BUFFER_SIZE, EVENTS_PER_TICK, lua}; +use crate::{CHANNEL_BUFFER_SIZE, EVENTS_PER_TICK}; use crate::{LUA, MODULE_NAME, global}; +type ModName = BString; + #[derive(Clone, Copy, Debug)] pub struct Identifier<'a> { name: &'a BStr, @@ -30,9 +43,11 @@ impl<'a> Identifier<'a> { pub fn new(namespace: &'a BStr, name: &'a BStr) -> Self { Self { namespace, name } } +} - pub(crate) fn to_topic(self) -> TopicHash { - TopicHash::from_raw(format!("{}", self)) +impl From> for String { + fn from(value: Identifier<'_>) -> Self { + format!("{}", value) } } @@ -42,46 +57,109 @@ impl std::fmt::Display for Identifier<'_> { } } +#[derive(Debug, bincode::Encode, bincode::Decode)] +// To avoid having to implement `bincode` for `bstr` types, we use raw `Vec` here, +// which can be turned into `BString` cheaply. +pub(crate) enum SwarmMessage { + // To avoid extra cloning, or having to deal with lifetimes, + // this message type contains the Lua args already encoded. + Rpc(Vec), + SessionJoin { + /// The in-game player ID for this peer + player_id: Vec, + /// A list of mod names this peer has enabled + mods: Vec>, + }, + SessionLeave, +} + #[derive(Debug)] -struct NamespacedMap { - map: HashMap>, +pub(crate) enum SwarmTask { + Message { topic: Topic, msg: SwarmMessage }, + Subscribe(Topic), + Unsubscribe(Vec), } -impl NamespacedMap { - pub fn insert(&mut self, id: Identifier, val: T) { - if !self.map.contains_key(id.namespace) { - self.map.insert(id.namespace.to_owned(), Default::default()); - } +#[derive(Clone, Debug)] +pub(crate) struct Topic(IdentTopic); - let map = self - .map - .get_mut(id.namespace) - .expect("entry is verified to exist"); - map.insert(id.name.to_owned(), val); - } - - pub fn get(&self, id: &Identifier) -> Option<&T> { - self.map.get(id.namespace).and_then(|map| map.get(id.name)) +impl Eq for Topic {} +impl PartialEq for Topic { + fn eq(&self, other: &Self) -> bool { + self.0.hash() == other.0.hash() } } -impl Default for NamespacedMap { - fn default() -> Self { - Self { - map: Default::default(), - } +impl Hash for Topic { + fn hash(&self, state: &mut H) { + self.0.hash().hash(state); } } -enum Task {} +impl std::fmt::Display for Topic { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::ops::Deref for Topic { + type Target = IdentTopic; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for TopicHash { + fn from(value: Topic) -> Self { + Self::from(value.0) + } +} + +#[derive(Debug)] +struct Player { + id: BString, + mods: Vec, +} + +#[derive(Default)] +pub(crate) struct ModCallbacks { + pub on_session_joined: Option, + pub on_session_left: Option, + pub on_user_joined: Option, + pub on_user_left: Option, +} + +struct Session { + online: bool, + address: String, + peer_id: BString, + topics: HashMap, + peers: HashMap, +} + +impl Session { + pub fn new_topic(&mut self, topic: impl Into) -> &Topic { + self.topics + .entry(TopicHash::from_raw(topic.into())) + .or_insert_with_key(|topic| { + Topic(IdentTopic::new(format!("{}/{}", self.address, topic))) + }) + } + + pub fn get_topic(&self, topic: impl Into) -> Option<&Topic> { + let hash = TopicHash::from_raw(topic.into()); + self.topics.get(&hash) + } +} pub(crate) struct Plugin { swarm_thread: JoinHandle>, event_rx: Receiver>, - send_tx: UnboundedSender, - rpcs: HashMap, - connect_listeners: HashMap, - disconnect_listeners: HashMap, + send_tx: UnboundedSender, + session: Session, + rpcs: HashMap, + mods: HashMap, } impl Plugin { @@ -138,7 +216,7 @@ impl Plugin { let (event_tx, event_rx) = mpsc::channel::>(CHANNEL_BUFFER_SIZE); // Since the `Sender` will be on the sync side, and we want to avoid blocking, we make this // unbounded to limit the chance for it to actually block. - let (send_tx, rpc_rx) = mpsc::unbounded_channel::(); + let (send_tx, send_rx) = mpsc::unbounded_channel::(); let swarm_thread = thread::Builder::new() .name("p2p-swarm".into()) @@ -148,7 +226,7 @@ impl Plugin { .wrap_err("Failed to create tokio runtime")?; let mut swarm = swarm; - let mut rpc_rx = rpc_rx; + let mut send_rx = send_rx; rt.block_on(async move { loop { @@ -156,11 +234,32 @@ impl Plugin { event = swarm.select_next_some() => { event_tx.send(event).await.wrap_err("Failed to queue event")?; } - msg = rpc_rx.recv() => { - let Some(msg) = msg else { - eyre::bail!("RPC queue closed prematurely"); + task = send_rx.recv() => { + let Some(task) = task else { + eyre::bail!("Task queue closed prematurely"); }; - swarm.behaviour_mut().publish(msg.topic, msg.data).wrap_err("Failed to send RPC")?; + + let behavior = swarm.behaviour_mut(); + + match task{ + SwarmTask::Message { topic, msg } => { + let data = bincode::encode_to_vec(msg, bincode::config::standard()) + .wrap_err("Failed to encode swarm message")?; + behavior + .publish(topic, data) + .wrap_err("Failed to send message")?; + }, + SwarmTask::Subscribe(topic) => { + behavior + .subscribe(&topic) + .wrap_err_with(|| format!("Failed to subscribe to topic {}", topic))?; + }, + SwarmTask::Unsubscribe(topics) => { + for topic in topics { + behavior.unsubscribe(&topic); + } + } + } } } } @@ -168,51 +267,64 @@ impl Plugin { }) .wrap_err("Failed to create p2p-swarm thread")?; + log::info!("Plugin initialized"); + Ok(Self { swarm_thread, event_rx, send_tx, + session: Session { + online: false, + address: Default::default(), + peer_id: Default::default(), + topics: Default::default(), + peers: Default::default(), + }, rpcs: Default::default(), - connect_listeners: Default::default(), - disconnect_listeners: Default::default(), + mods: Default::default(), }) } pub fn setup_game(&self) { let lua = global!(LUA); - lua.add_module_function(MODULE_NAME, c"update", lua::update); + // Internal API + // TODO: Maybe useful to move these to a separate module, e.g. `P2PInternal`? + lua.add_module_function(MODULE_NAME, c"join_session", lua::join_session); + lua.add_module_function(MODULE_NAME, c"leave_session", lua::leave_session); + // User-facing API + lua.add_module_function(MODULE_NAME, c"register_mod", lua::register_mod); lua.add_module_function(MODULE_NAME, c"create_rpc", lua::create_rpc); lua.add_module_function(MODULE_NAME, c"send_rpc", lua::send_rpc); lua.add_module_function(MODULE_NAME, c"receive_rpc", lua::receive_rpc); - // TODO: Handle mod reloads - lua.add_module_function(MODULE_NAME, c"on_peer_connected", lua::on_peer_connected); - lua.add_module_function( - MODULE_NAME, - c"on_peer_disconnected", - lua::on_peer_disconnected, - ); - - log::info!("Plugin initialized"); + log::debug!("Lua functions registered"); } pub fn shutdown_game(&self) { // TODO: Find a way to send a close command, and make it blocking. } - // WARN: Due to how the instance of `Plugin` is currently stored and - // accessed by Lua functions, things will likely break if we attempt to get a `lua_State` here - // and trigger out own Lua functions. - pub fn update_game(&mut self, _dt: f32) {} + pub fn update_game(&mut self, dt: f32) { + if let Err(err) = self.update(dt) { + log::error!("{:?}", err); + // TODO: Exit application or find a better way to report the error + } + } - pub fn lua_update(&mut self, _dt: f64, lua: &LuaState) -> Result<()> { + pub fn update(&mut self, _dt: f32) -> Result<()> { if self.swarm_thread.is_finished() { eyre::bail!("p2p-swarm thread terminated prematurely",); // TODO: Move `self.swarm_thread` into a data structure that I can move it out of here, // so that I can call `.join` and get the error it ended with. } + let lua = { + let lua = global!(LUA); + let l = lua.getscriptenvironmentstate(); + LuaState::new(l, lua) + }; + // Limit the amount of events we handle per tick to avoid potential large spikes in // frame time. // TODO: Add a system to monitor the amount of incoming vs processed events, and add @@ -233,34 +345,125 @@ impl Plugin { SwarmEvent::Behaviour(Event::Message { propagation_source, message_id, - message: msg, + message: + Message { + topic, + data, + source, + sequence_number: _, + }, }) => { - log::debug!("Received message {message_id} from {propagation_source}"); - let Some(rpc) = self.rpcs.get(&msg.topic) else { - log::error!("Receive message for unknown topic {}", msg.topic); + log::debug!( + "Received message {message_id} from {propagation_source} for topic {}", + topic + ); + + let Some(topic) = self.session.topics.get(&topic) else { + log::warn!("Received message for unknown topic {}", topic); continue; }; - let Ok((args, _)) = bincode::borrow_decode_from_slice::, _>( - &msg.data, + let Ok((msg, _)) = bincode::borrow_decode_from_slice::( + &data, bincode::config::standard(), ) else { log::error!( "Failed to decode data for message {message_id} on topic {}", - msg.topic + topic ); continue; }; - args.push(lua); - let args_index = lua.gettop(); + match msg { + SwarmMessage::Rpc(rpc_args) => { + let Some(rpc) = self.rpcs.get(topic) else { + log::warn!("Topic {} does not have an RPC", topic); + continue; + }; - for fn_ref in rpc.listeners() { - lua.rawgeti(LUA_REGISTRYINDEX, *fn_ref); - lua.pushvalue(args_index); - lua.pcall(1, 0).wrap_err_with(|| { - format!("Failed to call listener for RPC '{}'", msg.topic) - })?; + let Ok((args, _)) = bincode::borrow_decode_from_slice::, _>( + &rpc_args, + bincode::config::standard(), + ) else { + log::error!( + "Failed to decode data for message {message_id} on topic {}", + topic + ); + continue; + }; + + args.push_to_stack(&lua); + let args_index = lua.gettop(); + + for fn_ref in rpc.listeners() { + lua.rawgeti(LUA_REGISTRYINDEX, *fn_ref); + lua.pushvalue(args_index); + lua.pcall(1, 0).wrap_err_with(|| { + format!("Failed to call listener for RPC '{}'", topic) + })?; + } + } + SwarmMessage::SessionJoin { player_id, mods } => match source { + Some(peer_id) => { + let id = BString::new(player_id); + let mods = mods.into_iter().map(ModName::new).collect::>(); + let peer = Player { id, mods }; + + // TODO: Check if a corresponding player is in the lobby + + { + let callbacks = self + .mods + .iter() + .filter(|(name, _)| peer.mods.contains(name)) + .filter_map(|(_, cbs)| cbs.on_user_joined); + + lua.pushstring(peer.id.clone()); + let arg_index = lua.gettop(); + + for fn_ref in callbacks { + lua.pushnumber(fn_ref as f64); + lua.gettable(LUA_REGISTRYINDEX); + lua.pushvalue(arg_index); + lua.pcall(1, 0) + .wrap_err("on_user_joined handler failed")?; + } + } + + self.session.peers.insert(peer_id, peer); + } + None => { + log::warn!( + "Got SessionJoin event without a source peer_id. Don't know how to handle." + ); + } + }, + SwarmMessage::SessionLeave => match source { + Some(peer_id) => { + if let Some(peer) = self.session.peers.remove(&peer_id) { + let callbacks = self + .mods + .iter() + .filter(|(name, _)| peer.mods.contains(name)) + .filter_map(|(_, cbs)| cbs.on_user_left); + + lua.pushstring(peer.id); + let arg_index = lua.gettop(); + + for fn_ref in callbacks { + lua.pushnumber(fn_ref as f64); + lua.gettable(LUA_REGISTRYINDEX); + lua.pushvalue(arg_index); + lua.pcall(1, 0).wrap_err("on_user_left handler failed")?; + } + } + } + None => { + log::warn!( + "Got SessionLeave event without a source peer_id. Don't know how to handle." + ); + } + }, } } SwarmEvent::Behaviour(Event::GossipsubNotSupported { peer_id }) => { @@ -283,8 +486,9 @@ impl Plugin { established_in.as_millis(), num_established ); - // TODO: Establish mods shared with this peer - // TODO: Call `on_peer_connected` listeners for the corresponding mods + // TODO: Start a timeout to wait for a `SwarmMessage::SessionJoin` to show a + // warning when a client connected but didn't join the session. + // Not sure if that should ever happen. } SwarmEvent::ConnectionClosed { peer_id, @@ -300,10 +504,13 @@ impl Plugin { cause, num_established ); - // TODO: Call `on_peer_disconnected` listeners for active mods - // TODO: Re-establish active mods - // With a peer dropping out, the amount of active mods may change if there is - // now only a single peer left for a mod. + if self.session.peers.contains_key(&peer_id) { + log::warn!("Peer dropped connection without properly leaving session!"); + // TODO: Start a timeout and if the peer doesn't come back, remove the peer + // and trigger "user left" callbacks. + // TODO: Maybe also check if a corresponding player is still in the game + // lobby. + } } SwarmEvent::IncomingConnectionError { connection_id, @@ -337,20 +544,34 @@ impl Plugin { Ok(()) } + pub(crate) fn register_mod(&mut self, name: &BStr, callbacks: ModCallbacks) { + self.mods.insert(name.to_owned(), callbacks); + } + pub(crate) fn create_rpc(&mut self, id: Identifier) { let rpc = RPC::new(); - self.rpcs.insert(id.to_topic(), rpc); + let topic = self.session.new_topic(id); + self.rpcs.insert(topic.clone(), rpc); } pub(crate) fn send_rpc(&self, id: Identifier, args: LuaValue<'_>) -> Result<()> { - if !self.rpcs.contains_key(&id.to_topic()) { + let Some(topic) = self.session.get_topic(id) else { + eyre::bail!("Topic for this RPC does not exist"); + }; + + if !self.rpcs.contains_key(topic) { eyre::bail!("RPC '{}' does not exist", id); } let args = bincode::encode_to_vec(args, bincode::config::standard()) .wrap_err("Failed to encode RPC args")?; - let msg = RPCMessage::new(id, args); + // TODO: Add metrics/profiling for size of the encoded args + + let msg = SwarmTask::Message { + topic: topic.clone(), + msg: SwarmMessage::Rpc(args), + }; self.send_tx .send(msg) .wrap_err("Failed to queue RPC call")?; @@ -358,24 +579,92 @@ impl Plugin { Ok(()) } - pub(crate) fn add_rpc_listener(&mut self, id: Identifier, fn_ref: i32) -> Result<()> { - let Some(rpc) = self.rpcs.get_mut(&id.to_topic()) else { + pub(crate) fn add_rpc_listener(&mut self, id: Identifier, fn_ref: LuaRef) -> Result<()> { + let topic = self.session.new_topic(id); + let Some(rpc) = self.rpcs.get_mut(topic) else { eyre::bail!("RPC '{}' does not exist", id); }; rpc.add_listener(fn_ref); + self.send_tx + .send(SwarmTask::Subscribe(topic.clone())) + .wrap_err("Failed to subscribe to RPC topic")?; Ok(()) } - pub(crate) fn add_connect_listener(&mut self, mod_name: &BStr, fn_ref: i32) { - let key = TopicHash::from_raw(mod_name.to_str_lossy()); - self.connect_listeners.insert(key, fn_ref); + pub(crate) fn join_session( + &mut self, + lua: &LuaState, + server_name: &BStr, + peer_id: &BStr, + player_id: &BStr, + ) -> Result<()> { + self.session.peer_id = peer_id.to_owned(); + self.session.address = format!("/{:08X}", hash(server_name)); + + let session_topic = self.session.new_topic("session").clone(); + + self.send_tx + .send(SwarmTask::Subscribe(session_topic.clone())) + .wrap_err("Failed to subscribe to session topic")?; + + // TODO: Is there a way to do this without the intermediate `Vec`? + // Probably not, since we cannot keep an immutable reference on `self.rpcs`, while + // also trying to get a mutable reference on `self` for `self.subscribe`. + let topics = self.rpcs.keys().cloned().collect::>(); + for topic in topics { + self.send_tx + .send(SwarmTask::Subscribe(topic.clone())) + .wrap_err_with(|| format!("Failed to subscribe to {}", topic))?; + } + + self.session.online = true; + + let msg = SwarmTask::Message { + topic: session_topic, + msg: SwarmMessage::SessionJoin { + player_id: player_id.to_vec(), + mods: self.mods.keys().map(|name| name.to_vec()).collect(), + }, + }; + self.send_tx + .send(msg) + .wrap_err("Failed to queue RPC call")?; + + // TODO: Do I want to wait for a reply or some sort of confirmation? + // Currently, we just assume this works always. + + for fn_ref in self.mods.values().filter_map(|cbs| cbs.on_session_joined) { + lua.pushnumber(fn_ref as f64); + lua.gettable(LUA_REGISTRYINDEX); + lua.pcall(0, 0) + .wrap_err("on_session_joined handler failed")?; + } + + Ok(()) } - pub(crate) fn add_disconnect_listener(&mut self, mod_name: &BStr, fn_ref: i32) { - let key = TopicHash::from_raw(mod_name.to_str_lossy()); - self.disconnect_listeners.insert(key, fn_ref); + pub(crate) fn leave_session(&mut self, lua: &LuaState) -> Result<()> { + if !self.session.online { + log::warn!("There is no session to leave"); + return Ok(()); + } + + let topics = mem::take(&mut self.session.topics); + self.send_tx + .send(SwarmTask::Unsubscribe(topics.into_values().collect())) + .wrap_err("Failed to queue unsubscribe task")?; + + self.session.online = false; + + for fn_ref in self.mods.values().filter_map(|cbs| cbs.on_session_left) { + lua.pushnumber(fn_ref as f64); + lua.gettable(LUA_REGISTRYINDEX); + lua.pcall(0, 0).wrap_err("on_session_left handler failed")?; + } + + Ok(()) } } @@ -384,3 +673,9 @@ impl std::fmt::Debug for Plugin { f.write_str("PluginApi") } } + +fn hash(val: impl AsRef<[u8]>) -> u64 { + let mut hasher = DefaultHasher::new(); + hasher.write(val.as_ref()); + hasher.finish() +} diff --git a/src/rpc.rs b/src/rpc.rs index eaff863..27a0995 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -1,8 +1,5 @@ use std::collections::HashSet; -use libp2p::gossipsub::TopicHash; - -use crate::plugin::Identifier; use crate::stingray_sdk::LuaRef; #[derive(Debug)] @@ -25,19 +22,3 @@ impl RPC { self.listeners.iter() } } - -#[derive(Debug)] -pub(crate) struct RPCMessage { - pub topic: TopicHash, - pub data: Vec, -} - -impl RPCMessage { - pub(crate) fn new(id: Identifier, data: impl Into>) -> Self { - let topic = id.to_topic(); - Self { - topic, - data: data.into(), - } - } -} diff --git a/src/stingray_sdk.rs b/src/stingray_sdk.rs index c310280..1143a73 100644 --- a/src/stingray_sdk.rs +++ b/src/stingray_sdk.rs @@ -208,6 +208,8 @@ pub type LuaRef = i32; pub struct LuaApi { add_module_function: unsafe extern "C" fn(*const c_char, *const c_char, lua_CFunction), createtable: unsafe extern "C" fn(*mut lua_State, i32, i32), + error: unsafe extern "C" fn(*mut lua_State) -> i32, + getscriptenvironmentstate: unsafe extern "C" fn() -> *mut lua_State, getfield: unsafe extern "C" fn(*mut lua_State, i32, *const c_char), gettable: unsafe extern "C" fn(*mut lua_State, i32), gettop: unsafe extern "C" fn(*mut lua_State) -> i32, @@ -248,6 +250,8 @@ impl LuaApi { Self { add_module_function: (*api).add_module_function.unwrap_unchecked(), createtable: (*api).createtable.unwrap_unchecked(), + error: (*api).error.unwrap_unchecked(), + getscriptenvironmentstate: (*api).getscriptenvironmentstate.unwrap_unchecked(), getfield: (*api).getfield.unwrap_unchecked(), gettable: (*api).gettable.unwrap_unchecked(), gettop: (*api).gettop.unwrap_unchecked(), @@ -289,6 +293,14 @@ impl LuaApi { (self.add_module_function)(module.as_ref().as_ptr(), name.as_ref().as_ptr(), Some(cb)) } } + + pub fn getscriptenvironmentstate(&self) -> *mut lua_State { + unsafe { (self.getscriptenvironmentstate)() } + } + + pub fn error(&self, l: *mut lua_State) { + unsafe { (self.error)(l) }; + } } /// A wrapper that combines a lua_State and a LuaApi to make calling functions more convenient. @@ -326,8 +338,7 @@ impl<'a> LuaState<'a> { } pub fn isfunction(&self, idx: i32) -> bool { - let is_fn = unsafe { (self.api.isfunction)(self.l, idx) }; - is_fn > 0 + matches!(self.r#type(idx), LuaType::Function) } pub fn istable(&self, idx: i32) -> bool { @@ -420,6 +431,10 @@ impl<'a> LuaState<'a> { eyre::bail!("pcall failed: {}", err) } + pub fn error(&self) { + self.api.error(self.l) + } + pub fn next(&self, idx: i32) -> i32 { unsafe { (self.api.next)(self.l, idx) } } @@ -445,6 +460,8 @@ impl<'a> LuaState<'a> { unsafe { (self.api.lib_error)(self.l, s.as_ptr()) } } + /// Creates and returns a reference, in the table at index t, for the object at the top of + /// the stack (and pops the object). pub fn lib_ref(&self, t: i32) -> LuaRef { unsafe { (self.api.lib_ref)(self.l, t) } } From bf376bb174f69cee91877085eac2f9cafd765360 Mon Sep 17 00:00:00 2001 From: Renovate Date: Sun, 8 Jun 2025 11:46:36 +0000 Subject: [PATCH 3/5] Update Rust crate bindgen to 0.72.0 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a571545..49fdb20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.71.1" +version = "0.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f" dependencies = [ "bitflags", "cexpr", diff --git a/Cargo.toml b/Cargo.toml index bd898ab..aea88a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ libc = "0.2.144" log = { version = "0.4.27", features = ["release_max_level_info"] } [build-dependencies] -bindgen = "0.71.0" +bindgen = "0.72.0" [lib] crate-type = ["cdylib", "lib"] From ae58bccedfe88206e52fc26edd34e944a1e1fc5e Mon Sep 17 00:00:00 2001 From: Renovate Date: Fri, 13 Jun 2025 17:46:39 +0000 Subject: [PATCH 4/5] Update Rust crate libc to v0.2.173 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49fdb20..7c05d18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "libloading" From bdd3f2e7d494e82703870367099ff1b36a2c4524 Mon Sep 17 00:00:00 2001 From: Renovate Date: Tue, 17 Jun 2025 18:01:27 +0000 Subject: [PATCH 5/5] Update Rust crate libc to v0.2.174 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c05d18..51360a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading"