add autoreconnect, wisp_mux 1.2.0

This commit is contained in:
Toshit Chawda 2024-03-08 22:40:15 -08:00
parent 5b4fb1392a
commit a8709255b2
20 changed files with 404 additions and 333 deletions

215
Cargo.lock generated
View file

@ -34,9 +34,9 @@ dependencies = [
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.11" version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@ -176,9 +176,9 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.14.0" version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
[[package]] [[package]]
name = "bytes" name = "bytes"
@ -188,12 +188,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.83" version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -203,9 +200,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.18" version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -213,9 +210,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.18" version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -226,9 +223,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.4.7" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@ -238,9 +235,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]] [[package]]
name = "clio" name = "clio"
@ -309,9 +306,9 @@ dependencies = [
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.3.2" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -357,7 +354,7 @@ dependencies = [
[[package]] [[package]]
name = "epoxy-client" name = "epoxy-client"
version = "1.2.1" version = "1.3.0"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"async_io_stream", "async_io_stream",
@ -383,6 +380,7 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-streams", "wasm-streams",
"wasmtimer",
"web-sys", "web-sys",
"webpki-roots", "webpki-roots",
"wisp-mux", "wisp-mux",
@ -640,15 +638,15 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.5" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]] [[package]]
name = "http" name = "http"
version = "1.0.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -692,9 +690,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -706,6 +704,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"smallvec",
"tokio", "tokio",
"want", "want",
] ]
@ -748,9 +747,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.2.2" version = "2.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@ -758,12 +757,12 @@ dependencies = [
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.10" version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"rustix", "libc",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@ -775,9 +774,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.68" version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -812,9 +811,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.20" version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -833,9 +832,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.10" version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi",
@ -887,9 +886,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.63" version = "0.10.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
dependencies = [ dependencies = [
"bitflags 2.4.2", "bitflags 2.4.2",
"cfg-if", "cfg-if",
@ -919,9 +918,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.99" version = "0.9.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -960,18 +959,18 @@ dependencies = [
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.4" version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [ dependencies = [
"pin-project-internal", "pin-project-internal",
] ]
[[package]] [[package]]
name = "pin-project-internal" name = "pin-project-internal"
version = "1.1.4" version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -992,9 +991,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.29" version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
@ -1061,16 +1060,17 @@ dependencies = [
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.7" version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [ dependencies = [
"cc", "cc",
"cfg-if",
"getrandom", "getrandom",
"libc", "libc",
"spin", "spin",
"untrusted", "untrusted",
"windows-sys 0.48.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -1183,9 +1183,9 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.21" version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]] [[package]]
name = "send_wrapper" name = "send_wrapper"
@ -1251,12 +1251,12 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.5.5" version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -1267,9 +1267,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]] [[package]]
name = "subtle" name = "subtle"
@ -1279,9 +1279,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.48" version = "2.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1290,9 +1290,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.0" version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -1312,18 +1312,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.56" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.56" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1492,9 +1492,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.4.0" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [ dependencies = [
"same-file", "same-file",
"winapi-util", "winapi-util",
@ -1517,9 +1517,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.91" version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -1527,9 +1527,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.91" version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
@ -1542,9 +1542,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.41" version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@ -1554,9 +1554,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.91" version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -1564,9 +1564,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.91" version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1577,9 +1577,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.91" version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]] [[package]]
name = "wasm-streams" name = "wasm-streams"
@ -1610,9 +1610,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.67" version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -1688,7 +1688,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets 0.52.0", "windows-targets 0.52.4",
] ]
[[package]] [[package]]
@ -1708,17 +1708,17 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.52.0", "windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.0", "windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.0", "windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.0", "windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.0", "windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.0", "windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.0", "windows_x86_64_msvc 0.52.4",
] ]
[[package]] [[package]]
@ -1735,9 +1735,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
@ -1753,9 +1753,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
@ -1771,9 +1771,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
@ -1789,9 +1789,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
@ -1807,9 +1807,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
@ -1825,9 +1825,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
@ -1843,13 +1843,13 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]] [[package]]
name = "wisp-mux" name = "wisp-mux"
version = "1.1.3" version = "1.2.0"
dependencies = [ dependencies = [
"async_io_stream", "async_io_stream",
"bytes", "bytes",
@ -1857,11 +1857,8 @@ dependencies = [
"fastwebsockets", "fastwebsockets",
"futures", "futures",
"futures-util", "futures-util",
"hyper",
"hyper-util-wasm",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tower-service",
] ]
[[package]] [[package]]

View file

@ -1,5 +1,5 @@
# epoxy # epoxy
Epoxy is an encrypted proxy for browser javascript. It allows you to make requests that bypass cors without compromising security, by running SSL/TLS inside webassembly. Epoxy is an encrypted proxy for browser javascript. It allows you to make requests that bypass CORS without compromising security, by running SSL/TLS inside webassembly.
## Using the client ## Using the client
Epoxy must be run from within a web worker and must be served with the [security headers needed for `SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements). Here is a simple usage example: Epoxy must be run from within a web worker and must be served with the [security headers needed for `SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements). Here is a simple usage example:

View file

@ -1,6 +1,6 @@
[package] [package]
name = "epoxy-client" name = "epoxy-client"
version = "1.2.1" version = "1.3.0"
edition = "2021" edition = "2021"
license = "LGPL-3.0-only" license = "LGPL-3.0-only"
@ -25,7 +25,7 @@ tokio-util = { version = "0.7.10", features = ["io"] }
async-compression = { version = "0.4.5", features = ["tokio", "gzip", "brotli"] } async-compression = { version = "0.4.5", features = ["tokio", "gzip", "brotli"] }
fastwebsockets = { version = "0.6.0", features = ["unstable-split"] } fastwebsockets = { version = "0.6.0", features = ["unstable-split"] }
base64 = "0.21.7" base64 = "0.21.7"
wisp-mux = { path = "../wisp", features = ["tokio_io", "hyper_tower"] } wisp-mux = { path = "../wisp", features = ["tokio_io"] }
async_io_stream = { version = "0.3.3", features = ["tokio_io"] } async_io_stream = { version = "0.3.3", features = ["tokio_io"] }
getrandom = { version = "0.2.12", features = ["js"] } getrandom = { version = "0.2.12", features = ["js"] }
hyper-util-wasm = { version = "0.1.3", features = ["client", "client-legacy", "http1", "http2"] } hyper-util-wasm = { version = "0.1.3", features = ["client", "client-legacy", "http1", "http2"] }
@ -34,6 +34,7 @@ tower-service = "0.3.2"
console_error_panic_hook = "0.1.7" console_error_panic_hook = "0.1.7"
send_wrapper = "0.6.0" send_wrapper = "0.6.0"
event-listener = "5.2.0" event-listener = "5.2.0"
wasmtimer = "0.2.0"
[dependencies.ring] [dependencies.ring]
features = ["wasm32_unknown_unknown_js"] features = ["wasm32_unknown_unknown_js"]

View file

@ -10,7 +10,8 @@ onmessage = async (msg) => {
should_perf_test, should_perf_test,
should_ws_test, should_ws_test,
should_tls_test, should_tls_test,
should_udp_test should_udp_test,
should_reconnect_test,
] = msg.data; ] = msg.data;
console.log( console.log(
"%cWASM is significantly slower with DevTools open!", "%cWASM is significantly slower with DevTools open!",
@ -197,6 +198,14 @@ onmessage = async (msg) => {
); );
await (new Promise((res, _) => setTimeout(res, 5000))); await (new Promise((res, _) => setTimeout(res, 5000)));
await ws.close(); await ws.close();
} else if (should_reconnect_test) {
while (true) {
try {
await epoxy_client.fetch("https://httpbin.org/get");
} catch(e) {console.error(e)}
log("sent req");
await (new Promise((res, _) => setTimeout(res, 500)));
}
} else { } else {
let resp = await epoxy_client.fetch("https://httpbin.org/get"); let resp = await epoxy_client.fetch("https://httpbin.org/get");
console.log(resp, Object.fromEntries(resp.headers)); console.log(resp, Object.fromEntries(resp.headers));

View file

@ -17,6 +17,7 @@
const should_ws_test = params.has("ws_test"); const should_ws_test = params.has("ws_test");
const should_tls_test = params.has("rawtls_test"); const should_tls_test = params.has("rawtls_test");
const should_udp_test = params.has("udp_test"); const should_udp_test = params.has("udp_test");
const should_reconnect_test = params.has("reconnect_test");
const worker = new Worker("demo.js", {type:'module'}); const worker = new Worker("demo.js", {type:'module'});
worker.onmessage = (msg) => { worker.onmessage = (msg) => {
let el = document.createElement("pre"); let el = document.createElement("pre");
@ -32,7 +33,8 @@
should_perf_test, should_perf_test,
should_ws_test, should_ws_test,
should_tls_test, should_tls_test,
should_udp_test should_udp_test,
should_reconnect_test,
]); ]);
</script> </script>
</head> </head>

View file

@ -1,6 +1,6 @@
{ {
"name": "@mercuryworkshop/epoxy-tls", "name": "@mercuryworkshop/epoxy-tls",
"version": "1.2.1", "version": "1.3.0",
"description": "A wasm library for using raw encrypted tls/ssl/https/websocket streams on the browser", "description": "A wasm library for using raw encrypted tls/ssl/https/websocket streams on the browser",
"scripts": { "scripts": {
"build": "./build.sh" "build": "./build.sh"

View file

@ -2,15 +2,17 @@
#[macro_use] #[macro_use]
mod utils; mod utils;
mod tls_stream; mod tls_stream;
mod tokioio;
mod udp_stream; mod udp_stream;
mod websocket; mod websocket;
mod wrappers; mod wrappers;
use tls_stream::EpxTlsStream; use tls_stream::EpxTlsStream;
use tokioio::TokioIo;
use udp_stream::EpxUdpStream; use udp_stream::EpxUdpStream;
use utils::{Boolinator, ReplaceErr, UriExt}; use utils::{Boolinator, ReplaceErr, UriExt};
use websocket::EpxWebSocket; use websocket::EpxWebSocket;
use wrappers::{IncomingBody, TlsWispService, WebSocketWrapper}; use wrappers::{IncomingBody, ServiceWrapper, TlsWispService, WebSocketWrapper};
use std::sync::Arc; use std::sync::Arc;
@ -23,6 +25,7 @@ use hyper::{body::Incoming, Uri};
use hyper_util_wasm::client::legacy::Client; use hyper_util_wasm::client::legacy::Client;
use js_sys::{Array, Function, Object, Reflect, Uint8Array}; use js_sys::{Array, Function, Object, Reflect, Uint8Array};
use rustls::pki_types::TrustAnchor; use rustls::pki_types::TrustAnchor;
use tokio::sync::RwLock;
use tokio_rustls::{client::TlsStream, rustls, rustls::RootCertStore, TlsConnector}; use tokio_rustls::{client::TlsStream, rustls, rustls::RootCertStore, TlsConnector};
use tokio_util::{ use tokio_util::{
either::Either, either::Either,
@ -30,7 +33,7 @@ use tokio_util::{
}; };
use wasm_bindgen::{intern, prelude::*}; use wasm_bindgen::{intern, prelude::*};
use web_sys::TextEncoder; use web_sys::TextEncoder;
use wisp_mux::{tokioio::TokioIo, tower::ServiceWrapper, ClientMux, MuxStreamIo, StreamType}; use wisp_mux::{ClientMux, MuxStreamIo, StreamType};
type HttpBody = http_body_util::Full<Bytes>; type HttpBody = http_body_util::Full<Bytes>;
@ -101,8 +104,8 @@ pub fn certs() -> Result<JsValue, JsValue> {
#[wasm_bindgen(inspectable)] #[wasm_bindgen(inspectable)]
pub struct EpoxyClient { pub struct EpoxyClient {
rustls_config: Arc<rustls::ClientConfig>, rustls_config: Arc<rustls::ClientConfig>,
mux: Arc<ClientMux<WebSocketWrapper>>, mux: Arc<RwLock<ClientMux<WebSocketWrapper>>>,
hyper_client: Client<TlsWispService<WebSocketWrapper>, HttpBody>, hyper_client: Client<TlsWispService, HttpBody>,
#[wasm_bindgen(getter_with_clone)] #[wasm_bindgen(getter_with_clone)]
pub useragent: String, pub useragent: String,
#[wasm_bindgen(js_name = "redirectLimit")] #[wasm_bindgen(js_name = "redirectLimit")]
@ -128,20 +131,9 @@ impl EpoxyClient {
return Err(JsError::new("Scheme must be either `ws` or `wss`")); return Err(JsError::new("Scheme must be either `ws` or `wss`"));
} }
debug!("connecting to ws {:?}", ws_url); let (mux, fut) = utils::make_mux(&ws_url).await?;
let (wtx, wrx) = WebSocketWrapper::connect(ws_url, vec![]) let mux = Arc::new(RwLock::new(mux));
.await utils::spawn_mux_fut(mux.clone(), fut, ws_url.clone());
.replace_err("Failed to connect to websocket")?;
debug!("connected!");
let (mux, fut) = ClientMux::new(wrx, wtx).await?;
let mux = Arc::new(mux);
wasm_bindgen_futures::spawn_local(async move {
if let Err(err) = fut.await {
error!("epoxy: error in mux future! {:?}", err);
}
});
let mut certstore = RootCertStore::empty(); let mut certstore = RootCertStore::empty();
certstore.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); certstore.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
@ -160,7 +152,7 @@ impl EpoxyClient {
.http1_preserve_header_case(true) .http1_preserve_header_case(true)
.build(TlsWispService { .build(TlsWispService {
rustls_config: rustls_config.clone(), rustls_config: rustls_config.clone(),
service: ServiceWrapper(mux), service: ServiceWrapper(mux, ws_url),
}), }),
rustls_config, rustls_config,
useragent, useragent,
@ -171,6 +163,8 @@ impl EpoxyClient {
async fn get_tls_io(&self, url_host: &str, url_port: u16) -> Result<EpxIoTlsStream, JsError> { async fn get_tls_io(&self, url_host: &str, url_port: u16) -> Result<EpxIoTlsStream, JsError> {
let channel = self let channel = self
.mux .mux
.read()
.await
.client_new_stream(StreamType::Tcp, url_host.to_string(), url_port) .client_new_stream(StreamType::Tcp, url_host.to_string(), url_port)
.await .await
.replace_err("Failed to create multiplexor channel")? .replace_err("Failed to create multiplexor channel")?

View file

@ -1,8 +1,6 @@
use crate::*; use crate::*;
use js_sys::Function;
use tokio::io::{split, AsyncWriteExt, WriteHalf}; use tokio::io::{split, AsyncWriteExt, WriteHalf};
use tokio_util::io::ReaderStream;
#[wasm_bindgen(inspectable)] #[wasm_bindgen(inspectable)]
pub struct EpxTlsStream { pub struct EpxTlsStream {

View file

@ -1,7 +1,6 @@
use crate::*; use crate::*;
use futures_util::{stream::SplitSink, SinkExt}; use futures_util::{stream::SplitSink, SinkExt};
use js_sys::Function;
#[wasm_bindgen(inspectable)] #[wasm_bindgen(inspectable)]
pub struct EpxUdpStream { pub struct EpxUdpStream {
@ -34,6 +33,8 @@ impl EpxUdpStream {
let io = tcp let io = tcp
.mux .mux
.read()
.await
.client_new_stream(StreamType::Udp, url_host.to_string(), url_port) .client_new_stream(StreamType::Udp, url_host.to_string(), url_port)
.await .await
.replace_err("Failed to open multiplexor channel")? .replace_err("Failed to open multiplexor channel")?

View file

@ -1,9 +1,10 @@
use crate::*;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use hyper::rt::Executor; use hyper::rt::Executor;
use hyper::{header::HeaderValue, Uri};
use js_sys::{Array, Object};
use std::future::Future; use std::future::Future;
use wisp_mux::{CloseReason, WispError};
#[wasm_bindgen] #[wasm_bindgen]
extern "C" { extern "C" {
@ -186,3 +187,39 @@ pub fn get_url_port(url: &Uri) -> Result<u16, JsError> {
Ok(80) Ok(80)
} }
} }
pub async fn make_mux(url: &str) -> Result<(ClientMux<WebSocketWrapper>, impl Future<Output = Result<(), WispError>>), WispError> {
let (wtx, wrx) = WebSocketWrapper::connect(url, vec![])
.await
.map_err(|_| WispError::WsImplSocketClosed)?;
wtx.wait_for_open().await;
let mux = ClientMux::new(wrx, wtx).await?;
Ok(mux)
}
pub fn spawn_mux_fut(mux: Arc<RwLock<ClientMux<WebSocketWrapper>>>, fut: impl Future<Output = Result<(), WispError>> + 'static, url: String) {
wasm_bindgen_futures::spawn_local(async move {
if let Err(e) = fut.await {
error!("epoxy: error in mux future, restarting: {:?}", e);
while let Err(e) = replace_mux(mux.clone(), &url).await {
error!("epoxy: failed to restart mux future: {:?}", e);
wasmtimer::tokio::sleep(std::time::Duration::from_millis(500)).await;
}
}
debug!("epoxy: mux future exited");
});
}
pub async fn replace_mux(
mux: Arc<RwLock<ClientMux<WebSocketWrapper>>>,
url: &str,
) -> Result<(), WispError> {
let (mux_replace, fut) = make_mux(url).await?;
let mut mux_write = mux.write().await;
mux_write.close(CloseReason::Unknown).await;
*mux_write = mux_replace;
drop(mux_write);
spawn_mux_fut(mux, fut, url.into());
Ok(())
}

View file

@ -11,7 +11,6 @@ use hyper::{
upgrade::Upgraded, upgrade::Upgraded,
StatusCode, StatusCode,
}; };
use js_sys::Function;
use std::str::from_utf8; use std::str::from_utf8;
use tokio::io::WriteHalf; use tokio::io::WriteHalf;

View file

@ -1,11 +1,12 @@
use crate::*; use crate::*;
use std::{ use std::{
pin::Pin, pin::Pin,
sync::atomic::{AtomicBool, Ordering},
task::{Context, Poll}, task::{Context, Poll},
}; };
use event_listener::Event; use event_listener::Event;
use futures_util::Stream; use futures_util::{FutureExt, Stream};
use hyper::body::Body; use hyper::body::Body;
use js_sys::ArrayBuffer; use js_sys::ArrayBuffer;
use pin_project_lite::pin_project; use pin_project_lite::pin_project;
@ -14,8 +15,6 @@ use std::future::Future;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use web_sys::{BinaryType, MessageEvent, WebSocket}; use web_sys::{BinaryType, MessageEvent, WebSocket};
use wisp_mux::{ use wisp_mux::{
tokioio::TokioIo,
tower::ServiceWrapper,
ws::{Frame, LockedWebSocketWrite, WebSocketRead, WebSocketWrite}, ws::{Frame, LockedWebSocketWrite, WebSocketRead, WebSocketWrite},
WispError, WispError,
}; };
@ -53,17 +52,49 @@ impl Stream for IncomingBody {
} }
} }
pub struct TlsWispService<W> #[derive(Clone)]
where pub struct ServiceWrapper(pub Arc<RwLock<ClientMux<WebSocketWrapper>>>, pub String);
W: wisp_mux::ws::WebSocketWrite + Send + 'static,
{ impl tower_service::Service<hyper::Uri> for ServiceWrapper {
pub service: ServiceWrapper<W>, type Response = TokioIo<IoStream<MuxStreamIo, Vec<u8>>>;
type Error = WispError;
type Future = impl Future<Output = Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: hyper::Uri) -> Self::Future {
let mux = self.0.clone();
let mux_url = self.1.clone();
async move {
let stream = mux
.read()
.await
.client_new_stream(
StreamType::Tcp,
req.host().ok_or(WispError::UriHasNoHost)?.to_string(),
req.port().ok_or(WispError::UriHasNoPort)?.into(),
)
.await;
if stream
.as_ref()
.is_err_and(|e| matches!(e, WispError::WsImplSocketClosed))
{
utils::replace_mux(mux, &mux_url).await?;
}
Ok(TokioIo::new(stream?.into_io().into_asyncrw()))
}
}
}
#[derive(Clone)]
pub struct TlsWispService {
pub service: ServiceWrapper,
pub rustls_config: Arc<rustls::ClientConfig>, pub rustls_config: Arc<rustls::ClientConfig>,
} }
impl<W: wisp_mux::ws::WebSocketWrite + Send + 'static> tower_service::Service<hyper::Uri> impl tower_service::Service<hyper::Uri> for TlsWispService {
for TlsWispService<W>
{
type Response = TokioIo<EpxIoStream>; type Response = TokioIo<EpxIoStream>;
type Error = WispError; type Error = WispError;
type Future = Pin<Box<impl Future<Output = Result<Self::Response, Self::Error>>>>; type Future = Pin<Box<impl Future<Output = Result<Self::Response, Self::Error>>>>;
@ -108,18 +139,8 @@ impl<W: wisp_mux::ws::WebSocketWrite + Send + 'static> tower_service::Service<hy
} }
} }
impl<W: wisp_mux::ws::WebSocketWrite + Send + 'static> Clone for TlsWispService<W> {
fn clone(&self) -> Self {
Self {
rustls_config: self.rustls_config.clone(),
service: self.service.clone(),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum WebSocketError { pub enum WebSocketError {
Closed,
Unknown, Unknown,
SendFailed, SendFailed,
} }
@ -128,7 +149,6 @@ impl std::fmt::Display for WebSocketError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
use WebSocketError::*; use WebSocketError::*;
match self { match self {
Closed => write!(f, "Websocket closed"),
Unknown => write!(f, "Unknown error"), Unknown => write!(f, "Unknown error"),
SendFailed => write!(f, "Send failed"), SendFailed => write!(f, "Send failed"),
} }
@ -144,13 +164,16 @@ impl From<WebSocketError> for WispError {
} }
pub enum WebSocketMessage { pub enum WebSocketMessage {
Close, Closed,
Error, Error,
Message(Vec<u8>), Message(Vec<u8>),
} }
pub struct WebSocketWrapper { pub struct WebSocketWrapper {
inner: SendWrapper<WebSocket>, inner: SendWrapper<WebSocket>,
open_event: Arc<Event>,
error_event: Arc<Event>,
closed: Arc<AtomicBool>,
// used to retain the closures // used to retain the closures
#[allow(dead_code)] #[allow(dead_code)]
@ -165,6 +188,8 @@ pub struct WebSocketWrapper {
pub struct WebSocketReader { pub struct WebSocketReader {
read_rx: mpsc::UnboundedReceiver<WebSocketMessage>, read_rx: mpsc::UnboundedReceiver<WebSocketMessage>,
closed: Arc<AtomicBool>,
close_event: Arc<Event>,
} }
impl WebSocketRead for WebSocketReader { impl WebSocketRead for WebSocketReader {
@ -173,49 +198,36 @@ impl WebSocketRead for WebSocketReader {
_: &LockedWebSocketWrite<impl WebSocketWrite>, _: &LockedWebSocketWrite<impl WebSocketWrite>,
) -> Result<Frame, WispError> { ) -> Result<Frame, WispError> {
use WebSocketMessage::*; use WebSocketMessage::*;
match self if self.closed.load(Ordering::Acquire) {
.read_rx return Err(WispError::WsImplSocketClosed);
.recv() }
.await let res = futures_util::select! {
.ok_or(WispError::WsImplError(Box::new(WebSocketError::Closed)))? data = self.read_rx.recv().fuse() => data,
{ _ = self.close_event.listen().fuse() => Some(Closed),
};
match res.ok_or(WispError::WsImplSocketClosed)? {
Message(bin) => Ok(Frame::binary(bin.into())), Message(bin) => Ok(Frame::binary(bin.into())),
Error => Err(WebSocketError::Unknown.into()), Error => Err(WebSocketError::Unknown.into()),
Close => Err(WebSocketError::Closed.into()), Closed => Err(WispError::WsImplSocketClosed),
} }
} }
} }
impl WebSocketWrapper { impl WebSocketWrapper {
pub async fn connect( pub async fn connect(
url: String, url: &str,
protocols: Vec<String>, protocols: Vec<String>,
) -> Result<(Self, WebSocketReader), JsValue> { ) -> Result<(Self, WebSocketReader), JsValue> {
let ws = if protocols.is_empty() {
WebSocket::new(&url)
} else {
WebSocket::new_with_str_sequence(
&url,
&protocols
.iter()
.fold(Array::new(), |acc, x| {
acc.push(&jval!(x));
acc
})
.into(),
)
}
.replace_err("Failed to make websocket")?;
ws.set_binary_type(BinaryType::Arraybuffer);
let (read_tx, read_rx) = mpsc::unbounded_channel(); let (read_tx, read_rx) = mpsc::unbounded_channel();
let closed = Arc::new(AtomicBool::new(false));
let open_event = Arc::new(Event::new()); let open_event = Arc::new(Event::new());
let close_event = Arc::new(Event::new());
let error_event = Arc::new(Event::new());
let open_event_tx = open_event.clone(); let onopen_event = open_event.clone();
let onopen = Closure::wrap( let onopen = Closure::wrap(
Box::new(move || while open_event_tx.notify(usize::MAX) == 0 {}) as Box<dyn Fn()>, Box::new(move || while onopen_event.notify(usize::MAX) == 0 {}) as Box<dyn Fn()>,
); );
let onmessage_tx = read_tx.clone(); let onmessage_tx = read_tx.clone();
@ -226,40 +238,78 @@ impl WebSocketWrapper {
} }
}) as Box<dyn Fn(MessageEvent)>); }) as Box<dyn Fn(MessageEvent)>);
ws.set_onopen(Some(onopen.as_ref().unchecked_ref())); let onclose_closed = closed.clone();
ws.set_onmessage(Some(onmessage.as_ref().unchecked_ref())); let onclose_event = close_event.clone();
let onclose_tx = read_tx.clone();
let onclose = Closure::wrap(Box::new(move || { let onclose = Closure::wrap(Box::new(move || {
let _ = onclose_tx.send(WebSocketMessage::Close); onclose_closed.store(true, Ordering::Release);
onclose_event.notify(usize::MAX);
}) as Box<dyn Fn()>); }) as Box<dyn Fn()>);
let onerror_tx = read_tx.clone(); let onerror_tx = read_tx.clone();
let onerror_closed = closed.clone();
let onerror_close = close_event.clone();
let onerror_event = error_event.clone();
let onerror = Closure::wrap(Box::new(move || { let onerror = Closure::wrap(Box::new(move || {
let _ = onerror_tx.send(WebSocketMessage::Error); let _ = onerror_tx.send(WebSocketMessage::Error);
onerror_closed.store(true, Ordering::Release);
onerror_close.notify(usize::MAX);
onerror_event.notify(usize::MAX);
}) as Box<dyn Fn()>); }) as Box<dyn Fn()>);
let ws = if protocols.is_empty() {
WebSocket::new(url)
} else {
WebSocket::new_with_str_sequence(
url,
&protocols
.iter()
.fold(Array::new(), |acc, x| {
acc.push(&jval!(x));
acc
})
.into(),
)
}
.replace_err("Failed to make websocket")?;
ws.set_binary_type(BinaryType::Arraybuffer);
ws.set_onmessage(Some(onmessage.as_ref().unchecked_ref()));
ws.set_onopen(Some(onopen.as_ref().unchecked_ref()));
ws.set_onclose(Some(onclose.as_ref().unchecked_ref())); ws.set_onclose(Some(onclose.as_ref().unchecked_ref()));
ws.set_onerror(Some(onerror.as_ref().unchecked_ref())); ws.set_onerror(Some(onerror.as_ref().unchecked_ref()));
open_event.listen().await;
Ok(( Ok((
Self { Self {
inner: SendWrapper::new(ws), inner: SendWrapper::new(ws),
open_event,
error_event,
closed: closed.clone(),
onopen: SendWrapper::new(onopen), onopen: SendWrapper::new(onopen),
onclose: SendWrapper::new(onclose), onclose: SendWrapper::new(onclose),
onerror: SendWrapper::new(onerror), onerror: SendWrapper::new(onerror),
onmessage: SendWrapper::new(onmessage), onmessage: SendWrapper::new(onmessage),
}, },
WebSocketReader { read_rx }, WebSocketReader {
read_rx,
closed,
close_event,
},
)) ))
} }
pub async fn wait_for_open(&self) {
futures_util::select! {
_ = self.open_event.listen().fuse() => (),
_ = self.error_event.listen().fuse() => (),
}
}
} }
impl WebSocketWrite for WebSocketWrapper { impl WebSocketWrite for WebSocketWrapper {
async fn wisp_write_frame(&mut self, frame: Frame) -> Result<(), WispError> { async fn wisp_write_frame(&mut self, frame: Frame) -> Result<(), WispError> {
use wisp_mux::ws::OpCode::*; use wisp_mux::ws::OpCode::*;
if self.closed.load(Ordering::Acquire) {
return Err(WispError::WsImplSocketClosed);
}
match frame.opcode { match frame.opcode {
Binary => self Binary => self
.inner .inner

View file

@ -97,7 +97,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let (mux, fut) = ClientMux::new(rx, tx).await?; let (mux, fut) = ClientMux::new(rx, tx).await?;
tokio::task::spawn(fut); tokio::task::spawn(async move { println!("err: {:?}", fut.await); });
let mut hi: u64 = 0; let mut hi: u64 = 0;
loop { loop {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "wisp-mux" name = "wisp-mux"
version = "1.1.3" version = "1.2.0"
license = "LGPL-3.0-only" license = "LGPL-3.0-only"
description = "A library for easily creating Wisp servers and clients." description = "A library for easily creating Wisp servers and clients."
homepage = "https://github.com/MercuryWorkshop/epoxy-tls/tree/multiplexed/wisp" homepage = "https://github.com/MercuryWorkshop/epoxy-tls/tree/multiplexed/wisp"
@ -15,16 +15,12 @@ event-listener = "5.0.0"
fastwebsockets = { version = "0.6.0", features = ["unstable-split"], optional = true } fastwebsockets = { version = "0.6.0", features = ["unstable-split"], optional = true }
futures = "0.3.30" futures = "0.3.30"
futures-util = "0.3.30" futures-util = "0.3.30"
hyper = { version = "1.1.0", optional = true }
hyper-util-wasm = { version = "0.1.3", features = ["client", "client-legacy"], optional = true }
pin-project-lite = "0.2.13" pin-project-lite = "0.2.13"
tokio = { version = "1.35.1", optional = true, default-features = false } tokio = { version = "1.35.1", optional = true, default-features = false }
tower-service = { version = "0.3.2", optional = true }
[features] [features]
fastwebsockets = ["dep:fastwebsockets", "dep:tokio"] fastwebsockets = ["dep:fastwebsockets", "dep:tokio"]
tokio_io = ["async_io_stream/tokio_io"] tokio_io = ["async_io_stream/tokio_io"]
hyper_tower = ["dep:tower-service", "dep:hyper", "dep:tokio", "dep:hyper-util-wasm"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View file

@ -28,11 +28,10 @@ impl From<Frame<'_>> for crate::ws::Frame {
} }
} }
impl TryFrom<crate::ws::Frame> for Frame<'_> { impl From<crate::ws::Frame> for Frame<'_> {
type Error = crate::WispError; fn from(frame: crate::ws::Frame) -> Self {
fn try_from(frame: crate::ws::Frame) -> Result<Self, Self::Error> {
use crate::ws::OpCode::*; use crate::ws::OpCode::*;
Ok(match frame.opcode { match frame.opcode {
Text => Self::text(Payload::Owned(frame.payload.to_vec())), Text => Self::text(Payload::Owned(frame.payload.to_vec())),
Binary => Self::binary(Payload::Owned(frame.payload.to_vec())), Binary => Self::binary(Payload::Owned(frame.payload.to_vec())),
Close => Self::close_raw(Payload::Owned(frame.payload.to_vec())), Close => Self::close_raw(Payload::Owned(frame.payload.to_vec())),
@ -43,13 +42,17 @@ impl TryFrom<crate::ws::Frame> for Frame<'_> {
Payload::Owned(frame.payload.to_vec()), Payload::Owned(frame.payload.to_vec()),
), ),
Pong => Self::pong(Payload::Owned(frame.payload.to_vec())), Pong => Self::pong(Payload::Owned(frame.payload.to_vec())),
}) }
} }
} }
impl From<WebSocketError> for crate::WispError { impl From<WebSocketError> for crate::WispError {
fn from(err: WebSocketError) -> Self { fn from(err: WebSocketError) -> Self {
Self::WsImplError(Box::new(err)) if let WebSocketError::ConnectionClosed = err {
Self::WsImplSocketClosed
} else {
Self::WsImplError(Box::new(err))
}
} }
} }
@ -67,6 +70,8 @@ impl<S: AsyncRead + Unpin + Send> crate::ws::WebSocketRead for FragmentCollector
impl<S: AsyncWrite + Unpin + Send> crate::ws::WebSocketWrite for WebSocketWrite<S> { impl<S: AsyncWrite + Unpin + Send> crate::ws::WebSocketWrite for WebSocketWrite<S> {
async fn wisp_write_frame(&mut self, frame: crate::ws::Frame) -> Result<(), crate::WispError> { async fn wisp_write_frame(&mut self, frame: crate::ws::Frame) -> Result<(), crate::WispError> {
self.write_frame(frame.try_into()?).await.map_err(|e| e.into()) self.write_frame(frame.into())
.await
.map_err(|e| e.into())
} }
} }

View file

@ -11,12 +11,6 @@ mod fastwebsockets;
mod packet; mod packet;
mod sink_unfold; mod sink_unfold;
mod stream; mod stream;
#[cfg(feature = "hyper_tower")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper_tower")))]
pub mod tokioio;
#[cfg(feature = "hyper_tower")]
#[cfg_attr(docsrs, doc(cfg(feature = "hyper_tower")))]
pub mod tower;
pub mod ws; pub mod ws;
pub use crate::packet::*; pub use crate::packet::*;
@ -140,10 +134,10 @@ impl<W: ws::WebSocketWrite + Send + 'static> ServerMuxInner<W> {
R: ws::WebSocketRead, R: ws::WebSocketRead,
{ {
let ret = futures::select! { let ret = futures::select! {
x = self.server_close_loop(close_rx).fuse() => x, x = self.server_bg_loop(close_rx).fuse() => x,
x = self.server_msg_loop(rx, muxstream_sender, buffer_size).fuse() => x x = self.server_msg_loop(rx, muxstream_sender, buffer_size).fuse() => x
}; };
self.stream_map.lock().await.iter().for_each(|x| { self.stream_map.lock().await.drain().for_each(|x| {
let _ = let _ =
x.1.stream x.1.stream
.unbounded_send(MuxEvent::Close(ClosePacket::new(CloseReason::Unknown))); .unbounded_send(MuxEvent::Close(ClosePacket::new(CloseReason::Unknown)));
@ -151,7 +145,7 @@ impl<W: ws::WebSocketWrite + Send + 'static> ServerMuxInner<W> {
ret ret
} }
async fn server_close_loop( async fn server_bg_loop(
&self, &self,
mut close_rx: mpsc::UnboundedReceiver<WsEvent>, mut close_rx: mpsc::UnboundedReceiver<WsEvent>,
) -> Result<(), WispError> { ) -> Result<(), WispError> {
@ -168,6 +162,7 @@ impl<W: ws::WebSocketWrite + Send + 'static> ServerMuxInner<W> {
let _ = channel.send(Err(WispError::InvalidStreamId)); let _ = channel.send(Err(WispError::InvalidStreamId));
} }
} }
WsEvent::EndFut => break,
} }
} }
Ok(()) Ok(())
@ -186,66 +181,62 @@ impl<W: ws::WebSocketWrite + Send + 'static> ServerMuxInner<W> {
.write_frame(Packet::new_continue(0, buffer_size).into()) .write_frame(Packet::new_continue(0, buffer_size).into())
.await?; .await?;
while let Ok(frame) = rx.wisp_read_frame(&self.tx).await { loop {
if let Ok(packet) = Packet::try_from(frame) { let packet: Packet = rx.wisp_read_frame(&self.tx).await?.try_into()?;
use PacketType::*; use PacketType::*;
match packet.packet { match packet.packet_type {
Connect(inner_packet) => { Connect(inner_packet) => {
let (ch_tx, ch_rx) = mpsc::unbounded(); let (ch_tx, ch_rx) = mpsc::unbounded();
let stream_type = inner_packet.stream_type; let stream_type = inner_packet.stream_type;
let flow_control: Arc<AtomicU32> = AtomicU32::new(buffer_size).into(); let flow_control: Arc<AtomicU32> = AtomicU32::new(buffer_size).into();
let flow_control_event: Arc<Event> = Event::new().into(); let flow_control_event: Arc<Event> = Event::new().into();
self.stream_map.lock().await.insert( self.stream_map.lock().await.insert(
packet.stream_id, packet.stream_id,
MuxMapValue { MuxMapValue {
stream: ch_tx, stream: ch_tx,
flow_control: flow_control.clone(), flow_control: flow_control.clone(),
flow_control_event: flow_control_event.clone(), flow_control_event: flow_control_event.clone(),
}, },
);
muxstream_sender
.unbounded_send((
inner_packet,
MuxStream::new(
packet.stream_id,
Role::Server,
stream_type,
ch_rx,
self.tx.clone(),
self.close_tx.clone(),
AtomicBool::new(false).into(),
flow_control,
flow_control_event,
),
))
.map_err(|x| WispError::Other(Box::new(x)))?;
}
Data(data) => {
if let Some(stream) = self.stream_map.lock().await.get(&packet.stream_id) {
let _ = stream.stream.unbounded_send(MuxEvent::Send(data));
stream.flow_control.store(
stream
.flow_control
.load(Ordering::Acquire)
.saturating_sub(1),
Ordering::Release,
); );
muxstream_sender
.unbounded_send((
inner_packet,
MuxStream::new(
packet.stream_id,
Role::Server,
stream_type,
ch_rx,
self.tx.clone(),
self.close_tx.clone(),
AtomicBool::new(false).into(),
flow_control,
flow_control_event,
),
))
.map_err(|x| WispError::Other(Box::new(x)))?;
}
Data(data) => {
if let Some(stream) = self.stream_map.lock().await.get(&packet.stream_id) {
let _ = stream.stream.unbounded_send(MuxEvent::Send(data));
stream.flow_control.store(
stream.flow_control
.load(Ordering::Acquire)
.saturating_sub(1),
Ordering::Release,
);
}
}
Continue(_) => unreachable!(),
Close(inner_packet) => {
if let Some(stream) = self.stream_map.lock().await.get(&packet.stream_id) {
let _ = stream.stream.unbounded_send(MuxEvent::Close(inner_packet));
}
self.stream_map.lock().await.remove(&packet.stream_id);
} }
} }
} else { Continue(_) => unreachable!(),
break; Close(inner_packet) => {
if let Some(stream) = self.stream_map.lock().await.get(&packet.stream_id) {
let _ = stream.stream.unbounded_send(MuxEvent::Close(inner_packet));
}
self.stream_map.lock().await.remove(&packet.stream_id);
}
} }
} }
drop(muxstream_sender);
Ok(())
} }
} }
@ -272,6 +263,8 @@ pub struct ServerMux<W>
where where
W: ws::WebSocketWrite + Send + 'static, W: ws::WebSocketWrite + Send + 'static,
{ {
stream_map: Arc<Mutex<HashMap<u32, MuxMapValue>>>,
close_tx: mpsc::UnboundedSender<WsEvent>,
muxstream_recv: mpsc::UnboundedReceiver<(ConnectPacket, MuxStream<W>)>, muxstream_recv: mpsc::UnboundedReceiver<(ConnectPacket, MuxStream<W>)>,
} }
@ -290,7 +283,11 @@ impl<W: ws::WebSocketWrite + Send + 'static> ServerMux<W> {
let write = ws::LockedWebSocketWrite::new(write); let write = ws::LockedWebSocketWrite::new(write);
let map = Arc::new(Mutex::new(HashMap::new())); let map = Arc::new(Mutex::new(HashMap::new()));
( (
Self { muxstream_recv: rx }, Self {
muxstream_recv: rx,
close_tx: close_tx.clone(),
stream_map: map.clone(),
},
ServerMuxInner { ServerMuxInner {
tx: write, tx: write,
close_tx, close_tx,
@ -304,6 +301,19 @@ impl<W: ws::WebSocketWrite + Send + 'static> ServerMux<W> {
pub async fn server_new_stream(&mut self) -> Option<(ConnectPacket, MuxStream<W>)> { pub async fn server_new_stream(&mut self) -> Option<(ConnectPacket, MuxStream<W>)> {
self.muxstream_recv.next().await self.muxstream_recv.next().await
} }
/// Close all streams.
///
/// Also terminates the multiplexor future. Waiting for a new stream will never succeed after
/// this function is called.
pub async fn close(&self, reason: CloseReason) {
self.stream_map.lock().await.drain().for_each(|x| {
let _ =
x.1.stream
.unbounded_send(MuxEvent::Close(ClosePacket::new(reason)));
});
let _ = self.close_tx.unbounded_send(WsEvent::EndFut);
}
} }
struct ClientMuxInner<W> struct ClientMuxInner<W>
@ -346,6 +356,7 @@ impl<W: ws::WebSocketWrite + Send> ClientMuxInner<W> {
let _ = channel.send(Err(WispError::InvalidStreamId)); let _ = channel.send(Err(WispError::InvalidStreamId));
} }
} }
WsEvent::EndFut => break,
} }
} }
Ok(()) Ok(())
@ -355,10 +366,11 @@ impl<W: ws::WebSocketWrite + Send> ClientMuxInner<W> {
where where
R: ws::WebSocketRead, R: ws::WebSocketRead,
{ {
while let Ok(frame) = rx.wisp_read_frame(&self.tx).await { loop {
let frame = rx.wisp_read_frame(&self.tx).await?;
if let Ok(packet) = Packet::try_from(frame) { if let Ok(packet) = Packet::try_from(frame) {
use PacketType::*; use PacketType::*;
match packet.packet { match packet.packet_type {
Connect(_) => unreachable!(), Connect(_) => unreachable!(),
Data(data) => { Data(data) => {
if let Some(stream) = self.stream_map.lock().await.get(&packet.stream_id) { if let Some(stream) = self.stream_map.lock().await.get(&packet.stream_id) {
@ -382,7 +394,6 @@ impl<W: ws::WebSocketWrite + Send> ClientMuxInner<W> {
} }
} }
} }
Ok(())
} }
} }
@ -425,7 +436,7 @@ impl<W: ws::WebSocketWrite + Send + 'static> ClientMux<W> {
if first_packet.stream_id != 0 { if first_packet.stream_id != 0 {
return Err(WispError::InvalidStreamId); return Err(WispError::InvalidStreamId);
} }
if let PacketType::Continue(packet) = first_packet.packet { if let PacketType::Continue(packet) = first_packet.packet_type {
let (tx, rx) = mpsc::unbounded::<WsEvent>(); let (tx, rx) = mpsc::unbounded::<WsEvent>();
let map = Arc::new(Mutex::new(HashMap::new())); let map = Arc::new(Mutex::new(HashMap::new()));
Ok(( Ok((
@ -487,4 +498,17 @@ impl<W: ws::WebSocketWrite + Send + 'static> ClientMux<W> {
evt, evt,
)) ))
} }
/// Close all streams.
///
/// Also terminates the multiplexor future. Creating a stream is UB after calling this
/// function.
pub async fn close(&self, reason: CloseReason) {
self.stream_map.lock().await.drain().for_each(|x| {
let _ =
x.1.stream
.unbounded_send(MuxEvent::Close(ClosePacket::new(reason)));
});
let _ = self.close_tx.unbounded_send(WsEvent::EndFut);
}
} }

View file

@ -242,8 +242,8 @@ impl From<PacketType> for Vec<u8> {
pub struct Packet { pub struct Packet {
/// Stream this packet is associated with. /// Stream this packet is associated with.
pub stream_id: u32, pub stream_id: u32,
/// Packet recieved. /// Packet type recieved.
pub packet: PacketType, pub packet_type: PacketType,
} }
impl Packet { impl Packet {
@ -251,7 +251,7 @@ impl Packet {
/// ///
/// The helper functions should be used for most use cases. /// The helper functions should be used for most use cases.
pub fn new(stream_id: u32, packet: PacketType) -> Self { pub fn new(stream_id: u32, packet: PacketType) -> Self {
Self { stream_id, packet } Self { stream_id, packet_type: packet }
} }
/// Create a new connect packet. /// Create a new connect packet.
@ -263,7 +263,7 @@ impl Packet {
) -> Self { ) -> Self {
Self { Self {
stream_id, stream_id,
packet: PacketType::Connect(ConnectPacket::new( packet_type: PacketType::Connect(ConnectPacket::new(
stream_type, stream_type,
destination_port, destination_port,
destination_hostname, destination_hostname,
@ -275,7 +275,7 @@ impl Packet {
pub fn new_data(stream_id: u32, data: Bytes) -> Self { pub fn new_data(stream_id: u32, data: Bytes) -> Self {
Self { Self {
stream_id, stream_id,
packet: PacketType::Data(data), packet_type: PacketType::Data(data),
} }
} }
@ -283,7 +283,7 @@ impl Packet {
pub fn new_continue(stream_id: u32, buffer_remaining: u32) -> Self { pub fn new_continue(stream_id: u32, buffer_remaining: u32) -> Self {
Self { Self {
stream_id, stream_id,
packet: PacketType::Continue(ContinuePacket::new(buffer_remaining)), packet_type: PacketType::Continue(ContinuePacket::new(buffer_remaining)),
} }
} }
@ -291,7 +291,7 @@ impl Packet {
pub fn new_close(stream_id: u32, reason: CloseReason) -> Self { pub fn new_close(stream_id: u32, reason: CloseReason) -> Self {
Self { Self {
stream_id, stream_id,
packet: PacketType::Close(ClosePacket::new(reason)), packet_type: PacketType::Close(ClosePacket::new(reason)),
} }
} }
} }
@ -306,7 +306,7 @@ impl TryFrom<Bytes> for Packet {
use PacketType::*; use PacketType::*;
Ok(Self { Ok(Self {
stream_id: bytes.get_u32_le(), stream_id: bytes.get_u32_le(),
packet: match packet_type { packet_type: match packet_type {
0x01 => Connect(ConnectPacket::try_from(bytes)?), 0x01 => Connect(ConnectPacket::try_from(bytes)?),
0x02 => Data(bytes), 0x02 => Data(bytes),
0x03 => Continue(ContinuePacket::try_from(bytes)?), 0x03 => Continue(ContinuePacket::try_from(bytes)?),
@ -320,9 +320,9 @@ impl TryFrom<Bytes> for Packet {
impl From<Packet> for Vec<u8> { impl From<Packet> for Vec<u8> {
fn from(packet: Packet) -> Self { fn from(packet: Packet) -> Self {
let mut encoded = Self::with_capacity(1 + 4); let mut encoded = Self::with_capacity(1 + 4);
encoded.push(packet.packet.as_u8()); encoded.push(packet.packet_type.as_u8());
encoded.put_u32_le(packet.stream_id); encoded.put_u32_le(packet.stream_id);
encoded.extend(Vec::<u8>::from(packet.packet)); encoded.extend(Vec::<u8>::from(packet.packet_type));
encoded encoded
} }
} }

View file

@ -26,6 +26,7 @@ pub enum MuxEvent {
pub(crate) enum WsEvent { pub(crate) enum WsEvent {
Close(u32, crate::CloseReason, oneshot::Sender<Result<(), crate::WispError>>), Close(u32, crate::CloseReason, oneshot::Sender<Result<(), crate::WispError>>),
EndFut,
} }
/// Read side of a multiplexor stream. /// Read side of a multiplexor stream.

View file

@ -1,43 +0,0 @@
//! Helper that implements a Tower Service for a client multiplexor.
use crate::{tokioio::TokioIo, ws::WebSocketWrite, ClientMux, MuxStreamIo, StreamType, WispError};
use async_io_stream::IoStream;
use futures::{
task::{Context, Poll},
Future,
};
use std::sync::Arc;
/// Wrapper struct that implements a Tower Service sfor a client multiplexor.
pub struct ServiceWrapper<W: WebSocketWrite + Send + 'static>(pub Arc<ClientMux<W>>);
impl<W: WebSocketWrite + Send + 'static> tower_service::Service<hyper::Uri> for ServiceWrapper<W> {
type Response = TokioIo<IoStream<MuxStreamIo, Vec<u8>>>;
type Error = WispError;
type Future = impl Future<Output = Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: hyper::Uri) -> Self::Future {
let mux = self.0.clone();
async move {
Ok(TokioIo::new(
mux.client_new_stream(
StreamType::Tcp,
req.host().ok_or(WispError::UriHasNoHost)?.to_string(),
req.port().ok_or(WispError::UriHasNoPort)?.into(),
)
.await?
.into_io()
.into_asyncrw(),
))
}
}
}
impl<W: WebSocketWrite + Send + 'static> Clone for ServiceWrapper<W> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}