some error handling improvements & start on chat send
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
dist/
|
dist/
|
||||||
|
server_hash.txt
|
||||||
|
|||||||
Generated
+78
-285
@@ -29,6 +29,15 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.18"
|
version = "0.2.18"
|
||||||
@@ -47,17 +56,6 @@ version = "0.13.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
|
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-channel"
|
|
||||||
version = "1.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
|
||||||
dependencies = [
|
|
||||||
"concurrent-queue",
|
|
||||||
"event-listener 2.5.3",
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@@ -70,119 +68,6 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-executor"
|
|
||||||
version = "1.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0"
|
|
||||||
dependencies = [
|
|
||||||
"async-task",
|
|
||||||
"concurrent-queue",
|
|
||||||
"fastrand 2.1.0",
|
|
||||||
"futures-lite 2.3.0",
|
|
||||||
"slab",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-global-executor"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel 2.3.1",
|
|
||||||
"async-executor",
|
|
||||||
"async-io 2.3.3",
|
|
||||||
"async-lock 3.4.0",
|
|
||||||
"blocking",
|
|
||||||
"futures-lite 2.3.0",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-io"
|
|
||||||
version = "1.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
|
|
||||||
dependencies = [
|
|
||||||
"async-lock 2.8.0",
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"futures-lite 1.13.0",
|
|
||||||
"log",
|
|
||||||
"parking",
|
|
||||||
"polling 2.8.0",
|
|
||||||
"rustix 0.37.27",
|
|
||||||
"slab",
|
|
||||||
"socket2 0.4.10",
|
|
||||||
"waker-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-io"
|
|
||||||
version = "2.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964"
|
|
||||||
dependencies = [
|
|
||||||
"async-lock 3.4.0",
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"futures-io",
|
|
||||||
"futures-lite 2.3.0",
|
|
||||||
"parking",
|
|
||||||
"polling 3.7.2",
|
|
||||||
"rustix 0.38.34",
|
|
||||||
"slab",
|
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-lock"
|
|
||||||
version = "2.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
|
|
||||||
dependencies = [
|
|
||||||
"event-listener 2.5.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-lock"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
|
|
||||||
dependencies = [
|
|
||||||
"event-listener 5.3.1",
|
|
||||||
"event-listener-strategy",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-std"
|
|
||||||
version = "1.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
|
||||||
dependencies = [
|
|
||||||
"async-channel 1.9.0",
|
|
||||||
"async-global-executor",
|
|
||||||
"async-io 1.13.0",
|
|
||||||
"async-lock 2.8.0",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"futures-lite 1.13.0",
|
|
||||||
"gloo-timers",
|
|
||||||
"kv-log-macro",
|
|
||||||
"log",
|
|
||||||
"memchr",
|
|
||||||
"once_cell",
|
|
||||||
"pin-project-lite",
|
|
||||||
"pin-utils",
|
|
||||||
"slab",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-task"
|
name = "async-task"
|
||||||
version = "4.7.1"
|
version = "4.7.1"
|
||||||
@@ -276,10 +161,10 @@ version = "1.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.3.1",
|
"async-channel",
|
||||||
"async-task",
|
"async-task",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite 2.3.0",
|
"futures-lite",
|
||||||
"piper",
|
"piper",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -935,12 +820,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "event-listener"
|
|
||||||
version = "2.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "5.3.1"
|
version = "5.3.1"
|
||||||
@@ -958,19 +837,10 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
|
checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener 5.3.1",
|
"event-listener",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrand"
|
|
||||||
version = "1.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
|
||||||
dependencies = [
|
|
||||||
"instant",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@@ -1061,31 +931,13 @@ 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 = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-lite"
|
|
||||||
version = "1.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
|
||||||
dependencies = [
|
|
||||||
"fastrand 1.9.0",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"memchr",
|
|
||||||
"parking",
|
|
||||||
"pin-project-lite",
|
|
||||||
"waker-fn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
|
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand 2.1.0",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
|
||||||
"parking",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1179,7 +1031,7 @@ dependencies = [
|
|||||||
"gloo-net 0.3.1",
|
"gloo-net 0.3.1",
|
||||||
"gloo-render",
|
"gloo-render",
|
||||||
"gloo-storage",
|
"gloo-storage",
|
||||||
"gloo-timers",
|
"gloo-timers 0.2.6",
|
||||||
"gloo-utils 0.1.7",
|
"gloo-utils 0.1.7",
|
||||||
"gloo-worker",
|
"gloo-worker",
|
||||||
]
|
]
|
||||||
@@ -1317,6 +1169,16 @@ name = "gloo-timers"
|
|||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
|
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gloo-timers"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -1415,18 +1277,6 @@ dependencies = [
|
|||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.9"
|
version = "0.5.9"
|
||||||
@@ -1507,7 +1357,7 @@ dependencies = [
|
|||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa 1.0.11",
|
"itoa 1.0.11",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2 0.5.7",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -1562,15 +1412,6 @@ dependencies = [
|
|||||||
"cfb",
|
"cfb",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instant"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "internment"
|
name = "internment"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@@ -1607,17 +1448,6 @@ version = "0.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9"
|
checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "io-lifetimes"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi 0.3.9",
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
@@ -1669,15 +1499,6 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kv-log-macro"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -1696,12 +1517,6 @@ version = "0.2.155"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.3.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
@@ -1723,9 +1538,6 @@ name = "log"
|
|||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
dependencies = [
|
|
||||||
"value-bag",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lol_html"
|
name = "lol_html"
|
||||||
@@ -1801,6 +1613,17 @@ dependencies = [
|
|||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "markdown"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef3aab6a1d529b112695f72beec5ee80e729cb45af58663ec902c8fac764ecdd"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"pipeline",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
@@ -1873,14 +1696,16 @@ name = "mumble-webtransport"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-std",
|
|
||||||
"asynchronous-codec",
|
"asynchronous-codec",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-web",
|
"dioxus-web",
|
||||||
"futures",
|
"futures",
|
||||||
|
"futures-channel",
|
||||||
|
"gloo-timers 0.3.0",
|
||||||
"html-purifier",
|
"html-purifier",
|
||||||
"manganis",
|
"manganis",
|
||||||
|
"markdown",
|
||||||
"merge-io",
|
"merge-io",
|
||||||
"mumble-protocol-2x",
|
"mumble-protocol-2x",
|
||||||
"ogg",
|
"ogg",
|
||||||
@@ -2160,6 +1985,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pipeline"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d15b6607fa632996eb8a17c9041cb6071cb75ac057abd45dece578723ea8c7c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "piper"
|
name = "piper"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@@ -2167,7 +1998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391"
|
checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"fastrand 2.1.0",
|
"fastrand",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2177,37 +2008,6 @@ 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 = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "polling"
|
|
||||||
version = "2.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"pin-project-lite",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "polling"
|
|
||||||
version = "3.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"hermit-abi 0.4.0",
|
|
||||||
"pin-project-lite",
|
|
||||||
"rustix 0.38.34",
|
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
@@ -2342,6 +2142,35 @@ dependencies = [
|
|||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.27"
|
version = "0.11.27"
|
||||||
@@ -2403,20 +2232,6 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.37.27"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"errno",
|
|
||||||
"io-lifetimes",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys 0.3.8",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.34"
|
version = "0.38.34"
|
||||||
@@ -2426,7 +2241,7 @@ dependencies = [
|
|||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.4.14",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2760,16 +2575,6 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "socket2"
|
|
||||||
version = "0.4.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.7"
|
version = "0.5.7"
|
||||||
@@ -2851,8 +2656,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand 2.1.0",
|
"fastrand",
|
||||||
"rustix 0.38.34",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2924,7 +2729,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2 0.5.7",
|
"socket2",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3117,12 +2922,6 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "value-bag"
|
|
||||||
version = "1.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -3135,12 +2934,6 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "waker-fn"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|||||||
+3
-1
@@ -19,9 +19,11 @@ wasm-bindgen = "0.2.92"
|
|||||||
wasm-bindgen-futures = "0.4.42"
|
wasm-bindgen-futures = "0.4.42"
|
||||||
wasm-streams = "0.4.0"
|
wasm-streams = "0.4.0"
|
||||||
web-sys = { version = "0.3.70", features = ["WebTransport", "console", "WebTransportOptions", "WebTransportBidirectionalStream", "WebTransportSendStream", "WebTransportReceiveStream", "Navigator", "MediaDevices", "AudioDecoder", "AudioDecoderInit", "AudioData", "AudioEncoderConfig", "AudioDecoderConfig", "EncodedAudioChunk", "EncodedAudioChunkInit", "EncodedAudioChunkType", "CodecState", "MediaStreamTrackGenerator", "MediaStreamTrackGeneratorInit", "AudioContext", "AudioContextOptions", "MediaStream", "GainNode", "MediaStreamAudioSourceNode", "BaseAudioContext", "AudioDestinationNode", "AudioWorkletNode", "AudioWorklet", "AudioWorkletProcessor", "MediaStreamConstraints", "WorkletOptions", "AudioEncoder", "AudioEncoderInit", "AudioDataInit", "HtmlAnchorElement", "Url", "Blob", "AudioDataCopyToOptions", "AudioSampleFormat"] }
|
web-sys = { version = "0.3.70", features = ["WebTransport", "console", "WebTransportOptions", "WebTransportBidirectionalStream", "WebTransportSendStream", "WebTransportReceiveStream", "Navigator", "MediaDevices", "AudioDecoder", "AudioDecoderInit", "AudioData", "AudioEncoderConfig", "AudioDecoderConfig", "EncodedAudioChunk", "EncodedAudioChunkInit", "EncodedAudioChunkType", "CodecState", "MediaStreamTrackGenerator", "MediaStreamTrackGeneratorInit", "AudioContext", "AudioContextOptions", "MediaStream", "GainNode", "MediaStreamAudioSourceNode", "BaseAudioContext", "AudioDestinationNode", "AudioWorkletNode", "AudioWorklet", "AudioWorkletProcessor", "MediaStreamConstraints", "WorkletOptions", "AudioEncoder", "AudioEncoderInit", "AudioDataInit", "HtmlAnchorElement", "Url", "Blob", "AudioDataCopyToOptions", "AudioSampleFormat"] }
|
||||||
async-std = "1.12.0"
|
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
ogg = "0.9.1"
|
ogg = "0.9.1"
|
||||||
ordermap = "0.5.3"
|
ordermap = "0.5.3"
|
||||||
html-purifier = "0.3.0"
|
html-purifier = "0.3.0"
|
||||||
|
markdown = "0.3.0"
|
||||||
|
gloo-timers = { version = "0.3.0", features = ["futures"] }
|
||||||
|
futures-channel = "0.3.30"
|
||||||
|
|||||||
+50
-7
@@ -5,13 +5,31 @@ use std::collections::{BTreeMap, BTreeSet, HashMap};
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use ordermap::OrderSet;
|
use ordermap::OrderSet;
|
||||||
|
|
||||||
use super::Command;
|
|
||||||
use super::Command::*;
|
|
||||||
use super::ConnectionState::{self, *};
|
|
||||||
|
|
||||||
pub type ChannelId = u32;
|
pub type ChannelId = u32;
|
||||||
pub type UserId = u32;
|
pub type UserId = u32;
|
||||||
|
|
||||||
|
pub enum ConnectionState {
|
||||||
|
Disconnected,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Command {
|
||||||
|
Connect {
|
||||||
|
address: String,
|
||||||
|
username: String,
|
||||||
|
hash: String,
|
||||||
|
},
|
||||||
|
SendChat {
|
||||||
|
markdown: String,
|
||||||
|
channels: Vec<ChannelId>,
|
||||||
|
},
|
||||||
|
Disconnect,
|
||||||
|
}
|
||||||
|
|
||||||
|
use Command::*;
|
||||||
|
use ConnectionState::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ChannelState {
|
pub struct ChannelState {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -27,7 +45,7 @@ pub struct UserState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Chat {
|
pub struct Chat {
|
||||||
pub text: String,
|
pub raw: String,
|
||||||
pub dangerous_html: String,
|
pub dangerous_html: String,
|
||||||
pub sender: Option<UserId>,
|
pub sender: Option<UserId>,
|
||||||
}
|
}
|
||||||
@@ -37,6 +55,13 @@ pub struct ServerState {
|
|||||||
pub channels: HashMap<ChannelId, ChannelState>,
|
pub channels: HashMap<ChannelId, ChannelState>,
|
||||||
pub users: HashMap<UserId, UserState>,
|
pub users: HashMap<UserId, UserState>,
|
||||||
pub chat: Vec<Chat>,
|
pub chat: Vec<Chat>,
|
||||||
|
pub session: Option<UserId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerState {
|
||||||
|
pub fn this_user(&self) -> Option<&UserState> {
|
||||||
|
self.users.get(&self.session?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
@@ -80,8 +105,10 @@ pub fn Channel(id: ChannelId) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ChatHistory() -> Element {
|
pub fn ChatView() -> Element {
|
||||||
let server = STATE.server.read();
|
let server = STATE.server.read();
|
||||||
|
let mut draft = use_signal(|| "".to_string());
|
||||||
|
//let net: Coroutine<Command> = use_coroutine_handle();
|
||||||
rsx!(
|
rsx!(
|
||||||
div {
|
div {
|
||||||
style: "margin: 16px; padding: 16px; border: solid black 1px;",
|
style: "margin: 16px; padding: 16px; border: solid black 1px;",
|
||||||
@@ -98,6 +125,22 @@ pub fn ChatHistory() -> Element {
|
|||||||
}
|
}
|
||||||
hr {}
|
hr {}
|
||||||
}
|
}
|
||||||
|
input {
|
||||||
|
placeholder: "say something",
|
||||||
|
value: "{draft.read()}",
|
||||||
|
oninput: move |evt| draft.set(evt.value().clone()),
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
onclick: move |_| {
|
||||||
|
/*if let Some(user) = server.this_user() {
|
||||||
|
net.send(SendChat {
|
||||||
|
markdown: draft.write().split_off(0),
|
||||||
|
channels: vec![user.channel],
|
||||||
|
});
|
||||||
|
}*/
|
||||||
|
},
|
||||||
|
"Send"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -114,7 +157,7 @@ pub fn ServerView() -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChatHistory {}
|
ChatView {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+223
-205
@@ -1,25 +1,27 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
|
|
||||||
use app::ChannelState;
|
use app::ChannelId;
|
||||||
use app::Chat;
|
use app::Chat;
|
||||||
use app::UserState;
|
use app::Command;
|
||||||
|
use app::ConnectionState;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
use anyhow::Error;
|
|
||||||
use app::STATE;
|
use app::STATE;
|
||||||
use async_std::channel::Sender;
|
|
||||||
use futures::select;
|
use futures::select;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::SinkExt;
|
use futures::SinkExt;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use futures_channel::mpsc::UnboundedSender;
|
||||||
|
use gloo_timers::future::TimeoutFuture;
|
||||||
use manganis::{file, mg};
|
use manganis::{file, mg};
|
||||||
|
use markdown;
|
||||||
use mumble_protocol::control::ControlPacket;
|
use mumble_protocol::control::ControlPacket;
|
||||||
use mumble_protocol::control::{msgs, ClientControlCodec};
|
use mumble_protocol::control::{msgs, ClientControlCodec};
|
||||||
use mumble_protocol::voice::VoicePacket;
|
use mumble_protocol::voice::VoicePacket;
|
||||||
use mumble_protocol::voice::VoicePacketDst;
|
|
||||||
use mumble_protocol::voice::VoicePacketPayload;
|
use mumble_protocol::voice::VoicePacketPayload;
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Duration;
|
use std::fmt;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_futures::spawn_local as spawn;
|
use wasm_bindgen_futures::spawn_local as spawn;
|
||||||
use wasm_bindgen_futures::{future_to_promise, JsFuture};
|
use wasm_bindgen_futures::{future_to_promise, JsFuture};
|
||||||
@@ -47,11 +49,11 @@ use web_sys::MediaStreamTrackGenerator;
|
|||||||
use web_sys::MediaStreamTrackGeneratorInit;
|
use web_sys::MediaStreamTrackGeneratorInit;
|
||||||
use web_sys::MessageEvent;
|
use web_sys::MessageEvent;
|
||||||
use web_sys::WebTransport;
|
use web_sys::WebTransport;
|
||||||
|
use web_sys::WebTransportBidirectionalStream;
|
||||||
use web_sys::WebTransportOptions;
|
use web_sys::WebTransportOptions;
|
||||||
use web_sys::WorkletOptions;
|
use web_sys::WorkletOptions;
|
||||||
|
|
||||||
mod ass {
|
mod ass {
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use ogg::PacketWriter;
|
use ogg::PacketWriter;
|
||||||
|
|
||||||
@@ -168,7 +170,7 @@ impl PromiseExt for Promise {
|
|||||||
|
|
||||||
async fn create_encoder_worklet(
|
async fn create_encoder_worklet(
|
||||||
audio_context: &AudioContext,
|
audio_context: &AudioContext,
|
||||||
packets: Sender<ControlPacket<mumble_protocol::Serverbound>>,
|
packets: UnboundedSender<ControlPacket<mumble_protocol::Serverbound>>,
|
||||||
) -> Result<AudioWorkletNode, JsValue> {
|
) -> Result<AudioWorkletNode, JsValue> {
|
||||||
let stream = window()
|
let stream = window()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -219,14 +221,15 @@ async fn create_encoder_worklet(
|
|||||||
download_buffer.borrow_mut().clear();
|
download_buffer.borrow_mut().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = packets.try_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio {
|
let _ =
|
||||||
_dst: std::marker::PhantomData,
|
packets.unbounded_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio {
|
||||||
target: 0,
|
_dst: std::marker::PhantomData,
|
||||||
session_id: (),
|
target: 0,
|
||||||
seq_num: sequence_num,
|
session_id: (),
|
||||||
payload: VoicePacketPayload::Opus(array.into(), false),
|
seq_num: sequence_num,
|
||||||
position_info: None,
|
payload: VoicePacketPayload::Opus(array.into(), false),
|
||||||
})));
|
position_info: None,
|
||||||
|
})));
|
||||||
sequence_num = sequence_num.wrapping_add(2);
|
sequence_num = sequence_num.wrapping_add(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -284,27 +287,23 @@ async fn create_encoder_worklet(
|
|||||||
Ok(worklet_node)
|
Ok(worklet_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_decoder(audio_context: &AudioContext) -> AudioDecoder {
|
fn create_decoder(audio_context: &AudioContext) -> Result<AudioDecoder, JsValue> {
|
||||||
let audio_stream_generator =
|
let audio_stream_generator =
|
||||||
MediaStreamTrackGenerator::new(&MediaStreamTrackGeneratorInit::new("audio")).unwrap();
|
MediaStreamTrackGenerator::new(&MediaStreamTrackGeneratorInit::new("audio"))?;
|
||||||
|
|
||||||
// Create MediaStream from MediaStreamTrackGenerator
|
// Create MediaStream from MediaStreamTrackGenerator
|
||||||
let js_tracks = web_sys::js_sys::Array::new();
|
let js_tracks = web_sys::js_sys::Array::new();
|
||||||
js_tracks.push(&audio_stream_generator);
|
js_tracks.push(&audio_stream_generator);
|
||||||
let media_stream = MediaStream::new_with_tracks(&js_tracks).unwrap();
|
let media_stream = MediaStream::new_with_tracks(&js_tracks)?;
|
||||||
|
|
||||||
// Create MediaStreamAudioSourceNode
|
// Create MediaStreamAudioSourceNode
|
||||||
let audio_source = audio_context
|
let audio_source = audio_context.create_media_stream_source(&media_stream)?;
|
||||||
.create_media_stream_source(&media_stream)
|
|
||||||
.unwrap();
|
|
||||||
// Connect output of audio_source to audio_context (browser audio)
|
// Connect output of audio_source to audio_context (browser audio)
|
||||||
audio_source
|
audio_source.connect_with_audio_node(&audio_context.destination())?;
|
||||||
.connect_with_audio_node(&audio_context.destination())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Create callback functions for AudioDecoder
|
// Create callback functions for AudioDecoder
|
||||||
let error = Closure::wrap(Box::new(move |e: JsValue| {
|
let error = Closure::wrap(Box::new(move |e: JsValue| {
|
||||||
console::log_1(&e);
|
console::error_1(&e);
|
||||||
}) as Box<dyn FnMut(JsValue)>);
|
}) as Box<dyn FnMut(JsValue)>);
|
||||||
|
|
||||||
// This knows what MediaStreamTrackGenerator to use as it closes around it
|
// This knows what MediaStreamTrackGenerator to use as it closes around it
|
||||||
@@ -316,23 +315,22 @@ fn create_decoder(audio_context: &AudioContext) -> AudioDecoder {
|
|||||||
if let Err(e) = writable.get_writer().map(|writer| {
|
if let Err(e) = writable.get_writer().map(|writer| {
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
if let Err(e) = JsFuture::from(writer.ready()).await {
|
if let Err(e) = JsFuture::from(writer.ready()).await {
|
||||||
console::log_1(&format!("write chunk error {:?}", e).into());
|
console::error_1(&format!("write chunk ready error {:?}", e).into());
|
||||||
}
|
}
|
||||||
if let Err(e) = JsFuture::from(writer.write_with_chunk(&audio_data)).await {
|
if let Err(e) = JsFuture::from(writer.write_with_chunk(&audio_data)).await {
|
||||||
console::log_1(&format!("write chunk error {:?}", e).into());
|
console::error_1(&format!("write chunk error {:?}", e).into());
|
||||||
};
|
};
|
||||||
writer.release_lock();
|
writer.release_lock();
|
||||||
});
|
});
|
||||||
}) {
|
}) {
|
||||||
console::log_1(&e);
|
console::error_1(&e);
|
||||||
}
|
}
|
||||||
}) as Box<dyn FnMut(AudioData)>);
|
}) as Box<dyn FnMut(AudioData)>);
|
||||||
|
|
||||||
let audio_decoder = AudioDecoder::new(&AudioDecoderInit::new(
|
let audio_decoder = AudioDecoder::new(&AudioDecoderInit::new(
|
||||||
error.as_ref().unchecked_ref(),
|
error.as_ref().unchecked_ref(),
|
||||||
output.as_ref().unchecked_ref(),
|
output.as_ref().unchecked_ref(),
|
||||||
))
|
))?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
audio_decoder.configure(&AudioDecoderConfig::new("opus", 1, 48000));
|
audio_decoder.configure(&AudioDecoderConfig::new("opus", 1, 48000));
|
||||||
console::log_1(&"Created Audio Decoder".into());
|
console::log_1(&"Created Audio Decoder".into());
|
||||||
@@ -341,22 +339,7 @@ fn create_decoder(audio_context: &AudioContext) -> AudioDecoder {
|
|||||||
error.forget();
|
error.forget();
|
||||||
output.forget();
|
output.forget();
|
||||||
|
|
||||||
audio_decoder
|
Ok(audio_decoder)
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ConnectionState {
|
|
||||||
Disconnected,
|
|
||||||
Connecting,
|
|
||||||
Connected,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Command {
|
|
||||||
Connect {
|
|
||||||
address: String,
|
|
||||||
username: String,
|
|
||||||
hash: String,
|
|
||||||
},
|
|
||||||
Disconnect,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
|
pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
|
||||||
@@ -370,180 +353,195 @@ pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
|
|||||||
panic!("Did not receive connect command")
|
panic!("Did not receive connect command")
|
||||||
};
|
};
|
||||||
|
|
||||||
*STATE.server.write() = Default::default();
|
if let Err(error) = network_connect(address, username, &mut event_rx).await {
|
||||||
*STATE.status.write() = ConnectionState::Connecting;
|
console::error_1(&error);
|
||||||
|
|
||||||
console::log_1(&"Rust via WASM!".into());
|
|
||||||
|
|
||||||
let Ok(server_hash): Result<Vec<u8>, _> = env!("WEBTRANSPORT_SERVER_HASH")
|
|
||||||
.trim_matches(&['[', ']'])
|
|
||||||
.split(',')
|
|
||||||
.map(|x| x.trim().parse())
|
|
||||||
.collect()
|
|
||||||
else {
|
|
||||||
panic!("could not parse server hash")
|
|
||||||
};
|
|
||||||
let hash = web_sys::js_sys::Uint8Array::from(server_hash.as_slice());
|
|
||||||
|
|
||||||
let object = web_sys::js_sys::Object::new();
|
|
||||||
|
|
||||||
Reflect::set(
|
|
||||||
&object,
|
|
||||||
&JsValue::from_str("algorithm"),
|
|
||||||
&JsValue::from_str("sha-256"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
web_sys::js_sys::Reflect::set(&object, &"value".into(), &hash).unwrap();
|
|
||||||
|
|
||||||
let array = web_sys::js_sys::Array::new();
|
|
||||||
array.push(&object);
|
|
||||||
|
|
||||||
console::log_1(&object.clone().into());
|
|
||||||
console::log_1(&"Created option object!".into());
|
|
||||||
|
|
||||||
let mut options = WebTransportOptions::new();
|
|
||||||
options.server_certificate_hashes(&array);
|
|
||||||
|
|
||||||
console::log_1(&"Created WebTransportOptions!".into());
|
|
||||||
|
|
||||||
let transport = match WebTransport::new_with_options(&address, &options) {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(e) => {
|
|
||||||
console::log_1(&e.into());
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console::log_1(&"Created WebTransport connection object.".into());
|
|
||||||
|
|
||||||
console::log_1(&transport.clone().into());
|
|
||||||
|
|
||||||
if let Err(e) = wasm_bindgen_futures::JsFuture::from(transport.ready()).await {
|
|
||||||
console::log_1(&e.into());
|
|
||||||
panic!();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console::log_1(&"Transport is ready.".into());
|
macro_rules! bail {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
return Err(wasm_bindgen::JsError::new(&format!($($x)*)).into());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let stream: web_sys::WebTransportBidirectionalStream =
|
async fn network_connect(
|
||||||
match wasm_bindgen_futures::JsFuture::from(transport.create_bidirectional_stream())
|
address: String,
|
||||||
.await
|
username: String,
|
||||||
{
|
event_rx: &mut UnboundedReceiver<Command>,
|
||||||
Ok(x) => x.into(),
|
) -> Result<(), JsValue> {
|
||||||
Err(e) => {
|
*STATE.server.write() = Default::default();
|
||||||
console::log_1(&e.into());
|
*STATE.status.write() = ConnectionState::Connecting;
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let wasm_stream_readable = wasm_streams::ReadableStream::from_raw(stream.readable().into());
|
console::log_1(&"Rust via WASM!".into());
|
||||||
let wasm_stream_writable = wasm_streams::WritableStream::from_raw(stream.writable().into());
|
|
||||||
|
|
||||||
let read_codec = ClientControlCodec::new();
|
let Ok(server_hash): Result<Vec<u8>, _> = include_str!("../server_hash.txt")
|
||||||
let write_codec = ClientControlCodec::new();
|
.trim()
|
||||||
|
.trim_matches(&['[', ']'])
|
||||||
|
.split(',')
|
||||||
|
.map(|x| x.trim().parse())
|
||||||
|
.collect()
|
||||||
|
else {
|
||||||
|
bail!("could not parse server hash");
|
||||||
|
};
|
||||||
|
let hash = web_sys::js_sys::Uint8Array::from(server_hash.as_slice());
|
||||||
|
|
||||||
let mut reader =
|
let object = web_sys::js_sys::Object::new();
|
||||||
asynchronous_codec::FramedRead::new(wasm_stream_readable.into_async_read(), read_codec);
|
|
||||||
let mut writer = asynchronous_codec::FramedWrite::new(
|
|
||||||
wasm_stream_writable.into_async_write(),
|
|
||||||
write_codec,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (send_chan, writer_recv_chan) = async_std::channel::unbounded();
|
Reflect::set(
|
||||||
|
&object,
|
||||||
|
&JsValue::from_str("algorithm"),
|
||||||
|
&JsValue::from_str("sha-256"),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
web_sys::js_sys::Reflect::set(&object, &"value".into(), &hash)?;
|
||||||
|
|
||||||
|
let array = web_sys::js_sys::Array::new();
|
||||||
|
array.push(&object);
|
||||||
|
|
||||||
|
console::log_1(&object.clone().into());
|
||||||
|
console::log_1(&"Created option object!".into());
|
||||||
|
|
||||||
|
let mut options = WebTransportOptions::new();
|
||||||
|
options.server_certificate_hashes(&array);
|
||||||
|
|
||||||
|
console::log_1(&"Created WebTransportOptions!".into());
|
||||||
|
|
||||||
|
let transport = WebTransport::new_with_options(&address, &options)?;
|
||||||
|
console::log_1(&"Created WebTransport connection object.".into());
|
||||||
|
console::log_1(&transport.clone().into());
|
||||||
|
|
||||||
|
if let Err(e) = wasm_bindgen_futures::JsFuture::from(transport.ready()).await {
|
||||||
|
console::log_1(&e.into());
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
console::log_1(&"Transport is ready.".into());
|
||||||
|
|
||||||
|
let stream: WebTransportBidirectionalStream =
|
||||||
|
wasm_bindgen_futures::JsFuture::from(transport.create_bidirectional_stream())
|
||||||
|
.await?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let wasm_stream_readable = wasm_streams::ReadableStream::from_raw(stream.readable().into());
|
||||||
|
let wasm_stream_writable = wasm_streams::WritableStream::from_raw(stream.writable().into());
|
||||||
|
|
||||||
|
let read_codec = ClientControlCodec::new();
|
||||||
|
let write_codec = ClientControlCodec::new();
|
||||||
|
|
||||||
|
let mut reader =
|
||||||
|
asynchronous_codec::FramedRead::new(wasm_stream_readable.into_async_read(), read_codec);
|
||||||
|
let mut writer =
|
||||||
|
asynchronous_codec::FramedWrite::new(wasm_stream_writable.into_async_write(), write_codec);
|
||||||
|
|
||||||
|
let (mut send_chan, mut writer_recv_chan) = futures_channel::mpsc::unbounded();
|
||||||
|
|
||||||
|
spawn(async move {
|
||||||
|
while let Some(msg) = writer_recv_chan.next().await {
|
||||||
|
if let Err(e) = writer.send(msg).await {
|
||||||
|
console::error_1(&e.to_string().into());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get version packet
|
||||||
|
let version = match reader.next().await {
|
||||||
|
Some(Ok(v)) => v,
|
||||||
|
Some(Err(err)) => bail!("bad version packet: {err:?}"),
|
||||||
|
None => bail!("no version was recieved"),
|
||||||
|
};
|
||||||
|
console::log_1(&"Got version packet".into());
|
||||||
|
console::log_1(&format!("{:#?}", version).into());
|
||||||
|
|
||||||
|
// Send version packet
|
||||||
|
let mut msg = msgs::Version::new();
|
||||||
|
msg.set_version(0x000010204);
|
||||||
|
msg.set_release(format!("{} {}", "mumbleweb2", "6.9.0"));
|
||||||
|
//msg.set_os("Chrome".to_string());
|
||||||
|
send_chan.send(msg.into()).await.unwrap();
|
||||||
|
console::log_1(&"Sent version packet".into());
|
||||||
|
|
||||||
|
// Send authenticate packet
|
||||||
|
let mut msg = msgs::Authenticate::new();
|
||||||
|
msg.set_username(username);
|
||||||
|
msg.set_opus(true);
|
||||||
|
send_chan.send(msg.into()).await.unwrap();
|
||||||
|
console::log_1(&"Sent authenticate packet".into());
|
||||||
|
|
||||||
|
// Spawn worker to send pings
|
||||||
|
{
|
||||||
|
let mut send_chan = send_chan.clone();
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
while let Ok(msg) = writer_recv_chan.recv().await {
|
loop {
|
||||||
if let Err(e) = writer.send(msg).await {
|
console::log_1(&"Sending ping".into());
|
||||||
|
if let Err(e) = send_chan.send(msgs::Ping::new().into()).await {
|
||||||
|
console::log_1(&"could not ping".into());
|
||||||
console::log_1(&e.to_string().into());
|
console::log_1(&e.to_string().into());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeoutFuture::new(3000).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get version packet
|
|
||||||
let version = reader.next().await.unwrap().unwrap();
|
|
||||||
console::log_1(&"Got version packet".into());
|
|
||||||
console::log_1(&format!("{:#?}", version).into());
|
|
||||||
|
|
||||||
// Send version packet
|
|
||||||
let mut msg = msgs::Version::new();
|
|
||||||
msg.set_version(0x000010204);
|
|
||||||
msg.set_release(format!("{} {}", "mumbleweb2", "6.9.0"));
|
|
||||||
//msg.set_os("Chrome".to_string());
|
|
||||||
send_chan.send(msg.into()).await.unwrap();
|
|
||||||
console::log_1(&"Sent version packet".into());
|
|
||||||
|
|
||||||
// Send authenticate packet
|
|
||||||
let mut msg = msgs::Authenticate::new();
|
|
||||||
msg.set_username(username);
|
|
||||||
msg.set_opus(true);
|
|
||||||
send_chan.send(msg.into()).await.unwrap();
|
|
||||||
console::log_1(&"Sent authenticate packet".into());
|
|
||||||
|
|
||||||
// Spawn worker to send pings
|
|
||||||
{
|
|
||||||
let send_chan = send_chan.clone();
|
|
||||||
spawn(async move {
|
|
||||||
loop {
|
|
||||||
console::log_1(&"Sending ping".into());
|
|
||||||
if let Err(e) = send_chan.send(msgs::Ping::new().into()).await {
|
|
||||||
console::log_1(&"could not ping".into());
|
|
||||||
console::log_1(&e.to_string().into());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
async_std::task::sleep(Duration::from_millis(3000)).await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create MediaStreams to playback decoded audio
|
|
||||||
// The audio context is used to reproduce audio.
|
|
||||||
let audio_context = configure_audio_context();
|
|
||||||
|
|
||||||
let audio_context_worklet = audio_context.clone();
|
|
||||||
let packet_sender_worklet = send_chan.clone();
|
|
||||||
spawn(async move {
|
|
||||||
match create_encoder_worklet(&audio_context_worklet, packet_sender_worklet).await {
|
|
||||||
Ok(node) => console::log_2(&"Created audio worklet:".into(), &node),
|
|
||||||
Err(err) => console::error_1(&err),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
*STATE.status.write() = ConnectionState::Connected;
|
|
||||||
|
|
||||||
// Create map of session_id -> AudioDecoder
|
|
||||||
let mut decoder_map = HashMap::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
select! {
|
|
||||||
packet = reader.next().fuse() => {
|
|
||||||
match packet {
|
|
||||||
Some(Ok(msg)) => accept_packet(msg, &audio_context, &mut decoder_map),
|
|
||||||
Some(Err(err)) => panic!("{err}"),
|
|
||||||
None => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
command = event_rx.next() => {
|
|
||||||
match command {
|
|
||||||
Some(Command::Disconnect) => break,
|
|
||||||
_ => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send_chan.close();
|
|
||||||
*STATE.status.write() = ConnectionState::Disconnected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create MediaStreams to playback decoded audio
|
||||||
|
// The audio context is used to reproduce audio.
|
||||||
|
let audio_context = configure_audio_context();
|
||||||
|
|
||||||
|
let audio_context_worklet = audio_context.clone();
|
||||||
|
let packet_sender_worklet = send_chan.clone();
|
||||||
|
spawn(async move {
|
||||||
|
match create_encoder_worklet(&audio_context_worklet, packet_sender_worklet).await {
|
||||||
|
Ok(node) => console::log_2(&"Created audio worklet:".into(), &node),
|
||||||
|
Err(err) => console::error_1(&err),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create map of session_id -> AudioDecoder
|
||||||
|
let mut decoder_map = HashMap::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
select! {
|
||||||
|
packet = reader.next().fuse() => {
|
||||||
|
match packet {
|
||||||
|
Some(Ok(msg)) => {
|
||||||
|
let res =accept_packet(msg, &audio_context, &mut decoder_map);
|
||||||
|
if let Err(err) = res {
|
||||||
|
console::error_1(&err.into());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(Err(err)) => console::error_1(&err.to_string().into()),
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command = event_rx.next() => {
|
||||||
|
match command {
|
||||||
|
Some(Command::Disconnect) => break,
|
||||||
|
Some(Command::SendChat { markdown, channels }) => {
|
||||||
|
let html_text = markdown::to_html(&markdown);
|
||||||
|
let mut u = msgs::TextMessage::new();
|
||||||
|
u.set_message(html_text);
|
||||||
|
u.set_channel_id(channels);
|
||||||
|
let _ = send_chan.send(u.into());
|
||||||
|
},
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send_chan.close();
|
||||||
|
*STATE.status.write() = ConnectionState::Disconnected;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_packet(
|
fn accept_packet(
|
||||||
msg: ControlPacket<mumble_protocol::Clientbound>,
|
msg: ControlPacket<mumble_protocol::Clientbound>,
|
||||||
audio_context: &AudioContext,
|
audio_context: &AudioContext,
|
||||||
decoder_map: &mut HashMap<u32, AudioDecoder>,
|
decoder_map: &mut HashMap<u32, AudioDecoder>,
|
||||||
) {
|
) -> Result<(), JsValue> {
|
||||||
if !matches!(msg, ControlPacket::UDPTunnel(_)) {
|
if !matches!(msg, ControlPacket::UDPTunnel(_) | ControlPacket::Ping(_)) {
|
||||||
console::log_1(&format!("{:#?}", msg).into());
|
console::log_1(&format!("{:#?}", msg).into());
|
||||||
}
|
}
|
||||||
match msg {
|
match msg {
|
||||||
@@ -558,9 +556,12 @@ fn accept_packet(
|
|||||||
position_info,
|
position_info,
|
||||||
} => {
|
} => {
|
||||||
// Get or create audio decoder for this user
|
// Get or create audio decoder for this user
|
||||||
let audio_decoder = decoder_map
|
let audio_decoder = match decoder_map.entry(session_id) {
|
||||||
.entry(session_id)
|
Entry::Occupied(occupied_entry) => occupied_entry.into_mut(),
|
||||||
.or_insert_with(|| create_decoder(&audio_context));
|
Entry::Vacant(vacant_entry) => {
|
||||||
|
vacant_entry.insert(create_decoder(&audio_context)?)
|
||||||
|
}
|
||||||
|
};
|
||||||
// This will over time (as users join and leave) leak
|
// This will over time (as users join and leave) leak
|
||||||
// AudioDecoders, MediaStreamTrackGenerators, MediaStreams, and MediaStreamAudioSourceNodes.
|
// AudioDecoders, MediaStreamTrackGenerators, MediaStreams, and MediaStreamAudioSourceNodes.
|
||||||
// A better way to handle this would be to delete and create all the audio
|
// A better way to handle this would be to delete and create all the audio
|
||||||
@@ -568,7 +569,7 @@ fn accept_packet(
|
|||||||
// any audio packets that come in the meantime.
|
// any audio packets that come in the meantime.
|
||||||
if let VoicePacketPayload::Opus(audio_payload, end_bit) = payload {
|
if let VoicePacketPayload::Opus(audio_payload, end_bit) = payload {
|
||||||
let js_audio_payload = Uint8Array::from(audio_payload.as_ref());
|
let js_audio_payload = Uint8Array::from(audio_payload.as_ref());
|
||||||
audio_decoder.decode(
|
let _ = audio_decoder.decode(
|
||||||
&EncodedAudioChunk::new(&EncodedAudioChunkInit::new(
|
&EncodedAudioChunk::new(&EncodedAudioChunkInit::new(
|
||||||
&js_audio_payload.into(),
|
&js_audio_payload.into(),
|
||||||
0.0,
|
0.0,
|
||||||
@@ -668,10 +669,27 @@ fn accept_packet(
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
dangerous_html: html_purifier::purifier(&text, Default::default()),
|
dangerous_html: html_purifier::purifier(&text, Default::default()),
|
||||||
text: text,
|
raw: text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ControlPacket::ServerSync(u) => {
|
||||||
|
*STATE.status.write() = ConnectionState::Connected;
|
||||||
|
let mut server = STATE.server.write();
|
||||||
|
if u.has_welcome_text() {
|
||||||
|
let text = u.get_welcome_text().to_string();
|
||||||
|
server.chat.push(Chat {
|
||||||
|
sender: None,
|
||||||
|
dangerous_html: html_purifier::purifier(&text, Default::default()),
|
||||||
|
raw: text,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if u.has_session() {
|
||||||
|
server.session = Some(u.get_session());
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user