init
This commit is contained in:
commit
0d69c204bb
8 changed files with 2460 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
981
Cargo.lock
generated
Normal file
981
Cargo.lock
generated
Normal file
|
@ -0,0 +1,981 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alsa"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce34de545ad29bcc00cb1b87a94c132256dcf83aa7eeb9674482568405a6ff0a"
|
||||||
|
dependencies = [
|
||||||
|
"alsa-sys",
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"libc",
|
||||||
|
"nix",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alsa-sys"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "audiopus_sys"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651"
|
||||||
|
dependencies = [
|
||||||
|
"cmake",
|
||||||
|
"log",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.66.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"cexpr",
|
||||||
|
"clang-sys",
|
||||||
|
"lazy_static",
|
||||||
|
"lazycell",
|
||||||
|
"peeking_take_while",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash",
|
||||||
|
"shlex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.83"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-expr"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6100bc57b6209840798d95cb2775684849d332f7bd788db2a8c8caf7ef82a41a"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cmake"
|
||||||
|
version = "0.1.50"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cookie-factory"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "home"
|
||||||
|
version = "0.5.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazycell"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.152"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libspa"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0434617020ddca18b86067912970c55410ca654cdafd775480322f50b857a8c4"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"cc",
|
||||||
|
"convert_case",
|
||||||
|
"cookie-factory",
|
||||||
|
"libc",
|
||||||
|
"libspa-sys",
|
||||||
|
"nix",
|
||||||
|
"nom",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libspa-sys"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3e70ca3f3e70f858ef363046d06178c427b4e0b63d210c95fd87d752679d345"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"cc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multimap"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mumble-foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"alsa",
|
||||||
|
"anyhow",
|
||||||
|
"opus",
|
||||||
|
"pipewire",
|
||||||
|
"prost",
|
||||||
|
"prost-build",
|
||||||
|
"rustls",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"memoffset",
|
||||||
|
"pin-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opus"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6526409b274a7e98e55ff59d96aafd38e6cd34d46b7dbbc32ce126dffcd75e8e"
|
||||||
|
dependencies = [
|
||||||
|
"audiopus_sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peeking_take_while"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pipewire"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2d009c8dd65e890b515a71950f7e4c801523b8894ff33863a40830bf762e9e9"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"libc",
|
||||||
|
"libspa",
|
||||||
|
"libspa-sys",
|
||||||
|
"nix",
|
||||||
|
"once_cell",
|
||||||
|
"pipewire-sys",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pipewire-sys"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "890c084e7b737246cb4799c86b71a0e4da536031ff7473dd639eba9f95039f64"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"libspa-sys",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettyplease"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.76"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"prost-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-build"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"heck",
|
||||||
|
"itertools",
|
||||||
|
"log",
|
||||||
|
"multimap",
|
||||||
|
"once_cell",
|
||||||
|
"petgraph",
|
||||||
|
"prettyplease",
|
||||||
|
"prost",
|
||||||
|
"prost-types",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
"tempfile",
|
||||||
|
"which",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-derive"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-types"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e"
|
||||||
|
dependencies = [
|
||||||
|
"prost",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"getrandom",
|
||||||
|
"libc",
|
||||||
|
"spin",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.22.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.102.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef4ca26037c909dedb327b48c3327d0ba91d3dd3c4e05dad328f210ffb68e95b"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.195"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.195"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-deps"
|
||||||
|
version = "6.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-expr",
|
||||||
|
"heck",
|
||||||
|
"pkg-config",
|
||||||
|
"toml",
|
||||||
|
"version-compare",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "target-lexicon"
|
||||||
|
version = "0.12.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"redox_syscall",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version-compare"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "which"
|
||||||
|
version = "4.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"home",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
|
"windows_aarch64_msvc 0.48.5",
|
||||||
|
"windows_i686_gnu 0.48.5",
|
||||||
|
"windows_i686_msvc 0.48.5",
|
||||||
|
"windows_x86_64_gnu 0.48.5",
|
||||||
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
|
"windows_x86_64_msvc 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.0",
|
||||||
|
"windows_aarch64_msvc 0.52.0",
|
||||||
|
"windows_i686_gnu 0.52.0",
|
||||||
|
"windows_i686_msvc 0.52.0",
|
||||||
|
"windows_x86_64_gnu 0.52.0",
|
||||||
|
"windows_x86_64_gnullvm 0.52.0",
|
||||||
|
"windows_x86_64_msvc 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.5.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "mumble-foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
alsa = "0.8.1"
|
||||||
|
pipewire = "0.7.2"
|
||||||
|
opus = "0.3.0"
|
||||||
|
anyhow = "1.0.79"
|
||||||
|
rustls = "0.22.2"
|
||||||
|
prost = "0.12.3"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
prost-build = "0.12.3"
|
5
build.rs
Normal file
5
build.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use std::io::Result;
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
prost_build::compile_protos(&["proto/Mumble.proto"], &["proto/"])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
621
proto/Mumble.proto
Normal file
621
proto/Mumble.proto
Normal file
|
@ -0,0 +1,621 @@
|
||||||
|
// Copyright 2009-2023 The Mumble Developers. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license
|
||||||
|
// that can be found in the LICENSE file at the root of the
|
||||||
|
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package MumbleProto;
|
||||||
|
|
||||||
|
option optimize_for = SPEED;
|
||||||
|
|
||||||
|
message Version {
|
||||||
|
// Legacy version number format.
|
||||||
|
optional uint32 version_v1 = 1;
|
||||||
|
// New version number format.
|
||||||
|
// Necessary since patch level may exceed 255. (See https://github.com/mumble-voip/mumble/issues/5827)
|
||||||
|
optional uint64 version_v2 = 5;
|
||||||
|
|
||||||
|
// Client release name.
|
||||||
|
optional string release = 2;
|
||||||
|
// Client OS name.
|
||||||
|
optional string os = 3;
|
||||||
|
// Client OS version.
|
||||||
|
optional string os_version = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not used. Not even for tunneling UDP through TCP.
|
||||||
|
message UDPTunnel {
|
||||||
|
// Not used.
|
||||||
|
required bytes packet = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the client to send the authentication credentials to the server.
|
||||||
|
message Authenticate {
|
||||||
|
// UTF-8 encoded username.
|
||||||
|
optional string username = 1;
|
||||||
|
// Server or user password.
|
||||||
|
optional string password = 2;
|
||||||
|
// Additional access tokens for server ACL groups.
|
||||||
|
repeated string tokens = 3;
|
||||||
|
// A list of CELT bitstream version constants supported by the client.
|
||||||
|
repeated int32 celt_versions = 4;
|
||||||
|
optional bool opus = 5 [default = false];
|
||||||
|
// 0 = REGULAR, 1 = BOT
|
||||||
|
optional int32 client_type = 6 [default = 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the client to notify the server that the client is still alive.
|
||||||
|
// Server must reply to the packet with the same timestamp and its own
|
||||||
|
// good/late/lost/resync numbers. None of the fields is strictly required.
|
||||||
|
message Ping {
|
||||||
|
// Client timestamp. Server should not attempt to decode.
|
||||||
|
optional uint64 timestamp = 1;
|
||||||
|
// The amount of good packets received.
|
||||||
|
optional uint32 good = 2;
|
||||||
|
// The amount of late packets received.
|
||||||
|
optional uint32 late = 3;
|
||||||
|
// The amount of packets never received.
|
||||||
|
optional uint32 lost = 4;
|
||||||
|
// The amount of nonce resyncs.
|
||||||
|
optional uint32 resync = 5;
|
||||||
|
// The total amount of UDP packets received.
|
||||||
|
optional uint32 udp_packets = 6;
|
||||||
|
// The total amount of TCP packets received.
|
||||||
|
optional uint32 tcp_packets = 7;
|
||||||
|
// UDP ping average.
|
||||||
|
optional float udp_ping_avg = 8;
|
||||||
|
// UDP ping variance.
|
||||||
|
optional float udp_ping_var = 9;
|
||||||
|
// TCP ping average.
|
||||||
|
optional float tcp_ping_avg = 10;
|
||||||
|
// TCP ping variance.
|
||||||
|
optional float tcp_ping_var = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the server when it rejects the user connection.
|
||||||
|
message Reject {
|
||||||
|
enum RejectType {
|
||||||
|
// The rejection reason is unknown (details should be available
|
||||||
|
// in Reject.reason).
|
||||||
|
None = 0;
|
||||||
|
// The client attempted to connect with an incompatible version.
|
||||||
|
WrongVersion = 1;
|
||||||
|
// The user name supplied by the client was invalid.
|
||||||
|
InvalidUsername = 2;
|
||||||
|
// The client attempted to authenticate as a user with a password but it
|
||||||
|
// was wrong.
|
||||||
|
WrongUserPW = 3;
|
||||||
|
// The client attempted to connect to a passworded server but the password
|
||||||
|
// was wrong.
|
||||||
|
WrongServerPW = 4;
|
||||||
|
// Supplied username is already in use.
|
||||||
|
UsernameInUse = 5;
|
||||||
|
// Server is currently full and cannot accept more users.
|
||||||
|
ServerFull = 6;
|
||||||
|
// The user did not provide a certificate but one is required.
|
||||||
|
NoCertificate = 7;
|
||||||
|
AuthenticatorFail = 8;
|
||||||
|
}
|
||||||
|
// Rejection type.
|
||||||
|
optional RejectType type = 1;
|
||||||
|
// Human readable rejection reason.
|
||||||
|
optional string reason = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerSync message is sent by the server when it has authenticated the user
|
||||||
|
// and finished synchronizing the server state.
|
||||||
|
message ServerSync {
|
||||||
|
// The session of the current user.
|
||||||
|
optional uint32 session = 1;
|
||||||
|
// Maximum bandwidth that the user should use.
|
||||||
|
optional uint32 max_bandwidth = 2;
|
||||||
|
// Server welcome text.
|
||||||
|
optional string welcome_text = 3;
|
||||||
|
// Current user permissions in the root channel.
|
||||||
|
// Note: The permissions data type usually is uin32 (e.g. in PermissionQuery and PermissionDenied messages). Here
|
||||||
|
// it is uint64 because of an oversight in the past. Nonetheless it should never exceed the uin32 range.
|
||||||
|
// See also: https://github.com/mumble-voip/mumble/issues/5139
|
||||||
|
optional uint64 permissions = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the client when it wants a channel removed. Sent by the server when
|
||||||
|
// a channel has been removed and clients should be notified.
|
||||||
|
message ChannelRemove {
|
||||||
|
required uint32 channel_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to communicate channel properties between the client and the server.
|
||||||
|
// Sent by the server during the login process or when channel properties are
|
||||||
|
// updated. Client may use this message to update said channel properties.
|
||||||
|
message ChannelState {
|
||||||
|
// Unique ID for the channel within the server.
|
||||||
|
optional uint32 channel_id = 1;
|
||||||
|
// channel_id of the parent channel.
|
||||||
|
optional uint32 parent = 2;
|
||||||
|
// UTF-8 encoded channel name.
|
||||||
|
optional string name = 3;
|
||||||
|
// A collection of channel id values of the linked channels. Absent during
|
||||||
|
// the first channel listing.
|
||||||
|
repeated uint32 links = 4;
|
||||||
|
// UTF-8 encoded channel description. Only if the description is less than
|
||||||
|
// 128 bytes
|
||||||
|
optional string description = 5;
|
||||||
|
// A collection of channel_id values that should be added to links.
|
||||||
|
repeated uint32 links_add = 6;
|
||||||
|
// A collection of channel_id values that should be removed from links.
|
||||||
|
repeated uint32 links_remove = 7;
|
||||||
|
// True if the channel is temporary.
|
||||||
|
optional bool temporary = 8 [default = false];
|
||||||
|
// Position weight to tweak the channel position in the channel list.
|
||||||
|
optional int32 position = 9 [default = 0];
|
||||||
|
// SHA1 hash of the description if the description is 128 bytes or more.
|
||||||
|
optional bytes description_hash = 10;
|
||||||
|
// Maximum number of users allowed in the channel. If this value is zero,
|
||||||
|
// the maximum number of users allowed in the channel is given by the
|
||||||
|
// server's "usersperchannel" setting.
|
||||||
|
optional uint32 max_users = 11;
|
||||||
|
// Whether this channel has enter restrictions (ACL denying ENTER) set
|
||||||
|
optional bool is_enter_restricted = 12;
|
||||||
|
// Whether the receiver of this msg is considered to be able to enter this channel
|
||||||
|
optional bool can_enter = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to communicate user leaving or being kicked. May be sent by the client
|
||||||
|
// when it attempts to kick a user. Sent by the server when it informs the
|
||||||
|
// clients that a user is not present anymore.
|
||||||
|
message UserRemove {
|
||||||
|
// The user who is being kicked, identified by their session, not present
|
||||||
|
// when no one is being kicked.
|
||||||
|
required uint32 session = 1;
|
||||||
|
// The user who initiated the removal. Either the user who performs the kick
|
||||||
|
// or the user who is currently leaving.
|
||||||
|
optional uint32 actor = 2;
|
||||||
|
// Reason for the kick, stored as the ban reason if the user is banned.
|
||||||
|
optional string reason = 3;
|
||||||
|
// True if the kick should result in a ban.
|
||||||
|
optional bool ban = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the server when it communicates new and changed users to client.
|
||||||
|
// First seen during login procedure. May be sent by the client when it wishes
|
||||||
|
// to alter its state.
|
||||||
|
message UserState {
|
||||||
|
message VolumeAdjustment {
|
||||||
|
optional uint32 listening_channel = 1;
|
||||||
|
optional float volume_adjustment = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unique user session ID of the user whose state this is, may change on
|
||||||
|
// reconnect.
|
||||||
|
optional uint32 session = 1;
|
||||||
|
// The session of the user who is updating this user.
|
||||||
|
optional uint32 actor = 2;
|
||||||
|
// User name, UTF-8 encoded.
|
||||||
|
optional string name = 3;
|
||||||
|
// Registered user ID if the user is registered.
|
||||||
|
optional uint32 user_id = 4;
|
||||||
|
// Channel on which the user is.
|
||||||
|
optional uint32 channel_id = 5;
|
||||||
|
// True if the user is muted by admin.
|
||||||
|
optional bool mute = 6;
|
||||||
|
// True if the user is deafened by admin.
|
||||||
|
optional bool deaf = 7;
|
||||||
|
// True if the user has been suppressed from talking by a reason other than
|
||||||
|
// being muted.
|
||||||
|
optional bool suppress = 8;
|
||||||
|
// True if the user has muted self.
|
||||||
|
optional bool self_mute = 9;
|
||||||
|
// True if the user has deafened self.
|
||||||
|
optional bool self_deaf = 10;
|
||||||
|
// User image if it is less than 128 bytes.
|
||||||
|
optional bytes texture = 11;
|
||||||
|
// The positional audio plugin identifier.
|
||||||
|
// Positional audio information is only sent to users who share
|
||||||
|
// identical plugin contexts.
|
||||||
|
//
|
||||||
|
// This value is not transmitted to clients.
|
||||||
|
optional bytes plugin_context = 12;
|
||||||
|
// The user's plugin-specific identity.
|
||||||
|
// This value is not transmitted to clients.
|
||||||
|
optional string plugin_identity = 13;
|
||||||
|
// User comment if it is less than 128 bytes.
|
||||||
|
optional string comment = 14;
|
||||||
|
// The hash of the user certificate.
|
||||||
|
optional string hash = 15;
|
||||||
|
// SHA1 hash of the user comment if it 128 bytes or more.
|
||||||
|
optional bytes comment_hash = 16;
|
||||||
|
// SHA1 hash of the user picture if it 128 bytes or more.
|
||||||
|
optional bytes texture_hash = 17;
|
||||||
|
// True if the user is a priority speaker.
|
||||||
|
optional bool priority_speaker = 18;
|
||||||
|
// True if the user is currently recording.
|
||||||
|
optional bool recording = 19;
|
||||||
|
// A list of temporary access tokens to be respected when processing this request.
|
||||||
|
repeated string temporary_access_tokens = 20;
|
||||||
|
// A list of channels the user wants to start listening to.
|
||||||
|
repeated uint32 listening_channel_add = 21;
|
||||||
|
// a list of channels the user does no longer want to listen to.
|
||||||
|
repeated uint32 listening_channel_remove = 22;
|
||||||
|
// A list of volume adjustments the user has applied to listeners
|
||||||
|
repeated VolumeAdjustment listening_volume_adjustment = 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relays information on the bans. The client may send the BanList message to
|
||||||
|
// either modify the list of bans or query them from the server. The server
|
||||||
|
// sends this list only after a client queries for it.
|
||||||
|
message BanList {
|
||||||
|
message BanEntry {
|
||||||
|
// Banned IP address.
|
||||||
|
required bytes address = 1;
|
||||||
|
// The length of the subnet mask for the ban.
|
||||||
|
required uint32 mask = 2;
|
||||||
|
// User name for identification purposes (does not affect the ban).
|
||||||
|
optional string name = 3;
|
||||||
|
// The certificate hash of the banned user.
|
||||||
|
optional string hash = 4;
|
||||||
|
// Reason for the ban (does not affect the ban).
|
||||||
|
optional string reason = 5;
|
||||||
|
// Ban start time.
|
||||||
|
optional string start = 6;
|
||||||
|
// Ban duration in seconds.
|
||||||
|
optional uint32 duration = 7;
|
||||||
|
}
|
||||||
|
// List of ban entries currently in place.
|
||||||
|
repeated BanEntry bans = 1;
|
||||||
|
// True if the server should return the list, false if it should replace old
|
||||||
|
// ban list with the one provided.
|
||||||
|
optional bool query = 2 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to send and broadcast text messages.
|
||||||
|
message TextMessage {
|
||||||
|
// The message sender, identified by its session.
|
||||||
|
optional uint32 actor = 1;
|
||||||
|
// Target users for the message, identified by their session.
|
||||||
|
repeated uint32 session = 2;
|
||||||
|
// The channels to which the message is sent, identified by their
|
||||||
|
// channel_ids.
|
||||||
|
repeated uint32 channel_id = 3;
|
||||||
|
// The root channels when sending message recursively to several channels,
|
||||||
|
// identified by their channel_ids.
|
||||||
|
repeated uint32 tree_id = 4;
|
||||||
|
// The UTF-8 encoded message. May be HTML if the server allows.
|
||||||
|
required string message = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PermissionDenied {
|
||||||
|
enum DenyType {
|
||||||
|
// Operation denied for other reason, see reason field.
|
||||||
|
Text = 0;
|
||||||
|
// Permissions were denied.
|
||||||
|
Permission = 1;
|
||||||
|
// Cannot modify SuperUser.
|
||||||
|
SuperUser = 2;
|
||||||
|
// Invalid channel name.
|
||||||
|
ChannelName = 3;
|
||||||
|
// Text message too long.
|
||||||
|
TextTooLong = 4;
|
||||||
|
// The flux capacitor was spelled wrong.
|
||||||
|
H9K = 5;
|
||||||
|
// Operation not permitted in temporary channel.
|
||||||
|
TemporaryChannel = 6;
|
||||||
|
// Operation requires certificate.
|
||||||
|
MissingCertificate = 7;
|
||||||
|
// Invalid username.
|
||||||
|
UserName = 8;
|
||||||
|
// Channel is full.
|
||||||
|
ChannelFull = 9;
|
||||||
|
// Channels are nested too deeply.
|
||||||
|
NestingLimit = 10;
|
||||||
|
// Maximum channel count reached.
|
||||||
|
ChannelCountLimit = 11;
|
||||||
|
// Amount of listener objects for this channel has been reached
|
||||||
|
ChannelListenerLimit = 12;
|
||||||
|
// Amount of listener proxies for the user has been reached
|
||||||
|
UserListenerLimit = 13;
|
||||||
|
}
|
||||||
|
// The denied permission when type is Permission.
|
||||||
|
optional uint32 permission = 1;
|
||||||
|
// channel_id for the channel where the permission was denied when type is
|
||||||
|
// Permission.
|
||||||
|
optional uint32 channel_id = 2;
|
||||||
|
// The user who was denied permissions, identified by session.
|
||||||
|
optional uint32 session = 3;
|
||||||
|
// Textual reason for the denial.
|
||||||
|
optional string reason = 4;
|
||||||
|
// Type of the denial.
|
||||||
|
optional DenyType type = 5;
|
||||||
|
// The name that is invalid when type is UserName.
|
||||||
|
optional string name = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ACL {
|
||||||
|
message ChanGroup {
|
||||||
|
// Name of the channel group, UTF-8 encoded.
|
||||||
|
required string name = 1;
|
||||||
|
// True if the group has been inherited from the parent (Read only).
|
||||||
|
optional bool inherited = 2 [default = true];
|
||||||
|
// True if the group members are inherited.
|
||||||
|
optional bool inherit = 3 [default = true];
|
||||||
|
// True if the group can be inherited by sub channels.
|
||||||
|
optional bool inheritable = 4 [default = true];
|
||||||
|
// Users explicitly included in this group, identified by user_id.
|
||||||
|
repeated uint32 add = 5;
|
||||||
|
// Users explicitly removed from this group in this channel if the group
|
||||||
|
// has been inherited, identified by user_id.
|
||||||
|
repeated uint32 remove = 6;
|
||||||
|
// Users inherited, identified by user_id.
|
||||||
|
repeated uint32 inherited_members = 7;
|
||||||
|
}
|
||||||
|
message ChanACL {
|
||||||
|
// True if this ACL applies to the current channel.
|
||||||
|
optional bool apply_here = 1 [default = true];
|
||||||
|
// True if this ACL applies to the sub channels.
|
||||||
|
optional bool apply_subs = 2 [default = true];
|
||||||
|
// True if the ACL has been inherited from the parent.
|
||||||
|
optional bool inherited = 3 [default = true];
|
||||||
|
// ID of the user that is affected by this ACL.
|
||||||
|
optional uint32 user_id = 4;
|
||||||
|
// ID of the group that is affected by this ACL.
|
||||||
|
optional string group = 5;
|
||||||
|
// Bit flag field of the permissions granted by this ACL.
|
||||||
|
optional uint32 grant = 6;
|
||||||
|
// Bit flag field of the permissions denied by this ACL.
|
||||||
|
optional uint32 deny = 7;
|
||||||
|
}
|
||||||
|
// Channel ID of the channel this message affects.
|
||||||
|
required uint32 channel_id = 1;
|
||||||
|
// True if the channel inherits its parent's ACLs.
|
||||||
|
optional bool inherit_acls = 2 [default = true];
|
||||||
|
// User group specifications.
|
||||||
|
repeated ChanGroup groups = 3;
|
||||||
|
// ACL specifications.
|
||||||
|
repeated ChanACL acls = 4;
|
||||||
|
// True if the message is a query for ACLs instead of setting them.
|
||||||
|
optional bool query = 5 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client may use this message to refresh its registered user information. The
|
||||||
|
// client should fill the IDs or Names of the users it wants to refresh. The
|
||||||
|
// server fills the missing parts and sends the message back.
|
||||||
|
message QueryUsers {
|
||||||
|
// user_ids.
|
||||||
|
repeated uint32 ids = 1;
|
||||||
|
// User names in the same order as ids.
|
||||||
|
repeated string names = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to initialize and resync the UDP encryption. Either side may request a
|
||||||
|
// resync by sending the message without any values filled. The resync is
|
||||||
|
// performed by sending the message with only the client or server nonce
|
||||||
|
// filled.
|
||||||
|
message CryptSetup {
|
||||||
|
// Encryption key.
|
||||||
|
optional bytes key = 1;
|
||||||
|
// Client nonce.
|
||||||
|
optional bytes client_nonce = 2;
|
||||||
|
// Server nonce.
|
||||||
|
optional bytes server_nonce = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to add or remove custom context menu item on client-side.
|
||||||
|
message ContextActionModify {
|
||||||
|
enum Context {
|
||||||
|
// Action is applicable to the server.
|
||||||
|
Server = 0x01;
|
||||||
|
// Action can target a Channel.
|
||||||
|
Channel = 0x02;
|
||||||
|
// Action can target a User.
|
||||||
|
User = 0x04;
|
||||||
|
}
|
||||||
|
enum Operation {
|
||||||
|
Add = 0;
|
||||||
|
Remove = 1;
|
||||||
|
}
|
||||||
|
// The action identifier. Used later to initiate an action.
|
||||||
|
required string action = 1;
|
||||||
|
// The display name of the action.
|
||||||
|
optional string text = 2;
|
||||||
|
// Context bit flags defining where the action should be displayed.
|
||||||
|
// Flags can be OR-ed to combine different types.
|
||||||
|
optional uint32 context = 3;
|
||||||
|
// Choose either to add or to remove the context action.
|
||||||
|
// Note: This field only exists after Mumble 1.2.4-beta1 release.
|
||||||
|
// The message will be recognized as Add regardless of this field
|
||||||
|
// before said release.
|
||||||
|
optional Operation operation = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the client when it wants to initiate a Context action.
|
||||||
|
message ContextAction {
|
||||||
|
// The target User for the action, identified by session.
|
||||||
|
optional uint32 session = 1;
|
||||||
|
// The target Channel for the action, identified by channel_id.
|
||||||
|
optional uint32 channel_id = 2;
|
||||||
|
// The action that should be executed.
|
||||||
|
required string action = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lists the registered users.
|
||||||
|
message UserList {
|
||||||
|
message User {
|
||||||
|
// Registered user ID.
|
||||||
|
required uint32 user_id = 1;
|
||||||
|
// Registered user name.
|
||||||
|
optional string name = 2;
|
||||||
|
optional string last_seen = 3;
|
||||||
|
optional uint32 last_channel = 4;
|
||||||
|
}
|
||||||
|
// A list of registered users.
|
||||||
|
repeated User users = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the client when it wants to register or clear whisper targets.
|
||||||
|
//
|
||||||
|
// Note: The first available target ID is 1 as 0 is reserved for normal
|
||||||
|
// talking. Maximum target ID is 30.
|
||||||
|
message VoiceTarget {
|
||||||
|
message Target {
|
||||||
|
// Users that are included as targets.
|
||||||
|
repeated uint32 session = 1;
|
||||||
|
// Channel that is included as a target.
|
||||||
|
optional uint32 channel_id = 2;
|
||||||
|
// ACL group that is included as a target.
|
||||||
|
optional string group = 3;
|
||||||
|
// True if the voice should follow links from the specified channel.
|
||||||
|
optional bool links = 4 [default = false];
|
||||||
|
// True if the voice should also be sent to children of the specific
|
||||||
|
// channel.
|
||||||
|
optional bool children = 5 [default = false];
|
||||||
|
}
|
||||||
|
// Voice target ID.
|
||||||
|
optional uint32 id = 1;
|
||||||
|
// The receivers that this voice target includes.
|
||||||
|
repeated Target targets = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the client when it wants permissions for a certain channel. Sent by
|
||||||
|
// the server when it replies to the query or wants the user to resync all
|
||||||
|
// channel permissions.
|
||||||
|
message PermissionQuery {
|
||||||
|
// channel_id of the channel for which the permissions are queried.
|
||||||
|
optional uint32 channel_id = 1;
|
||||||
|
// Channel permissions.
|
||||||
|
optional uint32 permissions = 2;
|
||||||
|
// True if the client should drop its current permission information for all
|
||||||
|
// channels.
|
||||||
|
optional bool flush = 3 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the server to notify the users of the version of the CELT codec they
|
||||||
|
// should use. This may change during the connection when new users join.
|
||||||
|
message CodecVersion {
|
||||||
|
// The version of the CELT Alpha codec.
|
||||||
|
required int32 alpha = 1;
|
||||||
|
// The version of the CELT Beta codec.
|
||||||
|
required int32 beta = 2;
|
||||||
|
// True if the user should prefer Alpha over Beta.
|
||||||
|
required bool prefer_alpha = 3 [default = true];
|
||||||
|
optional bool opus = 4 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to communicate user stats between the server and clients.
|
||||||
|
message UserStats {
|
||||||
|
message Stats {
|
||||||
|
// The amount of good packets received.
|
||||||
|
optional uint32 good = 1;
|
||||||
|
// The amount of late packets received.
|
||||||
|
optional uint32 late = 2;
|
||||||
|
// The amount of packets never received.
|
||||||
|
optional uint32 lost = 3;
|
||||||
|
// The amount of nonce resyncs.
|
||||||
|
optional uint32 resync = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User whose stats these are.
|
||||||
|
optional uint32 session = 1;
|
||||||
|
// True if the message contains only mutable stats (packets, ping).
|
||||||
|
optional bool stats_only = 2 [default = false];
|
||||||
|
// Full user certificate chain of the user certificate in DER format.
|
||||||
|
repeated bytes certificates = 3;
|
||||||
|
// Packet statistics for packets received from the client.
|
||||||
|
optional Stats from_client = 4;
|
||||||
|
// Packet statistics for packets sent by the server.
|
||||||
|
optional Stats from_server = 5;
|
||||||
|
|
||||||
|
// Amount of UDP packets sent.
|
||||||
|
optional uint32 udp_packets = 6;
|
||||||
|
// Amount of TCP packets sent.
|
||||||
|
optional uint32 tcp_packets = 7;
|
||||||
|
// UDP ping average.
|
||||||
|
optional float udp_ping_avg = 8;
|
||||||
|
// UDP ping variance.
|
||||||
|
optional float udp_ping_var = 9;
|
||||||
|
// TCP ping average.
|
||||||
|
optional float tcp_ping_avg = 10;
|
||||||
|
// TCP ping variance.
|
||||||
|
optional float tcp_ping_var = 11;
|
||||||
|
|
||||||
|
// Client version.
|
||||||
|
optional Version version = 12;
|
||||||
|
// A list of CELT bitstream version constants supported by the client of this
|
||||||
|
// user.
|
||||||
|
repeated int32 celt_versions = 13;
|
||||||
|
// Client IP address.
|
||||||
|
optional bytes address = 14;
|
||||||
|
// Bandwidth used by this client.
|
||||||
|
optional uint32 bandwidth = 15;
|
||||||
|
// Connection duration.
|
||||||
|
optional uint32 onlinesecs = 16;
|
||||||
|
// Duration since last activity.
|
||||||
|
optional uint32 idlesecs = 17;
|
||||||
|
// True if the user has a strong certificate.
|
||||||
|
optional bool strong_certificate = 18 [default = false];
|
||||||
|
optional bool opus = 19 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the client to request binary data from the server. By default large
|
||||||
|
// comments or textures are not sent within standard messages but instead the
|
||||||
|
// hash is. If the client does not recognize the hash it may request the
|
||||||
|
// resource when it needs it. The client does so by sending a RequestBlob
|
||||||
|
// message with the correct fields filled with the user sessions or channel_ids
|
||||||
|
// it wants to receive. The server replies to this by sending a new
|
||||||
|
// UserState/ChannelState message with the resources filled even if they would
|
||||||
|
// normally be transmitted as hashes.
|
||||||
|
message RequestBlob {
|
||||||
|
// sessions of the requested UserState textures.
|
||||||
|
repeated uint32 session_texture = 1;
|
||||||
|
// sessions of the requested UserState comments.
|
||||||
|
repeated uint32 session_comment = 2;
|
||||||
|
// channel_ids of the requested ChannelState descriptions.
|
||||||
|
repeated uint32 channel_description = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the server when it informs the clients on server configuration
|
||||||
|
// details.
|
||||||
|
message ServerConfig {
|
||||||
|
// The maximum bandwidth the clients should use.
|
||||||
|
optional uint32 max_bandwidth = 1;
|
||||||
|
// Server welcome text.
|
||||||
|
optional string welcome_text = 2;
|
||||||
|
// True if the server allows HTML.
|
||||||
|
optional bool allow_html = 3;
|
||||||
|
// Maximum text message length.
|
||||||
|
optional uint32 message_length = 4;
|
||||||
|
// Maximum image message length.
|
||||||
|
optional uint32 image_message_length = 5;
|
||||||
|
// The maximum number of users allowed on the server.
|
||||||
|
optional uint32 max_users = 6;
|
||||||
|
// Whether using Mumble's recording feature is allowed on the server
|
||||||
|
optional bool recording_allowed = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent by the server to inform the clients of suggested client configuration
|
||||||
|
// specified by the server administrator.
|
||||||
|
message SuggestConfig {
|
||||||
|
// Suggested client version in the legacy format.
|
||||||
|
optional uint32 version_v1 = 1;
|
||||||
|
// Suggested client version in the new format.
|
||||||
|
// Necessary since patch level may exceed 255. (See https://github.com/mumble-voip/mumble/issues/5827)
|
||||||
|
optional uint64 version_v2 = 4;
|
||||||
|
|
||||||
|
// True if the administrator suggests positional audio to be used on this
|
||||||
|
// server.
|
||||||
|
optional bool positional = 2;
|
||||||
|
// True if the administrator suggests push to talk to be used on this server.
|
||||||
|
optional bool push_to_talk = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to send plugin messages between clients
|
||||||
|
message PluginDataTransmission {
|
||||||
|
// The session ID of the client this message was sent from
|
||||||
|
optional uint32 senderSession = 1;
|
||||||
|
// The session IDs of the clients that should receive this message
|
||||||
|
repeated uint32 receiverSessions = 2 [packed = true];
|
||||||
|
// The data that is sent
|
||||||
|
optional bytes data = 3;
|
||||||
|
// The ID of the sent data. This will be used by plugins to check whether they will
|
||||||
|
// process it or not
|
||||||
|
optional string dataID = 4;
|
||||||
|
}
|
22
src/audio_io.rs
Normal file
22
src/audio_io.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use alsa::PCM;
|
||||||
|
|
||||||
|
pub trait AudioIO {
|
||||||
|
fn play(&self, sender_id: u32, buf: &[i16]);
|
||||||
|
fn capture(&self, buf: &mut [i16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Alsa {
|
||||||
|
output_streams: HashMap<u32, PCM>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AudioIO for Alsa {
|
||||||
|
fn play(&self, sender_id: u32, buf: &[i16]) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capture(&self, buf: &mut [i16]) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
473
src/main.rs
Normal file
473
src/main.rs
Normal file
|
@ -0,0 +1,473 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{Cursor, Read, Write},
|
||||||
|
net::TcpStream,
|
||||||
|
sync::Arc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
use alsa::{
|
||||||
|
pcm::{Access, Format, HwParams, State},
|
||||||
|
Direction, ValueOr, PCM,
|
||||||
|
};
|
||||||
|
use audio_io::AudioIO;
|
||||||
|
use opus::{Channels, Decoder};
|
||||||
|
use prost::Message;
|
||||||
|
use rustls::{
|
||||||
|
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
|
||||||
|
internal::msgs::codec::Codec,
|
||||||
|
ClientConfig, ClientConnection, RootCertStore, SignatureScheme, Stream,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::mumble::{voice::VoiceData, ControlMessage};
|
||||||
|
|
||||||
|
mod audio_io;
|
||||||
|
mod mumble;
|
||||||
|
|
||||||
|
struct Client {
|
||||||
|
users: HashMap<u32, MumbleUser>,
|
||||||
|
user_audio: HashMap<u32, PCM>,
|
||||||
|
channels: HashMap<u32, MumbleChannel>,
|
||||||
|
conn: ClientConnection,
|
||||||
|
sock: TcpStream,
|
||||||
|
decoder: Decoder,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct MumbleUser {
|
||||||
|
name: String,
|
||||||
|
channel_id: u32,
|
||||||
|
mute: bool,
|
||||||
|
deaf: bool,
|
||||||
|
suppress: bool,
|
||||||
|
self_mute: bool,
|
||||||
|
self_deaf: bool,
|
||||||
|
priority_speaker: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct MumbleChannel {
|
||||||
|
name: String,
|
||||||
|
parent: Option<u32>,
|
||||||
|
max_users: u32,
|
||||||
|
is_enter_restricted: bool,
|
||||||
|
can_enter: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn connect(server: &str) -> anyhow::Result<Self> {
|
||||||
|
let mut root_store = RootCertStore::empty();
|
||||||
|
let mut config = ClientConfig::builder()
|
||||||
|
.with_root_certificates(root_store)
|
||||||
|
.with_no_client_auth();
|
||||||
|
|
||||||
|
config
|
||||||
|
.dangerous()
|
||||||
|
.set_certificate_verifier(Arc::new(Foo {}));
|
||||||
|
|
||||||
|
let mut conn = ClientConnection::new(Arc::new(config), "localhost".try_into()?)?;
|
||||||
|
let mut sock = TcpStream::connect(server)?;
|
||||||
|
let mut tls = Stream::new(&mut conn, &mut sock);
|
||||||
|
|
||||||
|
let msg = ControlMessage::Version(mumble::control::Version {
|
||||||
|
version_v1: Some(66815),
|
||||||
|
version_v2: Some(281492175388672),
|
||||||
|
release: Some("0.1.0".to_string()),
|
||||||
|
os: Some("RustMumble".to_string()),
|
||||||
|
os_version: Some("RustMumble".to_string()),
|
||||||
|
})
|
||||||
|
.encode();
|
||||||
|
tls.write_all(&msg)?;
|
||||||
|
|
||||||
|
let msg = ControlMessage::Authenticate(mumble::control::Authenticate {
|
||||||
|
username: Some("rust".to_string()),
|
||||||
|
password: None,
|
||||||
|
tokens: vec![],
|
||||||
|
celt_versions: vec![],
|
||||||
|
opus: Some(true),
|
||||||
|
client_type: Some(0),
|
||||||
|
})
|
||||||
|
.encode();
|
||||||
|
tls.write_all(&msg)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
users: HashMap::new(),
|
||||||
|
user_audio: HashMap::new(),
|
||||||
|
channels: HashMap::new(),
|
||||||
|
conn,
|
||||||
|
sock,
|
||||||
|
decoder: Decoder::new(48000, Channels::Mono)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn handle_incoming(&mut self) -> anyhow::Result<()> {
|
||||||
|
let mut tls = Stream::new(&mut self.conn, &mut self.sock);
|
||||||
|
match ControlMessage::decode(&mut tls)? {
|
||||||
|
ControlMessage::UserRemove(u) => {
|
||||||
|
self.users.remove(&u.session);
|
||||||
|
self.user_audio.remove(&u.session);
|
||||||
|
}
|
||||||
|
ControlMessage::UserState(u) => {
|
||||||
|
if let Some(user) = self.users.get_mut(&u.session()) {
|
||||||
|
if let Some(name) = &u.name {
|
||||||
|
user.name = name.clone();
|
||||||
|
}
|
||||||
|
if let Some(channel_id) = &u.channel_id {
|
||||||
|
user.channel_id = *channel_id;
|
||||||
|
}
|
||||||
|
if let Some(mute) = &u.mute {
|
||||||
|
user.mute = *mute;
|
||||||
|
}
|
||||||
|
if let Some(deaf) = &u.deaf {
|
||||||
|
user.deaf = *deaf;
|
||||||
|
}
|
||||||
|
if let Some(suppress) = &u.suppress {
|
||||||
|
user.suppress = *suppress;
|
||||||
|
}
|
||||||
|
if let Some(self_mute) = &u.self_mute {
|
||||||
|
user.self_mute = *self_mute;
|
||||||
|
}
|
||||||
|
if let Some(self_deaf) = &u.self_deaf {
|
||||||
|
user.self_deaf = *self_deaf;
|
||||||
|
}
|
||||||
|
if let Some(priority_speaker) = &u.priority_speaker {
|
||||||
|
user.priority_speaker = *priority_speaker;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let user = MumbleUser {
|
||||||
|
name: u.name().to_string(),
|
||||||
|
channel_id: u.channel_id(),
|
||||||
|
mute: u.mute(),
|
||||||
|
deaf: u.deaf(),
|
||||||
|
suppress: u.suppress(),
|
||||||
|
self_mute: u.self_mute(),
|
||||||
|
self_deaf: u.self_deaf(),
|
||||||
|
priority_speaker: u.priority_speaker(),
|
||||||
|
};
|
||||||
|
self.users.insert(u.session(), user);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ControlMessage::ChannelRemove(c) => {
|
||||||
|
self.channels.remove(&c.channel_id);
|
||||||
|
}
|
||||||
|
ControlMessage::ChannelState(c) => {
|
||||||
|
if let Some(channel) = self.channels.get_mut(&c.channel_id()) {
|
||||||
|
if let Some(name) = c.name {
|
||||||
|
channel.name = name.to_string();
|
||||||
|
}
|
||||||
|
if let Some(parent) = c.parent {
|
||||||
|
channel.parent = Some(parent);
|
||||||
|
}
|
||||||
|
if let Some(max_users) = c.max_users {
|
||||||
|
channel.max_users = max_users;
|
||||||
|
}
|
||||||
|
if let Some(is_enter_restricted) = c.is_enter_restricted {
|
||||||
|
channel.is_enter_restricted = is_enter_restricted;
|
||||||
|
}
|
||||||
|
if let Some(can_enter) = c.can_enter {
|
||||||
|
channel.can_enter = can_enter;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let channel = MumbleChannel {
|
||||||
|
name: c.name().to_string(),
|
||||||
|
parent: c.parent,
|
||||||
|
max_users: c.max_users(),
|
||||||
|
is_enter_restricted: c.is_enter_restricted(),
|
||||||
|
can_enter: c.can_enter(),
|
||||||
|
};
|
||||||
|
self.channels.insert(c.channel_id(), channel);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ControlMessage::UdpTunnel(packet) => match packet {
|
||||||
|
VoiceData::Opus { target, packet } => {
|
||||||
|
let mut buf: Vec<i16> = vec![0_i16; 16 * packet.payload.data.len()];
|
||||||
|
let len =
|
||||||
|
self.decoder
|
||||||
|
.decode(&packet.payload.data, buf.as_mut_slice(), false)?;
|
||||||
|
let buf = &buf[..len];
|
||||||
|
|
||||||
|
let pcm = match self.user_audio.get(&(packet.session_id.0 as u32)) {
|
||||||
|
Some(pcm) => pcm,
|
||||||
|
None => {
|
||||||
|
let pcm = PCM::new("default", Direction::Playback, true).unwrap();
|
||||||
|
{
|
||||||
|
// Set hardware parameters: 44100 Hz / Mono / 16 bit
|
||||||
|
let hwp = HwParams::any(&pcm).unwrap();
|
||||||
|
hwp.set_channels(1).unwrap();
|
||||||
|
hwp.set_rate(48000, ValueOr::Nearest).unwrap();
|
||||||
|
hwp.set_format(Format::s16()).unwrap();
|
||||||
|
hwp.set_access(Access::RWInterleaved).unwrap();
|
||||||
|
pcm.hw_params(&hwp).unwrap();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let hwp = pcm.hw_params_current().unwrap();
|
||||||
|
let swp = pcm.sw_params_current().unwrap();
|
||||||
|
swp.set_start_threshold(960 * 10).unwrap();
|
||||||
|
dbg!(hwp.get_buffer_size_min());
|
||||||
|
pcm.sw_params(&swp).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("START");
|
||||||
|
self.user_audio.insert(packet.session_id.0 as u32, pcm);
|
||||||
|
self.user_audio.get(&(packet.session_id.0 as u32)).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let io = pcm.io_i16()?;
|
||||||
|
|
||||||
|
dbg!(&io.writei(&buf));
|
||||||
|
println!("wrote");
|
||||||
|
|
||||||
|
if pcm.state() == State::Paused {}
|
||||||
|
|
||||||
|
if packet.payload.last {
|
||||||
|
println!("STOP");
|
||||||
|
pcm.wait(None)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
x => {
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait endecode {
|
||||||
|
fn encode(&self) -> Vec<u8>;
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main2() -> anyhow::Result<()> {
|
||||||
|
// Open default playback device
|
||||||
|
let pcm = PCM::new("default", Direction::Playback, false).unwrap();
|
||||||
|
{
|
||||||
|
// Set hardware parameters: 44100 Hz / Mono / 16 bit
|
||||||
|
let hwp = HwParams::any(&pcm).unwrap();
|
||||||
|
hwp.set_channels(1).unwrap();
|
||||||
|
hwp.set_rate(48000, ValueOr::Nearest).unwrap();
|
||||||
|
hwp.set_format(Format::s16()).unwrap();
|
||||||
|
hwp.set_access(Access::RWInterleaved).unwrap();
|
||||||
|
pcm.hw_params(&hwp).unwrap();
|
||||||
|
}
|
||||||
|
let io = pcm.io_i16().unwrap();
|
||||||
|
|
||||||
|
let hwp = pcm.hw_params_current().unwrap();
|
||||||
|
let swp = pcm.sw_params_current().unwrap();
|
||||||
|
swp.set_start_threshold(hwp.get_buffer_size().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
pcm.sw_params(&swp).unwrap();
|
||||||
|
|
||||||
|
let pcm2 = PCM::new("default", Direction::Capture, false).unwrap();
|
||||||
|
{
|
||||||
|
// Set hardware parameters: 44100 Hz / Mono / 16 bit
|
||||||
|
let hwp = HwParams::any(&pcm2).unwrap();
|
||||||
|
hwp.set_channels(1).unwrap();
|
||||||
|
hwp.set_rate(48000, ValueOr::Nearest).unwrap();
|
||||||
|
hwp.set_format(Format::s16()).unwrap();
|
||||||
|
hwp.set_access(Access::RWInterleaved).unwrap();
|
||||||
|
pcm2.hw_params(&hwp).unwrap();
|
||||||
|
}
|
||||||
|
let io2 = pcm2.io_i16().unwrap();
|
||||||
|
|
||||||
|
// // Make a sine wave
|
||||||
|
// let mut buf = [0i16; 512];
|
||||||
|
// for (i, a) in buf.iter_mut().enumerate() {
|
||||||
|
// *a = ((i as f32 * 8.0 * ::std::f32::consts::PI / 128.0).sin() * 8192.0) as i16
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Play it back for 2 seconds.
|
||||||
|
// for _ in 0..2 * 8000 / 512 {
|
||||||
|
// assert_eq!(io.writei(&buf[..]).unwrap(), 512);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
pcm2.start()?;
|
||||||
|
|
||||||
|
let mut buf = [0i16; 512];
|
||||||
|
loop {
|
||||||
|
let x = io2.readi(&mut buf)?;
|
||||||
|
|
||||||
|
buf.iter_mut().for_each(|x| *x = 2 * *x);
|
||||||
|
|
||||||
|
io.writei(&buf)?;
|
||||||
|
if pcm.state() != State::Running {
|
||||||
|
pcm.start().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let mut client = Client::connect("127.0.0.1:64738")?;
|
||||||
|
loop {
|
||||||
|
client.handle_incoming();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut root_store = RootCertStore::empty();
|
||||||
|
let mut config = ClientConfig::builder()
|
||||||
|
.with_root_certificates(root_store)
|
||||||
|
.with_no_client_auth();
|
||||||
|
|
||||||
|
config
|
||||||
|
.dangerous()
|
||||||
|
.set_certificate_verifier(Arc::new(Foo {}));
|
||||||
|
|
||||||
|
let mut conn = ClientConnection::new(Arc::new(config), "localhost".try_into()?)?;
|
||||||
|
let mut sock = TcpStream::connect("127.0.0.1:64738")?;
|
||||||
|
let mut tls = Stream::new(&mut conn, &mut sock);
|
||||||
|
|
||||||
|
println!("1");
|
||||||
|
|
||||||
|
dbg!(ControlMessage::decode(&mut tls));
|
||||||
|
|
||||||
|
println!("2");
|
||||||
|
|
||||||
|
let msg = ControlMessage::Version(mumble::control::Version {
|
||||||
|
version_v1: Some(66815),
|
||||||
|
version_v2: Some(281492175388672),
|
||||||
|
release: Some("0.1.0".to_string()),
|
||||||
|
os: Some("RustMumble".to_string()),
|
||||||
|
os_version: Some("RustMumble".to_string()),
|
||||||
|
})
|
||||||
|
.encode();
|
||||||
|
tls.write_all(&msg)?;
|
||||||
|
|
||||||
|
let msg = ControlMessage::Authenticate(mumble::control::Authenticate {
|
||||||
|
username: Some("rust".to_string()),
|
||||||
|
password: None,
|
||||||
|
tokens: vec![],
|
||||||
|
celt_versions: vec![],
|
||||||
|
opus: Some(true),
|
||||||
|
client_type: Some(0),
|
||||||
|
})
|
||||||
|
.encode();
|
||||||
|
tls.write_all(&msg)?;
|
||||||
|
|
||||||
|
let msg = ControlMessage::UserState(mumble::control::UserState {
|
||||||
|
channel_id: Some(1),
|
||||||
|
self_mute: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.encode();
|
||||||
|
tls.write_all(&msg)?;
|
||||||
|
|
||||||
|
let mut decoder = Decoder::new(48000, Channels::Mono)?;
|
||||||
|
|
||||||
|
let pcm = PCM::new("default", Direction::Playback, false).unwrap();
|
||||||
|
{
|
||||||
|
// Set hardware parameters: 44100 Hz / Mono / 16 bit
|
||||||
|
let hwp = HwParams::any(&pcm).unwrap();
|
||||||
|
hwp.set_channels(1).unwrap();
|
||||||
|
hwp.set_rate(48000, ValueOr::Nearest).unwrap();
|
||||||
|
hwp.set_format(Format::s16()).unwrap();
|
||||||
|
hwp.set_access(Access::RWInterleaved).unwrap();
|
||||||
|
pcm.hw_params(&hwp).unwrap();
|
||||||
|
}
|
||||||
|
let io = pcm.io_i16().unwrap();
|
||||||
|
|
||||||
|
let hwp = pcm.hw_params_current().unwrap();
|
||||||
|
let swp = pcm.sw_params_current().unwrap();
|
||||||
|
swp.set_start_threshold(hwp.get_buffer_size().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
pcm.sw_params(&swp).unwrap();
|
||||||
|
|
||||||
|
let mut running = false;
|
||||||
|
|
||||||
|
let mut last_ping = Instant::now();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
//TODO: non blocking
|
||||||
|
let cm = ControlMessage::decode(&mut tls)?;
|
||||||
|
match cm {
|
||||||
|
ControlMessage::UdpTunnel(x) => match x {
|
||||||
|
VoiceData::Opus { target, packet } => {
|
||||||
|
let mut buf: Vec<i16> = vec![0_i16; 16 * packet.payload.data.len()];
|
||||||
|
let len = decoder.decode(&packet.payload.data, buf.as_mut_slice(), false)?;
|
||||||
|
let buf = &buf[..len];
|
||||||
|
|
||||||
|
io.writei(&buf)?;
|
||||||
|
match pcm.state() {
|
||||||
|
State::Prepared if running => pcm.start()?,
|
||||||
|
State::Paused => pcm.pause(false)?,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
if packet.payload.last {
|
||||||
|
running = false;
|
||||||
|
pcm.pause(true)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
x => {
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if last_ping.elapsed() > Duration::from_secs(20) {
|
||||||
|
println!("TEST");
|
||||||
|
let msg = ControlMessage::Ping(mumble::control::Ping {
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.encode();
|
||||||
|
tls.write_all(&msg)?;
|
||||||
|
last_ping = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Foo {}
|
||||||
|
|
||||||
|
impl ServerCertVerifier for Foo {
|
||||||
|
fn verify_server_cert(
|
||||||
|
&self,
|
||||||
|
end_entity: &rustls::pki_types::CertificateDer<'_>,
|
||||||
|
intermediates: &[rustls::pki_types::CertificateDer<'_>],
|
||||||
|
server_name: &rustls::pki_types::ServerName<'_>,
|
||||||
|
ocsp_response: &[u8],
|
||||||
|
now: rustls::pki_types::UnixTime,
|
||||||
|
) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
|
||||||
|
Ok(ServerCertVerified::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_tls12_signature(
|
||||||
|
&self,
|
||||||
|
message: &[u8],
|
||||||
|
cert: &rustls::pki_types::CertificateDer<'_>,
|
||||||
|
dss: &rustls::DigitallySignedStruct,
|
||||||
|
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
|
||||||
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_tls13_signature(
|
||||||
|
&self,
|
||||||
|
message: &[u8],
|
||||||
|
cert: &rustls::pki_types::CertificateDer<'_>,
|
||||||
|
dss: &rustls::DigitallySignedStruct,
|
||||||
|
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
|
||||||
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
|
||||||
|
vec![
|
||||||
|
SignatureScheme::RSA_PKCS1_SHA1,
|
||||||
|
SignatureScheme::ECDSA_SHA1_Legacy,
|
||||||
|
SignatureScheme::RSA_PKCS1_SHA256,
|
||||||
|
SignatureScheme::ECDSA_NISTP256_SHA256,
|
||||||
|
SignatureScheme::RSA_PKCS1_SHA384,
|
||||||
|
SignatureScheme::ECDSA_NISTP384_SHA384,
|
||||||
|
SignatureScheme::RSA_PKCS1_SHA512,
|
||||||
|
SignatureScheme::ECDSA_NISTP521_SHA512,
|
||||||
|
SignatureScheme::RSA_PSS_SHA256,
|
||||||
|
SignatureScheme::RSA_PSS_SHA384,
|
||||||
|
SignatureScheme::RSA_PSS_SHA512,
|
||||||
|
SignatureScheme::ED25519,
|
||||||
|
SignatureScheme::ED448,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
340
src/mumble.rs
Normal file
340
src/mumble.rs
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
|
use prost::Message;
|
||||||
|
|
||||||
|
use crate::endecode;
|
||||||
|
|
||||||
|
use self::voice::VoiceData;
|
||||||
|
|
||||||
|
pub mod control {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/mumble_proto.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod voice {
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use crate::endecode;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum VoiceData {
|
||||||
|
CeltAlpha {
|
||||||
|
target: VoiceTarget,
|
||||||
|
packet: AudioDataPacket<CeltAlphaAudioPacket>,
|
||||||
|
},
|
||||||
|
Ping(u64),
|
||||||
|
Speex,
|
||||||
|
CeltBeta,
|
||||||
|
Opus {
|
||||||
|
target: VoiceTarget,
|
||||||
|
packet: AudioDataPacket<OpusAudioPacket>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl endecode for VoiceData {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
let mut header = [0_u8; 1];
|
||||||
|
stream.read_exact(&mut header)?;
|
||||||
|
let header = header[0];
|
||||||
|
let target = VoiceTarget::from(header & 0b00011111);
|
||||||
|
let kind = (header >> 5) & 0b00000111;
|
||||||
|
Ok(match kind {
|
||||||
|
0 => Self::CeltAlpha {
|
||||||
|
target,
|
||||||
|
packet: AudioDataPacket::<CeltAlphaAudioPacket>::decode(stream)?,
|
||||||
|
},
|
||||||
|
1 => {
|
||||||
|
let mut timestamp = [0_u8; 8];
|
||||||
|
stream.read_exact(&mut timestamp)?;
|
||||||
|
|
||||||
|
Self::Ping(u64::from_be_bytes(timestamp))
|
||||||
|
}
|
||||||
|
2 => Self::Speex,
|
||||||
|
3 => Self::CeltBeta,
|
||||||
|
4 => Self::Opus {
|
||||||
|
target,
|
||||||
|
packet: AudioDataPacket::<OpusAudioPacket>::decode(stream)?,
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum VoiceTarget {
|
||||||
|
Normal,
|
||||||
|
Whisper(u8),
|
||||||
|
ServerLoopback,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for VoiceTarget {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::Normal,
|
||||||
|
31 => Self::ServerLoopback,
|
||||||
|
x if x < 32 => Self::Whisper(x),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AudioDataPacket<T: endecode> {
|
||||||
|
pub session_id: VarI64,
|
||||||
|
pub seq_nr: VarI64,
|
||||||
|
pub payload: T,
|
||||||
|
//position_info: [f32; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: endecode> endecode for AudioDataPacket<T> {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
session_id: VarI64::decode(stream)?,
|
||||||
|
seq_nr: VarI64::decode(stream)?,
|
||||||
|
payload: T::decode(stream)?,
|
||||||
|
// position_info: {
|
||||||
|
// let mut f1 = [0_u8; 4];
|
||||||
|
// //stream.read_exact(&mut f1)?;
|
||||||
|
// let mut f2 = [0_u8; 4];
|
||||||
|
// //stream.read_exact(&mut f2)?;
|
||||||
|
// let mut f3 = [0_u8; 4];
|
||||||
|
// //stream.read_exact(&mut f3)?;
|
||||||
|
//
|
||||||
|
// [
|
||||||
|
// f32::from_be_bytes(f1),
|
||||||
|
// f32::from_be_bytes(f2),
|
||||||
|
// f32::from_be_bytes(f3),
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OpusAudioPacket {
|
||||||
|
pub last: bool,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl endecode for OpusAudioPacket {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
let length = VarI64::decode(stream)?.0;
|
||||||
|
let last = (length & 0x2000) == 0x2000;
|
||||||
|
let length = length & 0x1FFF;
|
||||||
|
let mut data = vec![0_u8; length as usize];
|
||||||
|
stream.read_exact(&mut data)?;
|
||||||
|
Ok(Self { last, data })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CeltAlphaAudioPacket(pub Vec<u8>);
|
||||||
|
|
||||||
|
impl endecode for CeltAlphaAudioPacket {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
let mut length = [0_u8; 1];
|
||||||
|
stream.read_exact(&mut length)?;
|
||||||
|
let length = length[0];
|
||||||
|
let continuation = ((length >> 7) & 0b1) == 1;
|
||||||
|
let length = length & 0b01111111;
|
||||||
|
|
||||||
|
let mut data = vec![0_u8; length as usize];
|
||||||
|
stream.read_exact(&mut data)?;
|
||||||
|
Ok(Self(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VarI64(pub i64);
|
||||||
|
|
||||||
|
impl endecode for VarI64 {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
let oct = self.0.to_be_bytes();
|
||||||
|
match self.0 {
|
||||||
|
x if x < (1 << 7) && x >= 0 => vec![oct[7] & 0b01111111 + 0b00000000],
|
||||||
|
x if x < (1 << 14) && x >= 0 => vec![oct[6] & 0b00111111 + 0b10000000, oct[7]],
|
||||||
|
x if x < (1 << 21) && x >= 0 => {
|
||||||
|
vec![oct[5] & 0b00011111 + 0b11000000, oct[6], oct[7]]
|
||||||
|
}
|
||||||
|
x if x < (1 << 28) && x >= 0 => {
|
||||||
|
vec![oct[4] & 0b00001111 + 0b11100000, oct[5], oct[6], oct[7]]
|
||||||
|
}
|
||||||
|
x if x < (1 << 32) && x >= 0 => vec![0b11110000, oct[4], oct[5], oct[6], oct[7]],
|
||||||
|
x if x >= 0 => vec![
|
||||||
|
0b11110100, oct[0], oct[1], oct[2], oct[3], oct[4], oct[5], oct[6], oct[7],
|
||||||
|
],
|
||||||
|
x if x < 0 && x > -4 => vec![0b11111100 + ((!(-(oct[7] as i8) as u8)) & 0b11)],
|
||||||
|
x => [&[0b11111100], VarI64(-self.0).encode().as_slice()].concat(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
let mut first = [0_u8; 1];
|
||||||
|
stream.read_exact(&mut first)?;
|
||||||
|
let first = first[0];
|
||||||
|
|
||||||
|
Ok(Self(match first {
|
||||||
|
x if ((x >> 7) & 0b00000001) == 0 => (x as i64) & 0b01111111,
|
||||||
|
x if ((x >> 6) & 0b00000011) == 0b10 => {
|
||||||
|
let mut next = [0_u8; 1];
|
||||||
|
stream.read_exact(&mut next)?;
|
||||||
|
|
||||||
|
i64::from_be_bytes([0, 0, 0, 0, 0, 0, x & 0b00111111, next[0]])
|
||||||
|
}
|
||||||
|
x if ((x >> 5) & 0b00000111) == 0b110 => {
|
||||||
|
let mut next = [0_u8; 2];
|
||||||
|
stream.read_exact(&mut next)?;
|
||||||
|
|
||||||
|
i64::from_be_bytes([0, 0, 0, 0, 0, x & 0b00011111, next[0], next[1]])
|
||||||
|
}
|
||||||
|
x if ((x >> 4) & 0b00001111) == 0b1110 => {
|
||||||
|
let mut next = [0_u8; 3];
|
||||||
|
stream.read_exact(&mut next)?;
|
||||||
|
|
||||||
|
i64::from_be_bytes([0, 0, 0, 0, x & 0b00001111, next[0], next[1], next[2]])
|
||||||
|
}
|
||||||
|
x if ((x >> 2) & 0b00111111) == 0b111100 => {
|
||||||
|
let mut next = [0_u8; 4];
|
||||||
|
stream.read_exact(&mut next)?;
|
||||||
|
|
||||||
|
i64::from_be_bytes([0, 0, 0, 0, next[0], next[1], next[2], next[3]])
|
||||||
|
}
|
||||||
|
x if ((x >> 2) & 0b00111111) == 0b111101 => {
|
||||||
|
let mut next = [0_u8; 8];
|
||||||
|
stream.read_exact(&mut next)?;
|
||||||
|
|
||||||
|
i64::from_be_bytes(next)
|
||||||
|
}
|
||||||
|
x if ((x >> 2) & 0b00111111) == 0b111110 => -(Self::decode(stream)?.0),
|
||||||
|
x if ((x >> 2) & 0b00111111) == 0b111111 => -!((x as i64) & 0b1111111),
|
||||||
|
_ => todo!(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ControlMessage {
|
||||||
|
Version(control::Version),
|
||||||
|
UdpTunnel(VoiceData),
|
||||||
|
Authenticate(control::Authenticate),
|
||||||
|
Ping(control::Ping),
|
||||||
|
Reject(control::Reject),
|
||||||
|
ServerSync(control::ServerSync),
|
||||||
|
ChannelRemove(control::ChannelRemove),
|
||||||
|
ChannelState(control::ChannelState),
|
||||||
|
UserRemove(control::UserRemove),
|
||||||
|
UserState(control::UserState),
|
||||||
|
BanList(control::BanList),
|
||||||
|
TextMessage(control::TextMessage),
|
||||||
|
PermissionDenied(control::PermissionDenied),
|
||||||
|
Acl(control::Acl),
|
||||||
|
QueryUsers(control::QueryUsers),
|
||||||
|
CryptSetup(control::CryptSetup),
|
||||||
|
ContextActionModify(control::ContextActionModify),
|
||||||
|
ContextAction(control::ContextAction),
|
||||||
|
UserList(control::UserList),
|
||||||
|
VoiceTarget(control::VoiceTarget),
|
||||||
|
PermissionQuery(control::PermissionQuery),
|
||||||
|
CodecVersion(control::CodecVersion),
|
||||||
|
UserStats(control::UserStats),
|
||||||
|
RequestBlob(control::RequestBlob),
|
||||||
|
ServerConfig(control::ServerConfig),
|
||||||
|
SuggestConfig(control::SuggestConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl endecode for ControlMessage {
|
||||||
|
fn decode(stream: &mut impl Read) -> anyhow::Result<Self> {
|
||||||
|
let mut kind = [0_u8; 2];
|
||||||
|
stream.read_exact(&mut kind)?;
|
||||||
|
let kind = u16::from_be_bytes(kind);
|
||||||
|
let mut length = [0_u8; 4];
|
||||||
|
stream.read_exact(&mut length)?;
|
||||||
|
let length = u32::from_be_bytes(length);
|
||||||
|
let mut data = vec![0_u8; length as usize];
|
||||||
|
stream.read_exact(&mut data)?;
|
||||||
|
let mut data = Cursor::new(data);
|
||||||
|
|
||||||
|
macro_rules! cm {
|
||||||
|
($x:ident) => {
|
||||||
|
Self::$x(control::$x::decode(data.get_ref().as_slice())?)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(match kind {
|
||||||
|
0 => cm!(Version),
|
||||||
|
1 => Self::UdpTunnel(VoiceData::decode(&mut data)?),
|
||||||
|
2 => cm!(Authenticate),
|
||||||
|
3 => cm!(Ping),
|
||||||
|
4 => cm!(Reject),
|
||||||
|
5 => cm!(ServerSync),
|
||||||
|
6 => cm!(ChannelRemove),
|
||||||
|
7 => cm!(ChannelState),
|
||||||
|
8 => cm!(UserRemove),
|
||||||
|
9 => cm!(UserState),
|
||||||
|
10 => cm!(BanList),
|
||||||
|
11 => cm!(TextMessage),
|
||||||
|
12 => cm!(PermissionDenied),
|
||||||
|
13 => cm!(Acl),
|
||||||
|
14 => cm!(QueryUsers),
|
||||||
|
15 => cm!(CryptSetup),
|
||||||
|
16 => cm!(ContextActionModify),
|
||||||
|
17 => cm!(ContextAction),
|
||||||
|
18 => cm!(UserList),
|
||||||
|
19 => cm!(VoiceTarget),
|
||||||
|
20 => cm!(PermissionQuery),
|
||||||
|
21 => cm!(CodecVersion),
|
||||||
|
22 => cm!(UserStats),
|
||||||
|
23 => cm!(RequestBlob),
|
||||||
|
24 => cm!(ServerConfig),
|
||||||
|
25 => cm!(SuggestConfig),
|
||||||
|
_ => todo!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
let (kind, data): (u16, Vec<u8>) = match self {
|
||||||
|
Self::Version(x) => (0, x.encode_to_vec()),
|
||||||
|
Self::UdpTunnel(x) => (1, x.encode()),
|
||||||
|
Self::Authenticate(x) => (2, x.encode_to_vec()),
|
||||||
|
Self::Ping(x) => (3, x.encode_to_vec()),
|
||||||
|
Self::Reject(x) => (4, x.encode_to_vec()),
|
||||||
|
Self::ServerSync(x) => (5, x.encode_to_vec()),
|
||||||
|
Self::ChannelRemove(x) => (6, x.encode_to_vec()),
|
||||||
|
Self::ChannelState(x) => (7, x.encode_to_vec()),
|
||||||
|
Self::UserRemove(x) => (8, x.encode_to_vec()),
|
||||||
|
Self::UserState(x) => (9, x.encode_to_vec()),
|
||||||
|
Self::BanList(x) => (10, x.encode_to_vec()),
|
||||||
|
Self::TextMessage(x) => (11, x.encode_to_vec()),
|
||||||
|
Self::PermissionDenied(x) => (12, x.encode_to_vec()),
|
||||||
|
Self::Acl(x) => (13, x.encode_to_vec()),
|
||||||
|
Self::QueryUsers(x) => (14, x.encode_to_vec()),
|
||||||
|
Self::CryptSetup(x) => (15, x.encode_to_vec()),
|
||||||
|
Self::ContextActionModify(x) => (16, x.encode_to_vec()),
|
||||||
|
Self::ContextAction(x) => (17, x.encode_to_vec()),
|
||||||
|
Self::UserList(x) => (18, x.encode_to_vec()),
|
||||||
|
Self::VoiceTarget(x) => (19, x.encode_to_vec()),
|
||||||
|
Self::PermissionQuery(x) => (20, x.encode_to_vec()),
|
||||||
|
Self::CodecVersion(x) => (21, x.encode_to_vec()),
|
||||||
|
Self::UserStats(x) => (22, x.encode_to_vec()),
|
||||||
|
Self::RequestBlob(x) => (23, x.encode_to_vec()),
|
||||||
|
Self::ServerConfig(x) => (24, x.encode_to_vec()),
|
||||||
|
Self::SuggestConfig(x) => (25, x.encode_to_vec()),
|
||||||
|
};
|
||||||
|
let length = (data.len() as u32).to_be_bytes();
|
||||||
|
let kind = kind.to_be_bytes();
|
||||||
|
[kind.as_slice(), length.as_slice(), &data].concat()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue