diff --git a/Cargo.lock b/Cargo.lock index f4c552a5..7291d2ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,41 @@ 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.11" @@ -116,6 +151,51 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[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-scoped" version = "0.9.0" @@ -161,6 +241,29 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "aws-lc-rs" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -185,6 +288,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.7" @@ -203,26 +312,44 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bindgen" version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cexpr", "clang-sys", "itertools 0.12.1", "lazy_static", "lazycell", + "log", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash 1.1.0", "shlex", "syn", + "which", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.0" @@ -253,6 +380,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "borsh" version = "1.5.7" @@ -278,6 +414,12 @@ 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" @@ -362,6 +504,15 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.2.16" @@ -373,6 +524,18 @@ dependencies = [ "shlex", ] +[[package]] +name = "ccm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae3c82e4355234767756212c570e29833699ab63e6ffd161887314cc5b43847" +dependencies = [ + "aead", + "cipher", + "ctr", + "subtle", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -418,6 +581,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -472,6 +645,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "color-eyre" version = "0.6.3" @@ -549,6 +731,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -564,6 +756,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -585,7 +792,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags", + "bitflags 2.9.0", "crossterm_winapi", "futures-core", "mio", @@ -605,6 +812,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -612,9 +831,19 @@ 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" @@ -642,6 +871,12 @@ dependencies = [ "syn", ] +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + [[package]] name = "debug-ignore" version = "1.0.5" @@ -655,9 +890,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", + "pem-rfc7468", "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 = "derive-where" version = "1.2.7" @@ -689,7 +948,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "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]] @@ -710,6 +982,20 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -741,6 +1027,27 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enable-ansi-support" version = "0.2.1" @@ -797,6 +1104,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -861,6 +1178,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -976,6 +1299,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1005,6 +1329,16 @@ dependencies = [ "windows-targets 0.52.6", ] +[[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.28.1" @@ -1030,6 +1364,17 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "guppy" version = "0.17.17" @@ -1100,6 +1445,24 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[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 = "home" version = "0.5.11" @@ -1315,6 +1678,36 @@ dependencies = [ "web-time", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "interceptor" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ab04c530fd82e414e40394cabe5f0ebfe30d119f10fe29d6e3561926af412e" +dependencies = [ + "async-trait", + "bytes", + "log", + "portable-atomic", + "rand 0.8.5", + "rtcp", + "rtp", + "thiserror 1.0.69", + "tokio", + "waitgroup", + "webrtc-srtp", + "webrtc-util", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1410,7 +1803,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags", + "bitflags 2.9.0", "libc", "redox_syscall", ] @@ -1442,21 +1835,31 @@ dependencies = [ "anyhow", "async-trait", "bitvec", + "futures", + "futures-channel", "hex", "librqbit-utp", "num_enum", "rand 0.9.0", "reqwest", + "rustls", + "rustls-native-certs", + "rustls-pki-types", "serde", "serde_bencode", + "serde_json", "serde_qs", "serde_repr", "sha1", "thiserror 2.0.12", "tokio", + "tokio-rustls", "tokio-stream", + "tokio-tungstenite", "tracing", "tracing-test", + "webpki-roots", + "webrtc", ] [[package]] @@ -1496,12 +1899,31 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "miette" version = "7.5.0" @@ -1612,7 +2034,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -1646,7 +2068,7 @@ dependencies = [ "recursion", "regex", "regex-syntax 0.8.5", - "smol_str", + "smol_str 0.3.2", "thiserror 2.0.12", "winnow", ] @@ -1661,7 +2083,7 @@ dependencies = [ "nextest-workspace-hack", "serde", "serde_json", - "smol_str", + "smol_str 0.3.2", "target-spec", ] @@ -1706,7 +2128,7 @@ dependencies = [ "nextest-filtering", "nextest-metadata", "nextest-workspace-hack", - "nix", + "nix 0.29.0", "owo-colors 4.2.0", "pin-project-lite", "quick-junit", @@ -1721,7 +2143,7 @@ dependencies = [ "sha2", "shell-words", "smallvec", - "smol_str", + "smol_str 0.3.2", "strip-ansi-escapes", "supports-unicode", "swrite", @@ -1748,13 +2170,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d906846a98739ed9d73d66e62c2641eef8321f1734b7a1156ab045a0248fb2b3" +[[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", + "memoffset", + "pin-utils", +] + [[package]] name = "nix" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cfg-if", "cfg_aliases", "libc", @@ -1780,6 +2215,31 @@ dependencies = [ "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" @@ -1825,19 +2285,34 @@ 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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cfg-if", "foreign-types", "libc", @@ -1903,6 +2378,30 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1935,6 +2434,25 @@ dependencies = [ "camino", ] +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1999,12 +2517,30 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[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 = "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" @@ -2014,6 +2550,25 @@ dependencies = [ "zerocopy 0.8.23", ] +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.3.0" @@ -2185,6 +2740,20 @@ dependencies = [ "getrandom 0.3.1", ] +[[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", + "x509-parser", + "yasna", +] + [[package]] name = "recursion" version = "0.5.2" @@ -2197,7 +2766,7 @@ version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags", + "bitflags 2.9.0", ] [[package]] @@ -2294,6 +2863,16 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.14" @@ -2325,12 +2904,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags", + "bitflags 2.9.0", "indexmap", "serde", "serde_derive", ] +[[package]] +name = "rtcp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8306430fb118b7834bbee50e744dc34826eca1da2158657a3d6cbc70e24c2096" +dependencies = [ + "bytes", + "thiserror 1.0.69", + "webrtc-util", +] + +[[package]] +name = "rtp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68baca5b6cb4980678713f0d06ef3a432aa642baefcbfd0f4dd2ef9eb5ab550" +dependencies = [ + "bytes", + "memchr", + "portable-atomic", + "rand 0.8.5", + "serde", + "thiserror 1.0.69", + "webrtc-util", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2358,13 +2963,22 @@ 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", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2377,7 +2991,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" dependencies = [ - "bitflags", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys 0.9.2", @@ -2386,10 +3000,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.23" +version = "0.23.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" dependencies = [ + "aws-lc-rs", + "log", "once_cell", "ring", "rustls-pki-types", @@ -2398,6 +3014,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -2418,10 +3046,11 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -2454,14 +3083,53 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sdp" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a526161f474ae94b966ba622379d939a8fe46c930eebbadb73e339622599d5" +dependencies = [ + "rand 0.8.5", + "substring", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", - "core-foundation", + "bitflags 2.9.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -2742,6 +3410,15 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + [[package]] name = "smol_str" version = "0.3.2" @@ -2793,6 +3470,34 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "stun" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea256fb46a13f9204e9dee9982997b2c3097db175a9fddaa8350310d03c4d5a3" +dependencies = [ + "base64 0.22.1", + "crc", + "lazy_static", + "md-5", + "rand 0.8.5", + "ring", + "subtle", + "thiserror 1.0.69", + "tokio", + "url", + "webrtc-util", +] + +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "subtle" version = "2.6.1" @@ -2846,14 +3551,25 @@ dependencies = [ "futures-core", ] +[[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", - "core-foundation", + "bitflags 2.9.0", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2998,6 +3714,37 @@ dependencies = [ "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 = "tinyvec" version = "1.9.0" @@ -3073,6 +3820,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +dependencies = [ + "futures-util", + "log", + "native-tls", + "tokio", + "tokio-native-tls", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.13" @@ -3255,6 +4016,45 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "native-tls", + "rand 0.9.0", + "sha1", + "thiserror 2.0.12", + "utf-8", +] + +[[package]] +name = "turn" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0044fdae001dd8a1e247ea6289abf12f4fcea1331a2364da512f9cd680bbd8cb" +dependencies = [ + "async-trait", + "base64 0.22.1", + "futures", + "log", + "md-5", + "portable-atomic", + "rand 0.8.5", + "ring", + "stun", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "webrtc-util", +] + [[package]] name = "typenum" version = "1.18.0" @@ -3300,6 +4100,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +[[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 = "untrusted" version = "0.9.0" @@ -3323,6 +4133,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3371,6 +4187,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "waitgroup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" +dependencies = [ + "atomic-waker", +] + [[package]] name = "want" version = "0.3.1" @@ -3495,6 +4320,227 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webrtc" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30367074d9f18231d28a74fab0120856b2b665da108d71a12beab7185a36f97b" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "cfg-if", + "hex", + "interceptor", + "lazy_static", + "log", + "portable-atomic", + "rand 0.8.5", + "rcgen", + "regex", + "ring", + "rtcp", + "rtp", + "rustls", + "sdp", + "serde", + "serde_json", + "sha2", + "smol_str 0.2.2", + "stun", + "thiserror 1.0.69", + "time", + "tokio", + "turn", + "url", + "waitgroup", + "webrtc-data", + "webrtc-dtls", + "webrtc-ice", + "webrtc-mdns", + "webrtc-media", + "webrtc-sctp", + "webrtc-srtp", + "webrtc-util", +] + +[[package]] +name = "webrtc-data" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec93b991efcd01b73c5b3503fa8adba159d069abe5785c988ebe14fcf8f05d1" +dependencies = [ + "bytes", + "log", + "portable-atomic", + "thiserror 1.0.69", + "tokio", + "webrtc-sctp", + "webrtc-util", +] + +[[package]] +name = "webrtc-dtls" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c9b89fc909f9da0499283b1112cd98f72fec28e55a54a9e352525ca65cd95c" +dependencies = [ + "aes", + "aes-gcm", + "async-trait", + "bincode", + "byteorder", + "cbc", + "ccm", + "der-parser", + "hkdf", + "hmac", + "log", + "p256", + "p384", + "portable-atomic", + "rand 0.8.5", + "rand_core 0.6.4", + "rcgen", + "ring", + "rustls", + "sec1", + "serde", + "sha1", + "sha2", + "subtle", + "thiserror 1.0.69", + "tokio", + "webrtc-util", + "x25519-dalek", + "x509-parser", +] + +[[package]] +name = "webrtc-ice" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348b28b593f7709ac98d872beb58c0009523df652c78e01b950ab9c537ff17d" +dependencies = [ + "arc-swap", + "async-trait", + "crc", + "log", + "portable-atomic", + "rand 0.8.5", + "serde", + "serde_json", + "stun", + "thiserror 1.0.69", + "tokio", + "turn", + "url", + "uuid", + "waitgroup", + "webrtc-mdns", + "webrtc-util", +] + +[[package]] +name = "webrtc-mdns" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6dfe9686c6c9c51428da4de415cb6ca2dc0591ce2b63212e23fd9cccf0e316b" +dependencies = [ + "log", + "socket2", + "thiserror 1.0.69", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-media" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e153be16b8650021ad3e9e49ab6e5fa9fb7f6d1c23c213fd8bbd1a1135a4c704" +dependencies = [ + "byteorder", + "bytes", + "rand 0.8.5", + "rtp", + "thiserror 1.0.69", +] + +[[package]] +name = "webrtc-sctp" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5faf3846ec4b7e64b56338d62cbafe084aa79806b0379dff5cc74a8b7a2b3063" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "portable-atomic", + "rand 0.8.5", + "thiserror 1.0.69", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-srtp" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771db9993712a8fb3886d5be4613ebf27250ef422bd4071988bf55f1ed1a64fa" +dependencies = [ + "aead", + "aes", + "aes-gcm", + "byteorder", + "bytes", + "ctr", + "hmac", + "log", + "rtcp", + "rtp", + "sha1", + "subtle", + "thiserror 1.0.69", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-util" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1438a8fd0d69c5775afb4a71470af92242dbd04059c61895163aa3c1ef933375" +dependencies = [ + "async-trait", + "bitflags 1.3.2", + "bytes", + "ipnet", + "lazy_static", + "libc", + "log", + "nix 0.26.4", + "portable-atomic", + "rand 0.8.5", + "thiserror 1.0.69", + "tokio", + "winapi", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + [[package]] name = "win32job" version = "2.0.2" @@ -3844,7 +4890,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "bitflags", + "bitflags 2.9.0", ] [[package]] @@ -3856,6 +4902,36 @@ dependencies = [ "tap", ] +[[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", + "ring", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + [[package]] name = "xattr" version = "1.5.0" @@ -3872,6 +4948,15 @@ version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -3917,6 +5002,20 @@ 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 = "zipsign-api" diff --git a/README.md b/README.md index abd5f3b3..65d85990 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,18 @@ We plan to support: - uTP peer connections - TCP peer connections -- Webtorrent (WSS) peer connections +- WebTorrent (WebRTC) peer connections We currently support: - Handling Magnet URIs - Handling Torrent files +- uTP peer handshakes +- TCP peer handshakes We are currently working on (this may be a little bit out of date, feel free to ask/open an issue): -- uTP peer connections -- TCP peer connections +- Webtorrent (WebRTC) peer handshakes/initial connections ## Testing @@ -32,6 +33,14 @@ We use [Nextest](https://nexte.st/) for testing. You may have to install Nextest Please keep in mind that as of April 6th, 2025, this library is not complete. +### A few notes about WebSocket (WS) trackers + +Generally speaking, this project refers to WebSockets as WSS (Web Sockets Secured), not WS. Consequently, you'll see files/structs/etc. with names such as `wss.rs`, `WssTracker`, and so on. Keep in mind that these files/structs/etc. refer to both secure and unsecured WebSockets. + +Additionally, WebSocket peers/trackers act in a very different manner in comparison to HTTPS/UDP peers/trackers. The general workflow for this process can be found in this very helpful diagram posted by [Akshat Schan on LinkedIn.](https://www.linkedin.com/pulse/edition-2-diving-deep-webrtc-webtorrent-p2p-streaming-akshat-sachan-bbtrc/) + +![Diagram of WSS peers/trackers](https://media.licdn.com/dms/image/v2/D5612AQG1-HvLrx6lAQ/article-inline_image-shrink_1000_1488/B56ZYjsOvSGUAY-/0/1744355520685?e=1752710400&v=beta&t=y9C53nrL8sl5aTjmhSdj20_8idD0PEzBMkhLiJGhvCE) + ### Handshaking with peers #### uTP diff --git a/crates/libtortillas/Cargo.toml b/crates/libtortillas/Cargo.toml index f9a108c2..8ae3310f 100644 --- a/crates/libtortillas/Cargo.toml +++ b/crates/libtortillas/Cargo.toml @@ -4,12 +4,13 @@ version = "0.0.0" edition = "2024" [dependencies] +serde_json = "1.0" tokio = { version = "1", features = ["full"] } anyhow = "1.0" serde_bencode = "^0.2.4" serde = { version = "1.0", features = ["derive"] } serde_qs = "0.14.0" -sha1 = "0.10.6" +sha1 = {version = "0.10.6" } hex = "0.4.3" reqwest = "0.12.13" serde_repr = "0.1.20" @@ -21,6 +22,24 @@ tracing = "0.1.41" async-trait = "0.1.88" librqbit-utp = "0.2.3" bitvec = "1.0.1" +webrtc = "0.12.0" +tokio-tungstenite = {version = "0.26.2", features=["native-tls"]} +rustls = { version = "0.23.26" } +tokio-rustls = "0.26.2" +futures = "0.3.31" +futures-channel = "0.3.31" + +[dependencies.rustls-native-certs] +optional = true +version = "0.8.0" + +[dependencies.webpki-roots] +optional = true +version = "0.26.0" + +[dependencies.rustls-pki-types] +optional = true +version = "1.0" [dev-dependencies] tracing-test = "0.2.5" diff --git a/crates/libtortillas/src/peers/mod.rs b/crates/libtortillas/src/peers/mod.rs index 13e301c9..08b2ce31 100644 --- a/crates/libtortillas/src/peers/mod.rs +++ b/crates/libtortillas/src/peers/mod.rs @@ -22,6 +22,7 @@ pub mod messages; pub mod tcp; mod transport_messages; pub mod utp; +pub mod webrtc; pub type PeerKey = SocketAddr; /// Represents a BitTorrent peer with connection state and statistics diff --git a/crates/libtortillas/src/peers/utp.rs b/crates/libtortillas/src/peers/utp.rs index 47c90bb3..e1799419 100644 --- a/crates/libtortillas/src/peers/utp.rs +++ b/crates/libtortillas/src/peers/utp.rs @@ -14,7 +14,7 @@ use tokio::{ sync::Mutex, time::Instant, }; -use tracing::{debug, error, info, instrument, trace}; +use tracing::{debug, error, info, trace}; #[derive(Clone)] pub struct UtpProtocol { diff --git a/crates/libtortillas/src/peers/webrtc.rs b/crates/libtortillas/src/peers/webrtc.rs new file mode 100644 index 00000000..acfbc20f --- /dev/null +++ b/crates/libtortillas/src/peers/webrtc.rs @@ -0,0 +1,125 @@ +use anyhow::Result; +use async_trait::async_trait; +use std::{collections::HashMap, net::IpAddr, str::FromStr, sync::Arc}; +use tokio::sync::Mutex; +use webrtc::{ + api::{ + interceptor_registry::register_default_interceptors, media_engine::MediaEngine, APIBuilder, + }, + data_channel::RTCDataChannel, + ice_transport::ice_server::RTCIceServer, + interceptor::registry::Registry, + peer_connection::{ + configuration::RTCConfiguration, offer_answer_options::RTCOfferOptions, RTCPeerConnection, + }, +}; + +use crate::{ + errors::PeerTransportError, + hashes::{Hash, InfoHash}, +}; + +use super::{Peer, PeerKey, TransportProtocol}; + +#[derive(Clone)] +pub struct WebRTCProtocol { + pub connection: Arc, + pub peers: HashMap>>, +} + +impl WebRTCProtocol { + pub async fn new() -> Self { + let mut m = MediaEngine::default(); + + // Register default codecs + m.register_default_codecs().unwrap(); + + // Create a InterceptorRegistry. This is the user configurable RTP/RTCP Pipeline. + // This provides NACKs, RTCP Reports and other features. If you use `webrtc.NewPeerConnection` + // this is enabled by default. If you are manually managing You MUST create a InterceptorRegistry + // for each PeerConnection. + let mut registry = Registry::new(); + + // Use the default set of Interceptors + registry = register_default_interceptors(registry, &mut m).unwrap(); + + // Create the API object with the MediaEngine + let api = APIBuilder::new() + .with_media_engine(m) + .with_interceptor_registry(registry) + .build(); + + let config = RTCConfiguration { + ice_servers: vec![RTCIceServer { + urls: vec!["stun:stun.l.google.com:19302".to_owned()], + ..Default::default() + }], + ..Default::default() + }; + let peer_connection = Arc::new(api.new_peer_connection(config).await.unwrap()); + WebRTCProtocol { + connection: peer_connection, + peers: HashMap::new(), + } + } +} + +#[async_trait] +#[allow(unused_variables)] +impl TransportProtocol for WebRTCProtocol { + /// Some helpful information: + /// + /// + async fn connect_peer( + &mut self, + peer: &mut Peer, + id: Arc>, + info_hash: Arc, + ) -> Result { + // let options = Some(RTCDataChannelInit { + // ordered: Some(true), + // ..Default::default() + // }); + // let data_channel = self + // .connection + // .create_data_channel("data", options) + // .await + // .map_err(|e| error!("Failed to create data channel!")) + // .unwrap(); + + // let offer_options = Some(RTCOfferOptions { + // voice_activity_detection: false, + // ice_restart: true, + // }); + // + // let sdp_description = self.connection.create_offer(offer_options).await.unwrap(); + // self + // .connection + // .set_local_description(sdp_description) + // .await + // .unwrap(); + Ok(PeerKey::new(IpAddr::from_str("192.168.1.1").unwrap(), 1234)) + } + async fn send_data(&mut self, to: PeerKey, data: Vec) -> Result<(), PeerTransportError> { + Ok(()) + } + async fn receive_data( + &mut self, + info_hash: Arc, + id: Arc>, + ) -> Result<(PeerKey, Vec), PeerTransportError> { + Ok(( + PeerKey::new(IpAddr::from_str("192.168.1.0").unwrap(), 1234), + vec![0], + )) + } + fn close_connection(&mut self, peer_key: PeerKey) -> Result<()> { + Ok(()) + } + fn is_peer_connected(&self, peer_key: PeerKey) -> bool { + true + } + async fn get_connected_peer(&self, peer_key: PeerKey) -> Option { + Some(Peer::new(IpAddr::from_str("192.168.1.0").unwrap(), 1234)) + } +} diff --git a/crates/libtortillas/src/tracker/http.rs b/crates/libtortillas/src/tracker/http.rs index 95d2d350..7fde0aa7 100644 --- a/crates/libtortillas/src/tracker/http.rs +++ b/crates/libtortillas/src/tracker/http.rs @@ -1,68 +1,27 @@ /// See https://www.bittorrent.org/beps/bep_0003.html -use super::{Peer, TrackerTrait}; +use super::{Peer, TrackerRequest, TrackerTrait}; use crate::{ errors::{HttpTrackerError, TrackerError}, hashes::{Hash, InfoHash}, + tracker::urlencode, }; use anyhow::Result; use async_trait::async_trait; use serde::{ - Deserialize, Serialize, de::{self, Visitor}, + Deserialize, Serialize, }; -use std::{ - net::{Ipv4Addr, SocketAddr}, - str::FromStr, - time::Duration, -}; -use tokio::{sync::mpsc, time::sleep}; +use std::net::{Ipv4Addr, SocketAddr}; use tracing::{debug, error, info, instrument, trace, warn}; #[derive(Debug, Deserialize)] -#[allow(dead_code)] // REMOVE SOON pub struct TrackerResponse { pub interval: usize, #[serde(deserialize_with = "deserialize_peers")] pub peers: Vec, } -/// Event. See @ trackers -#[derive(Clone, Debug, Deserialize, Serialize)] -pub enum Event { - Started, - Completed, - Stopped, - Empty, -} - -/// Tracker request. See @ trackers -#[derive(Clone, Debug, Deserialize, Serialize)] -struct TrackerRequest { - ip: Option, - port: u16, - uploaded: u8, - downloaded: u8, - left: Option, - event: Event, - peer_tracker_addr: SocketAddr, -} - -impl TrackerRequest { - pub fn new(peer_tracker_addr: Option) -> TrackerRequest { - TrackerRequest { - ip: None, - port: 6881, - uploaded: 0, - downloaded: 0, - left: None, - event: Event::Stopped, - peer_tracker_addr: peer_tracker_addr - .unwrap_or(SocketAddr::from_str("0.0.0.0:6881").unwrap()), - } - } -} - /// Struct for handling tracker over HTTP /// Interval is set to `u32::MAX` by default. #[derive(Clone, Debug, Deserialize, Serialize)] @@ -96,47 +55,11 @@ impl HttpTracker { } } -fn urlencode(t: &[u8; 20]) -> String { - let mut encoded = String::with_capacity(3 * t.len()); - - for &byte in t { - encoded.push('%'); - - let byte = hex::encode([byte]); - encoded.push_str(&byte); - } - - encoded -} - /// Fetches peers from tracker over HTTP and returns a stream of [Peers](Peer) #[async_trait] impl TrackerTrait for HttpTracker { - async fn stream_peers(&mut self) -> Result>> { - let (tx, rx) = mpsc::channel(100); - let mut tracker = self.clone(); - let tx = tx.clone(); - // no pre‑captured interval – always read the latest value - tokio::spawn(async move { - loop { - let peers = tracker.get_peers().await.unwrap(); - trace!( - "Successfully made request to get peers: {}", - peers.last().unwrap() - ); - - // stop gracefully if the receiver was dropped - if tx.send(peers).await.is_err() { - warn!("Receiver dropped – stopping peer stream"); - break; - } - - // pick up possibly updated interval (never sleep 0s) - let delay = tracker.interval.max(1); - sleep(Duration::from_secs(delay as u64)).await; - } - }); - Ok(rx) + fn get_interval(&self) -> u32 { + self.interval } #[instrument(skip(self))] diff --git a/crates/libtortillas/src/tracker/mod.rs b/crates/libtortillas/src/tracker/mod.rs index bc2e8f9c..c3804e3e 100644 --- a/crates/libtortillas/src/tracker/mod.rs +++ b/crates/libtortillas/src/tracker/mod.rs @@ -1,27 +1,162 @@ use anyhow::Result; use async_trait::async_trait; +use core::str; +use hex::FromHex; use http::HttpTracker; use rand::random_range; use serde::{ - Deserialize, de::{self, Visitor}, + Deserialize, Serialize, }; -use std::{fmt, net::SocketAddr}; -use tokio::sync::mpsc; +use std::{ + fmt, + net::{Ipv4Addr, SocketAddr}, + str::FromStr, + time::Duration, +}; +use tokio::{sync::mpsc, time::sleep}; +use tracing::{trace, warn}; use udp::UdpTracker; +use wss::WssTracker; -use crate::{hashes::InfoHash, peers::Peer}; +use crate::{ + hashes::{Hash, InfoHash}, + peers::Peer, +}; pub mod http; pub mod udp; +pub mod wss; + +// This is AI generated. But it works. +fn hash_to_byte_string(hex_str: &str) -> String { + // 1) decode hex → raw bytes + let bytes = Vec::from_hex(hex_str).expect("invalid hex input"); + + // 2) build the escaped string + let mut out = String::new(); + for &b in &bytes { + match b { + // common C-style escapes + 0x00 => out.push_str(r"\0"), + 0x07 => out.push_str(r"\a"), + 0x08 => out.push_str(r"\b"), + 0x09 => out.push_str(r"\t"), + 0x0A => out.push_str(r"\n"), + 0x0B => out.push_str(r"\v"), + 0x0C => out.push_str(r"\f"), + 0x0D => out.push_str(r"\r"), + + // any other C0 control → \u00XX + 0x01..=0x06 | 0x0E..=0x1F => { + out.push_str(&format!(r"\u{:04x}", b)); + } + + // printable ASCII + 0x20..=0x7E => { + out.push(b as char); + } + + // high-bit set → ISO-8859-1 codepoint + _ => { + let ch = char::from_u32(b as u32).expect("byte → char failed"); + out.push(ch); + } + } + } + + out +} + +fn urlencode(t: &[u8; 20]) -> String { + let mut encoded = String::with_capacity(3 * t.len()); + + for &byte in t { + encoded.push('%'); + + let byte = hex::encode([byte]); + encoded.push_str(&byte); + } + + encoded +} #[async_trait] -pub trait TrackerTrait: Clone { +pub trait TrackerTrait: Clone + 'static { /// Acts as a wrapper function for get_peers. Should be spawned with tokio::spawn. - async fn stream_peers(&mut self) -> Result>>; + async fn stream_peers(&mut self) -> Result>> { + let (tx, rx) = mpsc::channel(100); + + // Not *super* cheap clone, but not awful + let mut tracker = self.clone(); + // Very cheap clone + let interval = self.get_interval(); + + let tx = tx.clone(); + // no pre‑captured interval – always read the latest value + tokio::spawn(async move { + loop { + let peers = tracker.get_peers().await.unwrap(); + trace!( + "Successfully made request to get peers: {}", + peers.last().unwrap() + ); + + // stop gracefully if the receiver was dropped + if tx.send(peers).await.is_err() { + warn!("Receiver dropped – stopping peer stream"); + break; + } + + // pick up possibly updated interval (never sleep 0s) + let delay = interval.max(1); + sleep(Duration::from_secs(delay as u64)).await; + } + }); + Ok(rx) + } + + fn get_interval(&self) -> u32; async fn get_peers(&mut self) -> Result>; } +/// Event. See @ trackers +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Event { + Started, + Completed, + Stopped, + Empty, +} + +/// Tracker request. See @ trackers +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct TrackerRequest { + ip: Option, + port: u16, + uploaded: u8, + downloaded: u8, + left: Option, + event: Event, + peer_tracker_addr: SocketAddr, +} + +impl TrackerRequest { + pub fn new(peer_tracker_addr: Option) -> TrackerRequest { + TrackerRequest { + ip: None, + port: 6881, + uploaded: 0, + downloaded: 0, + left: None, + event: Event::Stopped, + peer_tracker_addr: peer_tracker_addr + .unwrap_or(SocketAddr::from_str("0.0.0.0:6881").unwrap()), + } + } +} + /// An Announce URI from a torrent file or magnet URI. /// /// Example: @@ -57,7 +192,16 @@ impl Tracker { Ok(tracker.get_peers().await.unwrap()) } - Tracker::Websocket(_) => todo!(), + Tracker::Websocket(uri) => { + let port: u16 = random_range(1024..65535); + let mut tracker = WssTracker::new( + uri.clone(), + info_hash, + Some(SocketAddr::from(([0, 0, 0, 0], port))), + ) + .await; + Ok(tracker.get_peers().await.unwrap()) + } } } diff --git a/crates/libtortillas/src/tracker/udp.rs b/crates/libtortillas/src/tracker/udp.rs index 12f15b38..f9c17bbe 100644 --- a/crates/libtortillas/src/tracker/udp.rs +++ b/crates/libtortillas/src/tracker/udp.rs @@ -492,6 +492,10 @@ impl UdpTracker { #[async_trait] impl TrackerTrait for UdpTracker { + fn get_interval(&self) -> u32 { + self.interval + } + async fn stream_peers(&mut self) -> anyhow::Result>> { let (tx, rx) = mpsc::channel(100); diff --git a/crates/libtortillas/src/tracker/wss.rs b/crates/libtortillas/src/tracker/wss.rs new file mode 100644 index 00000000..006c7a61 --- /dev/null +++ b/crates/libtortillas/src/tracker/wss.rs @@ -0,0 +1,348 @@ +use std::net::SocketAddr; +use std::sync::Arc; +use std::time::UNIX_EPOCH; + +use anyhow::Result; +use async_trait::async_trait; +use futures::stream::{SplitSink, SplitStream, StreamExt}; +use futures::SinkExt; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tokio::net::TcpStream; +use tokio::sync::Mutex; +use tokio_tungstenite::tungstenite::Message; +use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; +use tracing::{debug, error, trace}; +use webrtc::sdp::description::media::{MediaName, RangedPort}; +use webrtc::sdp::description::session::Origin; +use webrtc::sdp::{MediaDescription, SessionDescription}; + +use crate::hashes::Hash; +use crate::tracker::{hash_to_byte_string, Event}; +use crate::{hashes::InfoHash, peers::Peer}; + +use super::{TrackerRequest, TrackerTrait}; + +/// Tracker for websockets +#[derive(Clone)] +pub struct WssTracker { + info_hash: InfoHash, + params: TrackerRequest, + peer_id: Hash<20>, + interval: u32, + write: Arc>, Message>>>, + read: Arc>>>>, +} + +/// This is primarily used for serializing offers. Try torrenting a file with +/// and check out how the offers are "shaped" in the network tab. +#[derive(Serialize, Deserialize)] +struct WssOffer { + #[serde(rename = "type")] + offer_type: String, + sdp: String, +} + +impl WssOffer { + pub fn new(sdp: String) -> Self { + WssOffer { + offer_type: "offer".into(), + sdp, + } + } +} + +/// Again, please try torrenting using a site like and examine +/// the format that offers are sent in. We need to serialize offers in a format like this: +/// [ +/// { +/// "offer": { +/// ... +/// } +/// "offer_id": ... +/// } +/// { +/// "offer": { +/// ... +/// } +/// "offer_id": ... +/// } +/// ] +/// Hence, the easiest thing to do is use a wrapper. +#[derive(Serialize, Deserialize)] +struct WssOfferWrapper { + offer: WssOffer, + offer_id: String, +} + +impl WssOfferWrapper { + pub fn new(sdp: String) -> Self { + let mut offer_id_bytes = [0u8; 20]; + rand::fill(&mut offer_id_bytes); + let offer_id = Hash::new(offer_id_bytes); + WssOfferWrapper { + offer: WssOffer::new(sdp), + offer_id: hash_to_byte_string(&offer_id.to_string()), + } + } +} + +impl WssTracker { + pub async fn new( + uri: String, + info_hash: InfoHash, + peer_tracker_addr: Option, + ) -> Self { + let mut peer_id_bytes = [0u8; 20]; + rand::fill(&mut peer_id_bytes); + let peer_id = Hash::new(peer_id_bytes); + debug!(peer_id = %peer_id, "Generated peer ID"); + + trace!("Attemping connection to WSS tracker: {}", uri); + + let (stream, _) = connect_async(&uri) + .await + .map_err(|e| { + error!("Error connecting to peer: {}", e); + }) + .unwrap(); + let (write, read) = stream.split(); + let arc_write = Arc::new(Mutex::new(write)); + let arc_read = Arc::new(Mutex::new(read)); + trace!("Connected to WSS tracker at {}", uri); + + WssTracker { + info_hash, + params: TrackerRequest::new(peer_tracker_addr), + peer_id, + interval: u32::MAX, + write: arc_write, + read: arc_read, + } + } + + /// Prototype. Headers will be changed. + pub async fn recv_peers(&mut self) -> bool { + true + } +} + +#[async_trait] +impl TrackerTrait for WssTracker { + /// It should be noted that WebSockets are intended to communicate in JSON. (This makes our + /// lives very easy though) + /// + /// This does not initially return a list of peers, so to speak. Instead, it sends an SDP offer + /// to the tracker, and the tracker forwards that SDP offer to relevant peers. Those peers then + /// return an SDP answer to the tracker, which forwards the answer to us. + async fn get_peers(&mut self) -> Result> { + self.params.event = Event::Started; + let mut tracker_request_as_json = serde_json::to_string(&self.params).unwrap(); + trace!("Generated request parameters"); + + // Generate offers + let numwant = 1; + + let mut offers = vec![]; + let timestamp = UNIX_EPOCH.elapsed()?.as_secs(); + + // SDP Offer + // FIXME: Should unicast address actually be 0.0.0.0? All of WebTorrent's offers/answers are + // 0.0.0.0 or 127.0.0.1 + // FIXME: media_name port? + let sdp_offer = SessionDescription { + version: 0, + origin: Origin { + username: "-".to_string(), + session_id: timestamp, + session_version: timestamp, + network_type: "IN".to_string(), + address_type: "IP4".to_string(), + unicast_address: "0.0.0.0".to_string(), + }, + session_name: "SDP offer from WebTorrent peer".to_string(), + session_information: None, + uri: None, + email_address: None, + phone_number: None, + connection_information: None, + bandwidth: vec![], + time_descriptions: vec![], + time_zones: vec![], + encryption_key: None, + attributes: vec![], + media_descriptions: vec![MediaDescription { + media_name: MediaName { + media: "application".to_string(), + port: RangedPort { + value: 27764, + range: None, + }, + protos: vec!["UDP".to_string(), "DTLS".to_string(), "SCTP".to_string()], + formats: vec!["webrtc-datachannel".to_string()], + }, + media_title: None, + connection_information: None, + bandwidth: vec![], + encryption_key: None, + attributes: vec![], + }], + }; + let raw_sdp_offer = sdp_offer.marshal(); + + for _i in 0..numwant { + let offer = WssOfferWrapper::new(raw_sdp_offer.clone()); + offers.push(offer); + } + + // {tracker_request_as_json,info_hash:"xyz",peer_id:"abc",action:"announce",numwant:5,offers:{...}} + tracker_request_as_json.pop(); + let request = format!( + "{},\"info_hash\":\"{}\",\"peer_id\":\"{}\",\"action\":\"announce\",\"numwant\":{}, \"offers\": {} }}", + tracker_request_as_json, + hash_to_byte_string(&self.info_hash.to_string()), + hash_to_byte_string(&self.peer_id.to_string()), + numwant, + serde_json::to_string(&offers)? + ); + + trace!("Request json generated: {}", request); + let message = Message::from(request); + + trace!("Sending message to tracker"); + self + .write + .lock() + .await + .send(message) + .await + .map_err(|e| { + error!("Error sending message: {e}"); + }) + .unwrap(); + self + .write + .lock() + .await + .flush() + .await + .map_err(|e| { + error!("Error sending message: {e}"); + }) + .unwrap(); + + trace!("Recieving message from tracker"); + + // This section of code is completely and utterly scuffed. self.read.collect() refuses to + // work, so this is what we're stuck with for now. + let output = self + .read + .lock() + .await + .next() + .await + .unwrap() + .unwrap() + .into_text() + .unwrap() + .to_string(); + + trace!("Message recieved: {}", output); + + // Output should look something like this: + // {"complete":0,"incomplete":0,"action":"announce","interval":120,"info_hash":"myhash"} + let res_json: Value = serde_json::from_str(&output).unwrap(); + + // Check for "failure_reason" key (response failed) + let res_json = res_json.as_object().unwrap(); + if res_json.contains_key("failure reason") { + panic!("Error: {}", res_json.get("failure reason").unwrap()); + } + + self.interval = res_json.get("interval").unwrap().as_u64().unwrap() as u32; + + let answers = self + .read + .lock() + .await + .next() + .await + .unwrap() + .unwrap() + .into_text() + .unwrap() + .to_string(); + + let res: Vec = vec![]; + Ok(res) + } + + fn get_interval(&self) -> u32 { + self.interval + } +} + +#[cfg(test)] +mod tests { + + use crate::{parser::TorrentFile, tracker::TrackerTrait}; + use tracing_test::traced_test; + + use crate::{parser::MetaInfo, tracker::wss::WssTracker}; + + #[tokio::test] + #[traced_test] + async fn test_get_peers_with_wss_tracker() { + let path = std::env::current_dir() + .unwrap() + .join("tests/torrents/sintel.torrent"); + + let metainfo = TorrentFile::parse(path).await.unwrap(); + match metainfo { + MetaInfo::Torrent(torrent) => { + let info_hash = torrent.info.hash(); + let uri = "wss://tracker.btorrent.xyz".into(); + + let mut wss_tracker = WssTracker::new(uri, info_hash.unwrap(), None).await; + + // Spawn a task to re-fetch the latest list of peers at a given interval + let mut rx = wss_tracker.stream_peers().await.unwrap(); + + let peers = rx.recv().await.unwrap(); + + let peer = &peers[0]; + assert!(peer.ip.is_ipv4()); + } + _ => panic!("Expected Torrent"), + } + } + + #[tokio::test] + #[traced_test] + async fn test_get_peers_with_ws_tracker() { + let path = std::env::current_dir() + .unwrap() + .join("tests/torrents/big-buck-bunny.torrent"); + + let metainfo = TorrentFile::parse(path).await.unwrap(); + match metainfo { + MetaInfo::Torrent(torrent) => { + let info_hash = torrent.info.hash(); + // From https://github.com/ngosang/trackerslist/blob/master/trackers_all_ws.txt. May + // not be consistently present, as this repo is automatically updated/changed + let uri = "ws://tracker.files.fm:7072/announce".into(); + + let mut wss_tracker = WssTracker::new(uri, info_hash.unwrap(), None).await; + + // Spawn a task to re-fetch the latest list of peers at a given interval + let mut rx = wss_tracker.stream_peers().await.unwrap(); + + let peers = rx.recv().await.unwrap(); + + let peer = &peers[0]; + assert!(peer.ip.is_ipv4()); + } + _ => panic!("Expected Torrent"), + } + } +} diff --git a/crates/libtortillas/tests/torrents/sintel.torrent b/crates/libtortillas/tests/torrents/sintel.torrent new file mode 100644 index 00000000..c3775deb Binary files /dev/null and b/crates/libtortillas/tests/torrents/sintel.torrent differ