mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'xMAC94x/network' into 'master'
xMAC94x/network See merge request veloren/veloren!1032
This commit is contained in:
commit
de849adf84
724
Cargo.lock
generated
724
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ members = [
|
||||
"server-cli",
|
||||
"voxygen",
|
||||
"world",
|
||||
"network",
|
||||
]
|
||||
|
||||
# default profile for devs, fast to compile, okay enough to run, no debug information
|
||||
@ -24,6 +25,8 @@ incremental = true
|
||||
# All dependencies (but not this crate itself)
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 3
|
||||
[profile.dev.package."veloren_network"]
|
||||
opt-level = 2
|
||||
[profile.dev.package."veloren-common"]
|
||||
opt-level = 2
|
||||
[profile.dev.package."veloren-client"]
|
||||
|
28
network/Cargo.toml
Normal file
28
network/Cargo.toml
Normal file
@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "veloren_network"
|
||||
version = "0.1.0"
|
||||
authors = ["Marcel Märtens <marcel.cochem@googlemail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
#serialisation
|
||||
bincode = "1.2"
|
||||
serde = { version = "1.0" }
|
||||
#sending
|
||||
async-std = { version = "~1.5", features = ["std"] }
|
||||
#tracing and metrics
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
tracing-futures = "0.2"
|
||||
prometheus = { version = "0.7", default-features = false }
|
||||
#async
|
||||
futures = { version = "0.3", features = ["thread-pool"] }
|
||||
#mpsc channel registry
|
||||
lazy_static = { version = "1.4", default-features = false }
|
||||
rand = { version = "0.7" }
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = { version = "0.2.3", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] }
|
||||
uvth = { version = "3.1", default-features = false }
|
855
network/examples/chat/Cargo.lock
generated
Normal file
855
network/examples/chat/Cargo.lock
generated
Normal file
@ -0,0 +1,855 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "538ecb01eb64eecd772087e5b6f7540cbc917f047727339a472dafed2185b267"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-timer",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"mio",
|
||||
"mio-uds",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ac2c016b079e771204030951c366db398864f5026f84a44dafb0ff20f02085d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"maybe-uninit",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c54d9f465d530a752e6ebdc217e081a7a614b48cb200f6f0aee21ba6bc9aabb"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-uds"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
|
||||
dependencies = [
|
||||
"iovec",
|
||||
"libc",
|
||||
"mio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "network-speed"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"bincode",
|
||||
"clap",
|
||||
"futures",
|
||||
"serde",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"veloren_network",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f6a7f5eee6292c559c793430c55c00aea9d3b3d1905e855806ca4d7253426a2"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8988430ce790d8682672117bc06dda364c0be32d3abd738234f19f3240bad99a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5567486d5778e2c6455b1b90ff1c558f29e751fc018130fa182e15828e728af1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"quick-error",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae75d0445b5d3778c9da3d1f840faa16d0627c8607f78a74daf69e5b988c39a1"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1721cc8cf7d770cc4257872507180f35a4797272f5962f24c806af9e7faf52ab"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58b0b7fd92dc7b71f29623cc6836dd7200f32161a2313dd78be233a8405694f6"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfc50df245be6f0adf35c399cb16dea60e2c7d6cc83ff5dc22d727df06dd6f0c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"matchers",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "veloren_network"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"bincode",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"prometheus",
|
||||
"rand",
|
||||
"serde",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
19
network/examples/chat/Cargo.toml
Normal file
19
network/examples/chat/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "network-speed"
|
||||
version = "0.1.0"
|
||||
authors = ["Marcel Märtens <marcel.cochem@googlemail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
network = { package = "veloren_network", path = "../../../network" }
|
||||
clap = { version = "2.33", default-features = false }
|
||||
async-std = { version = "1.5", default-features = false }
|
||||
futures = { version = "0.3", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
tracing-subscriber = { version = "0.2.3", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] }
|
||||
bincode = "1.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
189
network/examples/chat/src/main.rs
Normal file
189
network/examples/chat/src/main.rs
Normal file
@ -0,0 +1,189 @@
|
||||
//!run with
|
||||
//! ```bash
|
||||
//! (cd network/examples/chat && RUST_BACKTRACE=1 cargo run --release -- --trace=info --port 15006)
|
||||
//! (cd network/examples/chat && RUST_BACKTRACE=1 cargo run --release -- --trace=info --port 15006 --mode=client)
|
||||
//! ```
|
||||
use async_std::io;
|
||||
use clap::{App, Arg};
|
||||
use futures::executor::{block_on, ThreadPool};
|
||||
use network::{Address, Network, Participant, Pid, PROMISES_CONSISTENCY, PROMISES_ORDERED};
|
||||
use std::{sync::Arc, thread, time::Duration};
|
||||
use tracing::*;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
///This example contains a simple chatserver, that allows to send messages
|
||||
/// between participants, it's neither pretty nor perfect, but it should show how to integrate network
|
||||
fn main() {
|
||||
let matches = App::new("Chat example")
|
||||
.version("0.1.0")
|
||||
.author("Marcel Märtens <marcel.cochem@googlemail.com>")
|
||||
.about("example chat implemented with veloren-network")
|
||||
.arg(
|
||||
Arg::with_name("mode")
|
||||
.short("m")
|
||||
.long("mode")
|
||||
.takes_value(true)
|
||||
.possible_values(&["server", "client", "both"])
|
||||
.default_value("both")
|
||||
.help(
|
||||
"choose whether you want to start the server or client or both needed for \
|
||||
this program",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.takes_value(true)
|
||||
.default_value("52000")
|
||||
.help("port to listen on"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ip")
|
||||
.long("ip")
|
||||
.takes_value(true)
|
||||
.default_value("127.0.0.1")
|
||||
.help("ip to listen and connect to"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("protocol")
|
||||
.long("protocol")
|
||||
.takes_value(true)
|
||||
.default_value("tcp")
|
||||
.possible_values(&["tcp", "upd", "mpsc"])
|
||||
.help(
|
||||
"underlying protocol used for this test, mpsc can only combined with mode=both",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("trace")
|
||||
.short("t")
|
||||
.long("trace")
|
||||
.takes_value(true)
|
||||
.default_value("warn")
|
||||
.possible_values(&["trace", "debug", "info", "warn", "error"])
|
||||
.help("set trace level, not this has a performance impact!"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let trace = matches.value_of("trace").unwrap();
|
||||
let filter = EnvFilter::from_default_env().add_directive(trace.parse().unwrap());
|
||||
tracing_subscriber::FmtSubscriber::builder()
|
||||
.with_max_level(Level::TRACE)
|
||||
.with_env_filter(filter)
|
||||
.init();
|
||||
|
||||
let port: u16 = matches.value_of("port").unwrap().parse().unwrap();
|
||||
let ip: &str = matches.value_of("ip").unwrap();
|
||||
let address = match matches.value_of("protocol") {
|
||||
Some("tcp") => Address::Tcp(format!("{}:{}", ip, port).parse().unwrap()),
|
||||
Some("udp") => Address::Udp(format!("{}:{}", ip, port).parse().unwrap()),
|
||||
_ => panic!("invalid mode, run --help!"),
|
||||
};
|
||||
|
||||
let mut background = None;
|
||||
match matches.value_of("mode") {
|
||||
Some("server") => server(address),
|
||||
Some("client") => client(address),
|
||||
Some("both") => {
|
||||
let address1 = address.clone();
|
||||
background = Some(thread::spawn(|| server(address1)));
|
||||
thread::sleep(Duration::from_millis(200)); //start client after server
|
||||
client(address)
|
||||
},
|
||||
_ => panic!("invalid mode, run --help!"),
|
||||
};
|
||||
if let Some(background) = background {
|
||||
background.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn server(address: Address) {
|
||||
let (server, f) = Network::new(Pid::new(), None);
|
||||
let server = Arc::new(server);
|
||||
std::thread::spawn(f);
|
||||
let pool = ThreadPool::new().unwrap();
|
||||
block_on(async {
|
||||
server.listen(address).await.unwrap();
|
||||
loop {
|
||||
let p1 = server.connected().await.unwrap();
|
||||
let server1 = server.clone();
|
||||
pool.spawn_ok(client_connection(server1, p1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn client_connection(network: Arc<Network>, participant: Arc<Participant>) {
|
||||
let mut s1 = participant.opened().await.unwrap();
|
||||
let username = s1.recv::<String>().await.unwrap();
|
||||
println!("[{}] connected", username);
|
||||
loop {
|
||||
match s1.recv::<String>().await {
|
||||
Err(_) => {
|
||||
break;
|
||||
},
|
||||
Ok(msg) => {
|
||||
println!("[{}]: {}", username, msg);
|
||||
let mut parts = network.participants().await;
|
||||
for (_, p) in parts.drain() {
|
||||
match p
|
||||
.open(32, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
.await {
|
||||
Err(_) => {
|
||||
//probably disconnected, remove it
|
||||
network.disconnect(p).await.unwrap();
|
||||
},
|
||||
Ok(mut s) => s.send((username.clone(), msg.clone())).unwrap(),
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
println!("[{}] disconnected", username);
|
||||
}
|
||||
|
||||
fn client(address: Address) {
|
||||
let (client, f) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f);
|
||||
let pool = ThreadPool::new().unwrap();
|
||||
|
||||
block_on(async {
|
||||
let p1 = client.connect(address.clone()).await.unwrap(); //remote representation of p1
|
||||
let mut s1 = p1
|
||||
.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
.await
|
||||
.unwrap(); //remote representation of s1
|
||||
println!("Enter your username:");
|
||||
let mut username = String::new();
|
||||
io::stdin().read_line(&mut username).await.unwrap();
|
||||
username = username.split_whitespace().collect();
|
||||
println!("Your username is: {}", username);
|
||||
println!("write /quit to close");
|
||||
pool.spawn_ok(read_messages(p1));
|
||||
s1.send(username).unwrap();
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
io::stdin().read_line(&mut line).await.unwrap();
|
||||
line = line.split_whitespace().collect();
|
||||
if line.as_str() == "/quit" {
|
||||
println!("goodbye");
|
||||
break;
|
||||
} else {
|
||||
s1.send(line).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
thread::sleep(Duration::from_millis(30)); // TODO: still needed for correct shutdown
|
||||
}
|
||||
|
||||
// I am quite lazy, the sending is done in a single stream above, but for
|
||||
// receiving i open and close a stream per message. this can be done easier but
|
||||
// this allows me to be quite lazy on the server side and just get a list of
|
||||
// all participants and send to them...
|
||||
async fn read_messages(participant: Arc<Participant>) {
|
||||
while let Ok(mut s) = participant.opened().await {
|
||||
let (username, message) = s.recv::<(String, String)>().await.unwrap();
|
||||
println!("[{}]: {}", username, message);
|
||||
}
|
||||
println!("gracefully shut down");
|
||||
}
|
946
network/examples/fileshare/Cargo.lock
generated
Normal file
946
network/examples/fileshare/Cargo.lock
generated
Normal file
@ -0,0 +1,946 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "538ecb01eb64eecd772087e5b6f7540cbc917f047727339a472dafed2185b267"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-timer",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"mio",
|
||||
"mio-uds",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ac2c016b079e771204030951c366db398864f5026f84a44dafb0ff20f02085d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"maybe-uninit",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fileshare"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"bincode",
|
||||
"clap",
|
||||
"futures",
|
||||
"rand",
|
||||
"serde",
|
||||
"shellexpand",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"veloren_network",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c54d9f465d530a752e6ebdc217e081a7a614b48cb200f6f0aee21ba6bc9aabb"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-uds"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
|
||||
dependencies = [
|
||||
"iovec",
|
||||
"libc",
|
||||
"mio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f6a7f5eee6292c559c793430c55c00aea9d3b3d1905e855806ca4d7253426a2"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8988430ce790d8682672117bc06dda364c0be32d3abd738234f19f3240bad99a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5567486d5778e2c6455b1b90ff1c558f29e751fc018130fa182e15828e728af1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"quick-error",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae75d0445b5d3778c9da3d1f840faa16d0627c8607f78a74daf69e5b988c39a1"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2b22262a9aaf9464d356f656fea420634f78c881c5eebd5ef5e66d8b9bc603"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1721cc8cf7d770cc4257872507180f35a4797272f5962f24c806af9e7faf52ab"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58b0b7fd92dc7b71f29623cc6836dd7200f32161a2313dd78be233a8405694f6"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfc50df245be6f0adf35c399cb16dea60e2c7d6cc83ff5dc22d727df06dd6f0c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"matchers",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "veloren_network"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"bincode",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"prometheus",
|
||||
"rand",
|
||||
"serde",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
21
network/examples/fileshare/Cargo.toml
Normal file
21
network/examples/fileshare/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "fileshare"
|
||||
version = "0.1.0"
|
||||
authors = ["Marcel Märtens <marcel.cochem@googlemail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
network = { package = "veloren_network", path = "../../../network" }
|
||||
clap = { version = "2.33", default-features = false }
|
||||
async-std = { version = "1.5", default-features = false }
|
||||
futures = { version = "0.3", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
tracing-subscriber = { version = "0.2.3", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] }
|
||||
bincode = "1.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
rand = "0.7.3"
|
||||
shellexpand = "2.0.0"
|
87
network/examples/fileshare/src/commands.rs
Normal file
87
network/examples/fileshare/src/commands.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use async_std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use network::{Address, Participant, Stream};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LocalCommand {
|
||||
Shutdown,
|
||||
Disconnect,
|
||||
Connect(Address),
|
||||
List,
|
||||
Serve(FileInfo),
|
||||
Get(u32, Option<String>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Command {
|
||||
List,
|
||||
Get(u32),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct FileInfo {
|
||||
id: u32,
|
||||
pub path: String,
|
||||
pub size: u64,
|
||||
pub hash: String,
|
||||
}
|
||||
|
||||
pub struct RemoteInfo {
|
||||
infos: HashMap<u32, FileInfo>,
|
||||
_participant: Arc<Participant>,
|
||||
pub cmd_out: Stream,
|
||||
pub file_out: Stream,
|
||||
}
|
||||
|
||||
impl FileInfo {
|
||||
pub async fn new(path: &Path) -> Option<Self> {
|
||||
let mt = match fs::metadata(&path).await {
|
||||
Err(e) => {
|
||||
println!(
|
||||
"cannot get metadata for file: {:?}, does it exist? Error: {:?}",
|
||||
&path, &e
|
||||
);
|
||||
return None;
|
||||
},
|
||||
Ok(mt) => mt,
|
||||
};
|
||||
let size = mt.len();
|
||||
Some(Self {
|
||||
id: rand::thread_rng().gen(),
|
||||
path: path.as_os_str().to_os_string().into_string().unwrap(),
|
||||
size,
|
||||
hash: "<none>".to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn load(&self) -> Result<Vec<u8>, std::io::Error> { fs::read(self.path()).await }
|
||||
|
||||
pub fn id(&self) -> u32 { self.id }
|
||||
|
||||
pub fn path(&self) -> PathBuf { self.path.parse().unwrap() }
|
||||
}
|
||||
|
||||
impl RemoteInfo {
|
||||
pub fn new(cmd_out: Stream, file_out: Stream, participant: Arc<Participant>) -> Self {
|
||||
Self {
|
||||
infos: HashMap::new(),
|
||||
_participant: participant,
|
||||
cmd_out,
|
||||
file_out,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_info(&self, id: u32) -> Option<FileInfo> { self.infos.get(&id).map(|fi| fi.clone()) }
|
||||
|
||||
pub fn insert_infos(&mut self, mut fi: Vec<FileInfo>) {
|
||||
for fi in fi.drain(..) {
|
||||
self.infos.insert(fi.id(), fi);
|
||||
}
|
||||
}
|
||||
}
|
204
network/examples/fileshare/src/main.rs
Normal file
204
network/examples/fileshare/src/main.rs
Normal file
@ -0,0 +1,204 @@
|
||||
#![feature(async_closure, exclusive_range_pattern)]
|
||||
//!run with
|
||||
//! (cd network/examples/fileshare && RUST_BACKTRACE=1 cargo run --profile=release -Z unstable-options -- --trace=info --port 15006)
|
||||
//! (cd network/examples/fileshare && RUST_BACKTRACE=1 cargo run --profile=release -Z unstable-options -- --trace=info --port 15007)
|
||||
//! ```
|
||||
use async_std::{io, path::PathBuf};
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use futures::{
|
||||
channel::mpsc,
|
||||
executor::{block_on, ThreadPool},
|
||||
sink::SinkExt,
|
||||
};
|
||||
use network::Address;
|
||||
use std::{thread, time::Duration};
|
||||
use tracing::*;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
mod commands;
|
||||
mod server;
|
||||
use commands::{FileInfo, LocalCommand};
|
||||
use server::Server;
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("File Server")
|
||||
.version("0.1.0")
|
||||
.author("Marcel Märtens <marcel.cochem@googlemail.com>")
|
||||
.about("example file server implemented with veloren-network")
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.takes_value(true)
|
||||
.default_value("15006")
|
||||
.help("port to listen on"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("trace")
|
||||
.short("t")
|
||||
.long("trace")
|
||||
.takes_value(true)
|
||||
.default_value("warn")
|
||||
.possible_values(&["trace", "debug", "info", "warn", "error"])
|
||||
.help("set trace level, not this has a performance impact!"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let trace = matches.value_of("trace").unwrap();
|
||||
let filter = EnvFilter::from_default_env()
|
||||
.add_directive(trace.parse().unwrap())
|
||||
.add_directive("fileshare::server=trace".parse().unwrap())
|
||||
.add_directive("fileshare::commands=trace".parse().unwrap());
|
||||
tracing_subscriber::FmtSubscriber::builder()
|
||||
.with_max_level(Level::TRACE)
|
||||
.with_env_filter(filter)
|
||||
.init();
|
||||
|
||||
let port: u16 = matches.value_of("port").unwrap().parse().unwrap();
|
||||
let address = Address::Tcp(format!("{}:{}", "127.0.0.1", port).parse().unwrap());
|
||||
|
||||
let (server, cmd_sender) = Server::new();
|
||||
let pool = ThreadPool::new().unwrap();
|
||||
pool.spawn_ok(server.run(address));
|
||||
|
||||
thread::sleep(Duration::from_millis(50)); //just for trace
|
||||
|
||||
block_on(client(cmd_sender));
|
||||
}
|
||||
|
||||
fn file_exists(file: String) -> Result<(), String> {
|
||||
let file: std::path::PathBuf = shellexpand::tilde(&file).parse().unwrap();
|
||||
if file.exists() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("file does not exist"))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_options<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("")
|
||||
.setting(clap::AppSettings::NoBinaryName)
|
||||
.setting(clap::AppSettings::SubcommandRequired)
|
||||
.setting(clap::AppSettings::VersionlessSubcommands)
|
||||
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
|
||||
.setting(clap::AppSettings::ColorAuto)
|
||||
.subcommand(SubCommand::with_name("quit").about("closes program"))
|
||||
.subcommand(SubCommand::with_name("disconnect").about("stop connections to all servers"))
|
||||
.subcommand(SubCommand::with_name("t").about("quick test by connectiong to 127.0.0.1:1231"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("connect")
|
||||
.about("opens a connection to another instance of this fileserver network")
|
||||
.setting(clap::AppSettings::NoBinaryName)
|
||||
.arg(
|
||||
Arg::with_name("ip:port")
|
||||
.help("ip and port to connect to, example '127.0.0.1:1231'")
|
||||
.required(true)
|
||||
.validator(|ipport| match ipport.parse::<std::net::SocketAddr>() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(format!("must be valid Ip:Port combination {:?}", e)),
|
||||
}),
|
||||
),
|
||||
)
|
||||
.subcommand(SubCommand::with_name("list").about("lists all available files on the network"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("serve")
|
||||
.about("make file available on the network")
|
||||
.arg(
|
||||
Arg::with_name("file")
|
||||
.help("file to serve")
|
||||
.required(true)
|
||||
.validator(file_exists),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("get")
|
||||
.about(
|
||||
"downloads file with the id from the `list` command. Optionally provide a \
|
||||
storage path, if none is provided it will be saved in the current directory \
|
||||
with the remote filename",
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.help("id to download. get the id from the `list` command")
|
||||
.required(true)
|
||||
.validator(|id| match id.parse::<u32>() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(format!("must be a number {:?}", e)),
|
||||
}),
|
||||
)
|
||||
.arg(Arg::with_name("file").help("local path to store the file to")),
|
||||
)
|
||||
}
|
||||
|
||||
async fn client(mut cmd_sender: mpsc::UnboundedSender<LocalCommand>) {
|
||||
use std::io::Write;
|
||||
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
print!("==> ");
|
||||
std::io::stdout().flush().unwrap();
|
||||
io::stdin().read_line(&mut line).await.unwrap();
|
||||
let matches = match get_options().get_matches_from_safe(line.split_whitespace()) {
|
||||
Err(e) => {
|
||||
println!("{}", e.message);
|
||||
continue;
|
||||
},
|
||||
Ok(matches) => matches,
|
||||
};
|
||||
|
||||
match matches.subcommand() {
|
||||
("quit", _) => {
|
||||
cmd_sender.send(LocalCommand::Shutdown).await.unwrap();
|
||||
println!("goodbye");
|
||||
break;
|
||||
},
|
||||
("disconnect", _) => {
|
||||
cmd_sender.send(LocalCommand::Disconnect).await.unwrap();
|
||||
},
|
||||
("connect", Some(connect_matches)) => {
|
||||
let socketaddr = connect_matches.value_of("ip:port").unwrap().parse().unwrap();
|
||||
cmd_sender
|
||||
.send(LocalCommand::Connect(Address::Tcp(socketaddr)))
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
("t", _) => {
|
||||
cmd_sender
|
||||
.send(LocalCommand::Connect(Address::Tcp(
|
||||
"127.0.0.1:1231".parse().unwrap(),
|
||||
)))
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
("serve", Some(serve_matches)) => {
|
||||
let path = shellexpand::tilde(serve_matches.value_of("file").unwrap());
|
||||
let path: PathBuf = path.parse().unwrap();
|
||||
if let Some(fileinfo) = FileInfo::new(&path).await {
|
||||
cmd_sender
|
||||
.send(LocalCommand::Serve(fileinfo))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
("list", _) => {
|
||||
cmd_sender.send(LocalCommand::List).await.unwrap();
|
||||
},
|
||||
("get", Some(get_matches)) => {
|
||||
let id: u32 = get_matches.value_of("id").unwrap().parse().unwrap();
|
||||
let file = get_matches.value_of("file");
|
||||
cmd_sender
|
||||
.send(LocalCommand::Get(id, file.map(|s| s.to_string())))
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
|
||||
(_, _) => {
|
||||
unreachable!("this subcommand isn't yet handled");
|
||||
},
|
||||
}
|
||||
// this 100 ms is because i am super lazy, and i want to appear the logs before
|
||||
// the next '==>' appears...
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
println!("");
|
||||
}
|
||||
thread::sleep(Duration::from_millis(30)); // TODO: still needed for correct shutdown
|
||||
}
|
213
network/examples/fileshare/src/server.rs
Normal file
213
network/examples/fileshare/src/server.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use crate::commands::{Command, FileInfo, LocalCommand, RemoteInfo};
|
||||
use async_std::{
|
||||
fs,
|
||||
path::PathBuf,
|
||||
sync::{Mutex, RwLock},
|
||||
};
|
||||
use futures::{channel::mpsc, future::FutureExt, stream::StreamExt};
|
||||
use network::{Address, Network, Participant, Pid, Stream, PROMISES_CONSISTENCY, PROMISES_ORDERED};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tracing::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ControlChannels {
|
||||
command_receiver: mpsc::UnboundedReceiver<LocalCommand>,
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
run_channels: Option<ControlChannels>,
|
||||
network: Network,
|
||||
served: RwLock<Vec<FileInfo>>,
|
||||
remotes: RwLock<HashMap<Pid, Arc<Mutex<RemoteInfo>>>>,
|
||||
receiving_files: Mutex<HashMap<u32, Option<String>>>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new() -> (Self, mpsc::UnboundedSender<LocalCommand>) {
|
||||
let (command_sender, command_receiver) = mpsc::unbounded();
|
||||
|
||||
let (network, f) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f);
|
||||
|
||||
let run_channels = Some(ControlChannels { command_receiver });
|
||||
(
|
||||
Server {
|
||||
run_channels,
|
||||
network,
|
||||
served: RwLock::new(vec![]),
|
||||
remotes: RwLock::new(HashMap::new()),
|
||||
receiving_files: Mutex::new(HashMap::new()),
|
||||
},
|
||||
command_sender,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn run(mut self, address: Address) {
|
||||
let run_channels = self.run_channels.take().unwrap();
|
||||
|
||||
self.network.listen(address).await.unwrap();
|
||||
|
||||
futures::join!(
|
||||
self.command_manager(run_channels.command_receiver,),
|
||||
self.connect_manager(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn command_manager(&self, command_receiver: mpsc::UnboundedReceiver<LocalCommand>) {
|
||||
trace!("start command_manager");
|
||||
command_receiver
|
||||
.for_each_concurrent(None, async move |cmd| {
|
||||
match cmd {
|
||||
LocalCommand::Shutdown => {
|
||||
println!("shutting down service");
|
||||
return;
|
||||
},
|
||||
LocalCommand::Disconnect => {
|
||||
self.remotes.write().await.clear();
|
||||
for (_, p) in self.network.participants().await.drain() {
|
||||
self.network.disconnect(p).await.unwrap();
|
||||
}
|
||||
println!("disconnecting all connections");
|
||||
return;
|
||||
},
|
||||
LocalCommand::Connect(addr) => {
|
||||
println!("trying to connect to: {:?}", &addr);
|
||||
match self.network.connect(addr.clone()).await {
|
||||
Ok(p) => self.loop_participant(p).await,
|
||||
Err(e) => {
|
||||
println!("failled to connect to {:?}, err: {:?}", &addr, e);
|
||||
},
|
||||
}
|
||||
},
|
||||
LocalCommand::Serve(fileinfo) => {
|
||||
self.served.write().await.push(fileinfo.clone());
|
||||
println!("serving file: {:?}", fileinfo.path);
|
||||
},
|
||||
LocalCommand::List => {
|
||||
let mut total_file_infos = vec![];
|
||||
for ri in self.remotes.read().await.values() {
|
||||
let mut ri = ri.lock().await;
|
||||
ri.cmd_out.send(Command::List).unwrap();
|
||||
let mut file_infos = ri.cmd_out.recv::<Vec<FileInfo>>().await.unwrap();
|
||||
ri.insert_infos(file_infos.clone());
|
||||
total_file_infos.append(&mut file_infos);
|
||||
}
|
||||
print_fileinfos(&total_file_infos);
|
||||
},
|
||||
LocalCommand::Get(id, path) => {
|
||||
// i dont know the owner, just broadcast, i am laaaazyyy
|
||||
for ri in self.remotes.read().await.values() {
|
||||
let mut ri = ri.lock().await;
|
||||
if ri.get_info(id).is_some() {
|
||||
//found provider, send request.
|
||||
self.receiving_files.lock().await.insert(id, path.clone());
|
||||
ri.cmd_out.send(Command::Get(id)).unwrap();
|
||||
// the answer is handled via the other stream!
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
.await;
|
||||
trace!("stop command_manager");
|
||||
}
|
||||
|
||||
async fn connect_manager(&self) {
|
||||
trace!("start connect_manager");
|
||||
let iter = futures::stream::unfold((), |_| {
|
||||
self.network.connected().map(|r| r.ok().map(|v| (v, ())))
|
||||
});
|
||||
|
||||
iter.for_each_concurrent(/* limit */ None, async move |participant| {
|
||||
self.loop_participant(participant).await;
|
||||
})
|
||||
.await;
|
||||
trace!("stop connect_manager");
|
||||
}
|
||||
|
||||
async fn loop_participant(&self, p: Arc<Participant>) {
|
||||
if let (Ok(cmd_out), Ok(file_out), Ok(cmd_in), Ok(file_in)) = (
|
||||
p.open(15, PROMISES_CONSISTENCY | PROMISES_ORDERED).await,
|
||||
p.open(40, PROMISES_CONSISTENCY).await,
|
||||
p.opened().await,
|
||||
p.opened().await,
|
||||
) {
|
||||
debug!(?p, "connection successfully initiated");
|
||||
let id = p.remote_pid();
|
||||
let ri = Arc::new(Mutex::new(RemoteInfo::new(cmd_out, file_out, p)));
|
||||
self.remotes.write().await.insert(id, ri.clone());
|
||||
futures::join!(
|
||||
self.handle_remote_cmd(cmd_in, ri.clone()),
|
||||
self.handle_files(file_in, ri.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_remote_cmd(&self, mut stream: Stream, remote_info: Arc<Mutex<RemoteInfo>>) {
|
||||
while let Ok(msg) = stream.recv::<Command>().await {
|
||||
println!("got message: {:?}", &msg);
|
||||
match msg {
|
||||
Command::List => {
|
||||
info!("request to send my list");
|
||||
let served = self.served.read().await.clone();
|
||||
stream.send(served).unwrap();
|
||||
},
|
||||
Command::Get(id) => {
|
||||
for file_info in self.served.read().await.iter() {
|
||||
if file_info.id() == id {
|
||||
info!("request to send file i got, sending it");
|
||||
if let Ok(data) = file_info.load().await {
|
||||
match remote_info.lock().await.file_out.send((file_info, data)) {
|
||||
Ok(_) => debug!("send file"),
|
||||
Err(e) => error!(?e, "sending file failed"),
|
||||
}
|
||||
} else {
|
||||
warn!("cannot send file as loading failed, oes it still exist?");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_files(&self, mut stream: Stream, _remote_info: Arc<Mutex<RemoteInfo>>) {
|
||||
while let Ok((fi, data)) = stream.recv::<(FileInfo, Vec<u8>)>().await {
|
||||
debug!(?fi, "got file");
|
||||
let path = self.receiving_files.lock().await.remove(&fi.id()).flatten();
|
||||
let path: PathBuf = match &path {
|
||||
Some(path) => shellexpand::tilde(&path).parse().unwrap(),
|
||||
None => {
|
||||
let mut path = std::env::current_dir().unwrap();
|
||||
path.push(fi.path().file_name().unwrap());
|
||||
trace!("no path provided, saving down to {:?}", path);
|
||||
PathBuf::from(path)
|
||||
},
|
||||
};
|
||||
debug!("received file, going to save it under {:?}", path);
|
||||
fs::write(path, data).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_fileinfos(infos: &Vec<FileInfo>) {
|
||||
let mut i = 0;
|
||||
for info in infos {
|
||||
let bytes = info.size;
|
||||
match bytes {
|
||||
0..100_000 => println!("{}: {}bytes '{}'", info.id(), bytes, info.path),
|
||||
100_000..100_000_000 => {
|
||||
println!("{}: {}bytes '{}'", info.id(), bytes / 1024, info.path)
|
||||
},
|
||||
_ => println!(
|
||||
"{}: {}bytes '{}'",
|
||||
info.id(),
|
||||
bytes / 1024 / 1024,
|
||||
info.path
|
||||
),
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
println!("-- {} files available", i);
|
||||
}
|
937
network/examples/network-speed/Cargo.lock
generated
Normal file
937
network/examples/network-speed/Cargo.lock
generated
Normal file
@ -0,0 +1,937 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109"
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "538ecb01eb64eecd772087e5b6f7540cbc917f047727339a472dafed2185b267"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-timer",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"mio",
|
||||
"mio-uds",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ac2c016b079e771204030951c366db398864f5026f84a44dafb0ff20f02085d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chunked_transfer"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b89647f09b9f4c838cb622799b2843e4e13bff64661dab9a0362bb92985addd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"maybe-uninit",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ff57d6d215f7ca7eb35a9a64d656ba4d9d2bef114d741dc08048e75e2f5d418"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-uds"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||
dependencies = [
|
||||
"iovec",
|
||||
"libc",
|
||||
"mio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "network-speed"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"clap",
|
||||
"futures",
|
||||
"prometheus",
|
||||
"serde",
|
||||
"tiny_http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"veloren_network",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9df32da11d84f3a7d70205549562966279adb900e080fad3dccd8e64afccf0ad"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5567486d5778e2c6455b1b90ff1c558f29e751fc018130fa182e15828e728af1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"protobuf",
|
||||
"quick-error",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e86d370532557ae7573551a1ec8235a0f8d6cb276c7c9e6aa490b511c447485"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2c3ac8e6ca1e9c80b8be1023940162bf81ae3cffbb1809474152f2ce1eb250"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06d5a3f5166fb5b42a5439f2eee8b9de149e235961e3eb21c5808fc3ea17ff3e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93a56fabc59dce20fe48b6c832cc249c713e7ed88fa28b0ee0a3bfcaae5fe4e2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny_http"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15ce4fc3c4cdea1a4399bb1819a539195fb69db4bbe0bde5b7c7f18fed412e02"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"chrono",
|
||||
"chunked_transfer",
|
||||
"log",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7c6b59d116d218cb2d990eb06b77b64043e0268ef7323aae63d8b30ae462923"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d53c40489aa69c9aed21ff483f26886ca8403df33bdc2d2f87c60c1617826d2"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"matchers",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
dependencies = [
|
||||
"matches",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
||||
dependencies = [
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "veloren_network"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"bincode",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"prometheus",
|
||||
"rand",
|
||||
"serde",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
20
network/examples/network-speed/Cargo.toml
Normal file
20
network/examples/network-speed/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "network-speed"
|
||||
version = "0.1.0"
|
||||
authors = ["Marcel Märtens <marcel.cochem@googlemail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
network = { package = "veloren_network", path = "../../../network" }
|
||||
clap = { version = "2.33", default-features = false }
|
||||
futures = { version = "0.3", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
tracing-subscriber = { version = "0.2.3", default-features = false, features = ["env-filter", "fmt", "chrono", "ansi", "smallvec"] }
|
||||
bincode = "1.2"
|
||||
prometheus = "0.7"
|
||||
tiny_http = "0.7.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
189
network/examples/network-speed/src/main.rs
Normal file
189
network/examples/network-speed/src/main.rs
Normal file
@ -0,0 +1,189 @@
|
||||
///run with
|
||||
/// ```bash
|
||||
/// (cd network/examples/network-speed && RUST_BACKTRACE=1 cargo run --profile=debuginfo -Z unstable-options -- --trace=error --protocol=tcp --mode=server)
|
||||
/// (cd network/examples/network-speed && RUST_BACKTRACE=1 cargo run --profile=debuginfo -Z unstable-options -- --trace=error --protocol=tcp --mode=client)
|
||||
/// ```
|
||||
mod metrics;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use futures::executor::block_on;
|
||||
use network::{Address, MessageBuffer, Network, Pid, PROMISES_CONSISTENCY, PROMISES_ORDERED};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tracing::*;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
enum Msg {
|
||||
Ping { id: u64, data: Vec<u8> },
|
||||
Pong { id: u64, data: Vec<u8> },
|
||||
}
|
||||
|
||||
/// This utility tests the speed of veloren network by creating a client that
|
||||
/// opens a stream and pipes as many messages through it as possible.
|
||||
fn main() {
|
||||
let matches = App::new("Veloren Speed Test Utility")
|
||||
.version("0.1.0")
|
||||
.author("Marcel Märtens <marcel.cochem@googlemail.com>")
|
||||
.about("Runs speedtests regarding different parameter to benchmark veloren-network")
|
||||
.arg(
|
||||
Arg::with_name("mode")
|
||||
.short("m")
|
||||
.long("mode")
|
||||
.takes_value(true)
|
||||
.possible_values(&["server", "client", "both"])
|
||||
.default_value("both")
|
||||
.help(
|
||||
"choose whether you want to start the server or client or both needed for \
|
||||
this program",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.takes_value(true)
|
||||
.default_value("52000")
|
||||
.help("port to listen on"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ip")
|
||||
.long("ip")
|
||||
.takes_value(true)
|
||||
.default_value("127.0.0.1")
|
||||
.help("ip to listen and connect to"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("protocol")
|
||||
.long("protocol")
|
||||
.takes_value(true)
|
||||
.default_value("tcp")
|
||||
.possible_values(&["tcp", "udp", "mpsc"])
|
||||
.help(
|
||||
"underlying protocol used for this test, mpsc can only combined with mode=both",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("trace")
|
||||
.short("t")
|
||||
.long("trace")
|
||||
.takes_value(true)
|
||||
.default_value("warn")
|
||||
.possible_values(&["trace", "debug", "info", "warn", "error"])
|
||||
.help("set trace level, not this has a performance impact!"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let trace = matches.value_of("trace").unwrap();
|
||||
let filter = EnvFilter::from_default_env()
|
||||
.add_directive(trace.parse().unwrap())
|
||||
.add_directive("network_speed=debug".parse().unwrap())
|
||||
.add_directive("veloren_network::participant=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::protocol=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::scheduler=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::api=trace".parse().unwrap())
|
||||
/*
|
||||
.add_directive("veloren_network::participant=debug".parse().unwrap()).add_directive("veloren_network::api=debug".parse().unwrap())*/;
|
||||
tracing_subscriber::FmtSubscriber::builder()
|
||||
.with_max_level(Level::ERROR)
|
||||
.with_env_filter(filter)
|
||||
.init();
|
||||
|
||||
let port: u16 = matches.value_of("port").unwrap().parse().unwrap();
|
||||
let ip: &str = matches.value_of("ip").unwrap();
|
||||
let address = match matches.value_of("protocol") {
|
||||
Some("tcp") => Address::Tcp(format!("{}:{}", ip, port).parse().unwrap()),
|
||||
Some("udp") => Address::Udp(format!("{}:{}", ip, port).parse().unwrap()),
|
||||
_ => panic!("invalid mode, run --help!"),
|
||||
};
|
||||
|
||||
let mut background = None;
|
||||
match matches.value_of("mode") {
|
||||
Some("server") => server(address),
|
||||
Some("client") => client(address),
|
||||
Some("both") => {
|
||||
let address1 = address.clone();
|
||||
background = Some(thread::spawn(|| server(address1)));
|
||||
thread::sleep(Duration::from_millis(200)); //start client after server
|
||||
client(address);
|
||||
},
|
||||
_ => panic!("invalid mode, run --help!"),
|
||||
};
|
||||
if let Some(background) = background {
|
||||
background.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn server(address: Address) {
|
||||
let mut metrics = metrics::SimpleMetrics::new();
|
||||
let (server, f) = Network::new(Pid::new(), Some(metrics.registry()));
|
||||
std::thread::spawn(f);
|
||||
metrics.run("0.0.0.0:59112".parse().unwrap()).unwrap();
|
||||
block_on(server.listen(address)).unwrap();
|
||||
|
||||
loop {
|
||||
info!("waiting for participant to connect");
|
||||
let p1 = block_on(server.connected()).unwrap(); //remote representation of p1
|
||||
let mut s1 = block_on(p1.opened()).unwrap(); //remote representation of s1
|
||||
block_on(async {
|
||||
let mut last = Instant::now();
|
||||
let mut id = 0u64;
|
||||
while let Ok(_msg) = s1.recv_raw().await {
|
||||
id += 1;
|
||||
if id.rem_euclid(1000000) == 0 {
|
||||
let new = Instant::now();
|
||||
let diff = new.duration_since(last);
|
||||
last = new;
|
||||
println!("recv 1.000.000 took {}", diff.as_millis());
|
||||
}
|
||||
}
|
||||
info!("other stream was closed");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn client(address: Address) {
|
||||
let mut metrics = metrics::SimpleMetrics::new();
|
||||
let (client, f) = Network::new(Pid::new(), Some(metrics.registry()));
|
||||
std::thread::spawn(f);
|
||||
metrics.run("0.0.0.0:59111".parse().unwrap()).unwrap();
|
||||
|
||||
let p1 = block_on(client.connect(address.clone())).unwrap(); //remote representation of p1
|
||||
let mut s1 = block_on(p1.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY)).unwrap(); //remote representation of s1
|
||||
let mut last = Instant::now();
|
||||
let mut id = 0u64;
|
||||
let raw_msg = Arc::new(MessageBuffer {
|
||||
data: bincode::serialize(&Msg::Ping {
|
||||
id,
|
||||
data: vec![0; 1000],
|
||||
})
|
||||
.unwrap(),
|
||||
});
|
||||
loop {
|
||||
s1.send_raw(raw_msg.clone()).unwrap();
|
||||
id += 1;
|
||||
if id.rem_euclid(1000000) == 0 {
|
||||
let new = Instant::now();
|
||||
let diff = new.duration_since(last);
|
||||
last = new;
|
||||
println!("send 1.000.000 took {}", diff.as_millis());
|
||||
}
|
||||
if id > 2000000 {
|
||||
println!("stop");
|
||||
std::thread::sleep(std::time::Duration::from_millis(5000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
drop(s1);
|
||||
std::thread::sleep(std::time::Duration::from_millis(5000));
|
||||
info!("closing participant");
|
||||
block_on(client.disconnect(p1)).unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_millis(25000));
|
||||
info!("DROPPING! client");
|
||||
drop(client);
|
||||
std::thread::sleep(std::time::Duration::from_millis(25000));
|
||||
}
|
94
network/examples/network-speed/src/metrics.rs
Normal file
94
network/examples/network-speed/src/metrics.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use prometheus::{Encoder, Registry, TextEncoder};
|
||||
use std::{
|
||||
error::Error,
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
};
|
||||
use tiny_http;
|
||||
use tracing::*;
|
||||
|
||||
pub struct SimpleMetrics {
|
||||
running: Arc<AtomicBool>,
|
||||
handle: Option<thread::JoinHandle<()>>,
|
||||
registry: Option<Registry>,
|
||||
}
|
||||
|
||||
impl SimpleMetrics {
|
||||
pub fn new() -> Self {
|
||||
let running = Arc::new(AtomicBool::new(false));
|
||||
let registry = Some(Registry::new());
|
||||
|
||||
Self {
|
||||
running,
|
||||
handle: None,
|
||||
registry,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn registry(&self) -> &Registry {
|
||||
match self.registry {
|
||||
Some(ref r) => r,
|
||||
None => panic!("You cannot longer register new metrics after the server has started!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, addr: SocketAddr) -> Result<(), Box<dyn Error>> {
|
||||
self.running.store(true, Ordering::Relaxed);
|
||||
let running2 = self.running.clone();
|
||||
|
||||
let registry = self
|
||||
.registry
|
||||
.take()
|
||||
.expect("ServerMetrics must be already started");
|
||||
|
||||
//TODO: make this a job
|
||||
self.handle = Some(thread::spawn(move || {
|
||||
let server = tiny_http::Server::http(addr).unwrap();
|
||||
const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(1);
|
||||
debug!("starting tiny_http server to serve metrics");
|
||||
while running2.load(Ordering::Relaxed) {
|
||||
let request = match server.recv_timeout(TIMEOUT) {
|
||||
Ok(Some(rq)) => rq,
|
||||
Ok(None) => continue,
|
||||
Err(e) => {
|
||||
println!("error: {}", e);
|
||||
break;
|
||||
},
|
||||
};
|
||||
let mf = registry.gather();
|
||||
let encoder = TextEncoder::new();
|
||||
let mut buffer = vec![];
|
||||
encoder
|
||||
.encode(&mf, &mut buffer)
|
||||
.expect("Failed to encoder metrics text.");
|
||||
let response = tiny_http::Response::from_string(
|
||||
String::from_utf8(buffer).expect("Failed to parse bytes as a string."),
|
||||
);
|
||||
match request.respond(response) {
|
||||
Err(e) => error!(
|
||||
?e,
|
||||
"The metrics HTTP server had encountered and error with answering"
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
debug!("stopping tiny_http server to serve metrics");
|
||||
}));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SimpleMetrics {
|
||||
fn drop(&mut self) {
|
||||
self.running.store(false, Ordering::Relaxed);
|
||||
let handle = self.handle.take();
|
||||
handle
|
||||
.expect("ServerMetrics worker handle does not exist.")
|
||||
.join()
|
||||
.expect("Error shutting down prometheus metric exporter");
|
||||
}
|
||||
}
|
84
network/examples/tcp-loadtest/Cargo.lock
generated
Normal file
84
network/examples/tcp-loadtest/Cargo.lock
generated
Normal file
@ -0,0 +1,84 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tcp-loadtest"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
13
network/examples/tcp-loadtest/Cargo.toml
Normal file
13
network/examples/tcp-loadtest/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "tcp-loadtest"
|
||||
version = "0.1.0"
|
||||
authors = ["Marcel Märtens <marcel.cochem@googlemail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
rand = "0.7"
|
112
network/examples/tcp-loadtest/src/main.rs
Normal file
112
network/examples/tcp-loadtest/src/main.rs
Normal file
@ -0,0 +1,112 @@
|
||||
//!run with
|
||||
//! ```bash
|
||||
//! (cd network/examples/tcp-loadtest && RUST_BACKTRACE=1 cargo run 127.0.0.1 52000)
|
||||
//! ```
|
||||
use std::{
|
||||
env,
|
||||
io::Write,
|
||||
net::{SocketAddr, TcpStream},
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
extern crate rand;
|
||||
|
||||
fn setup() -> Result<SocketAddr, u32> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() < 3 {
|
||||
println!("usage: tcp-loadtest <ip> <port>");
|
||||
println!("example: tcp-loadtest 127.0.0.1 52000");
|
||||
return Err(1);
|
||||
}
|
||||
let a: SocketAddr = format!("{}:{}", args[1], args[2]).parse().unwrap();
|
||||
println!("You provided address: {}", &a);
|
||||
return Ok(a);
|
||||
}
|
||||
/// This example file is not running veloren-network at all,
|
||||
/// instead it's just trying to create 4 threads and pump as much bytes as
|
||||
/// possible through a specific listener, the listener needs to be created
|
||||
/// before this program is started.
|
||||
fn main() -> Result<(), u32> {
|
||||
let addr = Arc::new(setup()?);
|
||||
let data: Arc<String> = Arc::new(
|
||||
(0..1000000)
|
||||
.map(|_| (0x20u8 + (rand::random::<f32>() * 96.0) as u8) as char)
|
||||
.collect(),
|
||||
);
|
||||
|
||||
let total_bytes_send = Arc::new(AtomicU64::new(0));
|
||||
let total_send_count = Arc::new(AtomicU64::new(0));
|
||||
let total_finished_threads = Arc::new(AtomicU64::new(0));
|
||||
let start_time = Instant::now();
|
||||
|
||||
let mut threads = Vec::new();
|
||||
let thread_count = 4;
|
||||
for i in 0..thread_count {
|
||||
let addr = addr.clone();
|
||||
let total_bytes_send = total_bytes_send.clone();
|
||||
let total_send_count = total_send_count.clone();
|
||||
let total_finished_threads = total_finished_threads.clone();
|
||||
let data = data.clone();
|
||||
threads.push(thread::spawn(move || {
|
||||
let mut stream = match TcpStream::connect(addr.as_ref()) {
|
||||
Err(err) => {
|
||||
total_finished_threads.fetch_add(1, Ordering::Relaxed);
|
||||
panic!("could not open connection: {}", err);
|
||||
},
|
||||
Ok(s) => s,
|
||||
};
|
||||
let mut thread_bytes_send: u64 = 0;
|
||||
let mut thread_last_sync = Instant::now();
|
||||
|
||||
loop {
|
||||
let tosend: u64 = rand::random::<u16>() as u64 * 10 + 1000;
|
||||
thread_bytes_send += tosend;
|
||||
|
||||
let cur = Instant::now();
|
||||
if cur.duration_since(thread_last_sync) >= Duration::from_secs(1) {
|
||||
thread_last_sync = cur;
|
||||
println!("[{}]send: {}MiB/s", i, thread_bytes_send / (1024 * 1024));
|
||||
total_bytes_send.fetch_add(thread_bytes_send, Ordering::Relaxed);
|
||||
thread_bytes_send = 0;
|
||||
}
|
||||
|
||||
total_send_count.fetch_add(1, Ordering::Relaxed);
|
||||
let ret = stream.write_all(data[0..(tosend as usize)].as_bytes());
|
||||
if ret.is_err() {
|
||||
println!("[{}] error: {}", i, ret.err().unwrap());
|
||||
total_finished_threads.fetch_add(1, Ordering::Relaxed);
|
||||
return;
|
||||
}
|
||||
//stream.flush();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
while total_finished_threads.load(Ordering::Relaxed) < thread_count {
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
|
||||
let cur = Instant::now();
|
||||
let dur = cur.duration_since(start_time);
|
||||
println!("================");
|
||||
println!("test endet");
|
||||
println!(
|
||||
"total send: {}MiB",
|
||||
total_bytes_send.load(Ordering::Relaxed) / (1024 * 1024)
|
||||
);
|
||||
println!("total time: {}s", dur.as_secs());
|
||||
println!(
|
||||
"average: {}KiB/s",
|
||||
total_bytes_send.load(Ordering::Relaxed) * 1000 / dur.as_millis() as u64 / 1024
|
||||
);
|
||||
println!(
|
||||
"send count: {}/s",
|
||||
total_send_count.load(Ordering::Relaxed) * 1000 / dur.as_millis() as u64
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
1031
network/src/api.rs
Normal file
1031
network/src/api.rs
Normal file
File diff suppressed because it is too large
Load Diff
341
network/src/channel.rs
Normal file
341
network/src/channel.rs
Normal file
@ -0,0 +1,341 @@
|
||||
use crate::{
|
||||
metrics::NetworkMetrics,
|
||||
protocols::Protocols,
|
||||
types::{
|
||||
Cid, Frame, Pid, Sid, STREAM_ID_OFFSET1, STREAM_ID_OFFSET2, VELOREN_MAGIC_NUMBER,
|
||||
VELOREN_NETWORK_VERSION,
|
||||
},
|
||||
};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
join,
|
||||
sink::SinkExt,
|
||||
stream::StreamExt,
|
||||
FutureExt,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tracing::*;
|
||||
|
||||
pub(crate) struct Channel {
|
||||
cid: Cid,
|
||||
c2w_frame_r: Option<mpsc::UnboundedReceiver<Frame>>,
|
||||
read_stop_receiver: Option<oneshot::Receiver<()>>,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn new(cid: u64) -> (Self, mpsc::UnboundedSender<Frame>, oneshot::Sender<()>) {
|
||||
let (c2w_frame_s, c2w_frame_r) = mpsc::unbounded::<Frame>();
|
||||
let (read_stop_sender, read_stop_receiver) = oneshot::channel();
|
||||
(
|
||||
Self {
|
||||
cid,
|
||||
c2w_frame_r: Some(c2w_frame_r),
|
||||
read_stop_receiver: Some(read_stop_receiver),
|
||||
},
|
||||
c2w_frame_s,
|
||||
read_stop_sender,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn run(
|
||||
mut self,
|
||||
protocol: Protocols,
|
||||
mut w2c_cid_frame_s: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
mut leftover_cid_frame: Vec<(Cid, Frame)>,
|
||||
) {
|
||||
let c2w_frame_r = self.c2w_frame_r.take().unwrap();
|
||||
let read_stop_receiver = self.read_stop_receiver.take().unwrap();
|
||||
|
||||
//reapply leftovers from handshake
|
||||
let cnt = leftover_cid_frame.len();
|
||||
trace!(?self.cid, ?cnt, "reapplying leftovers");
|
||||
for cid_frame in leftover_cid_frame.drain(..) {
|
||||
w2c_cid_frame_s.send(cid_frame).await.unwrap();
|
||||
}
|
||||
trace!(?self.cid, ?cnt, "all leftovers reapplied");
|
||||
|
||||
trace!(?self.cid, "start up channel");
|
||||
match protocol {
|
||||
Protocols::Tcp(tcp) => {
|
||||
futures::join!(
|
||||
tcp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
tcp.write_to_wire(self.cid, c2w_frame_r),
|
||||
);
|
||||
},
|
||||
Protocols::Udp(udp) => {
|
||||
futures::join!(
|
||||
udp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
udp.write_to_wire(self.cid, c2w_frame_r),
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
trace!(?self.cid, "shut down channel");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Handshake {
|
||||
cid: Cid,
|
||||
local_pid: Pid,
|
||||
secret: u128,
|
||||
init_handshake: bool,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
}
|
||||
|
||||
impl Handshake {
|
||||
#[cfg(debug_assertions)]
|
||||
const WRONG_NUMBER: &'static [u8] = "Handshake does not contain the magic number requiered by \
|
||||
veloren server.\nWe are not sure if you are a valid \
|
||||
veloren client.\nClosing the connection"
|
||||
.as_bytes();
|
||||
#[cfg(debug_assertions)]
|
||||
const WRONG_VERSION: &'static str = "Handshake does contain a correct magic number, but \
|
||||
invalid version.\nWe don't know how to communicate with \
|
||||
you.\nClosing the connection";
|
||||
|
||||
pub fn new(
|
||||
cid: u64,
|
||||
local_pid: Pid,
|
||||
secret: u128,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
init_handshake: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
cid,
|
||||
local_pid,
|
||||
secret,
|
||||
metrics,
|
||||
init_handshake,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn setup(
|
||||
self,
|
||||
protocol: &Protocols,
|
||||
) -> Result<(Pid, Sid, u128, Vec<(Cid, Frame)>), ()> {
|
||||
let (c2w_frame_s, c2w_frame_r) = mpsc::unbounded::<Frame>();
|
||||
let (mut w2c_cid_frame_s, mut w2c_cid_frame_r) = mpsc::unbounded::<(Cid, Frame)>();
|
||||
|
||||
let (read_stop_sender, read_stop_receiver) = oneshot::channel();
|
||||
let handler_future =
|
||||
self.frame_handler(&mut w2c_cid_frame_r, c2w_frame_s, read_stop_sender);
|
||||
let res = match protocol {
|
||||
Protocols::Tcp(tcp) => {
|
||||
(join! {
|
||||
tcp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
tcp.write_to_wire(self.cid, c2w_frame_r).fuse(),
|
||||
handler_future,
|
||||
})
|
||||
.2
|
||||
},
|
||||
Protocols::Udp(udp) => {
|
||||
(join! {
|
||||
udp.read_from_wire(self.cid, &mut w2c_cid_frame_s, read_stop_receiver),
|
||||
udp.write_to_wire(self.cid, c2w_frame_r),
|
||||
handler_future,
|
||||
})
|
||||
.2
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::unit_arg)]
|
||||
match res {
|
||||
Ok(res) => {
|
||||
let mut leftover_frames = vec![];
|
||||
while let Ok(Some(cid_frame)) = w2c_cid_frame_r.try_next() {
|
||||
leftover_frames.push(cid_frame);
|
||||
}
|
||||
let cnt = leftover_frames.len();
|
||||
if cnt > 0 {
|
||||
debug!(?self.cid, ?cnt, "Some additional frames got already transfered, piping them to the bparticipant as leftover_frames");
|
||||
}
|
||||
Ok((res.0, res.1, res.2, leftover_frames))
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn frame_handler(
|
||||
&self,
|
||||
w2c_cid_frame_r: &mut mpsc::UnboundedReceiver<(Cid, Frame)>,
|
||||
mut c2w_frame_s: mpsc::UnboundedSender<Frame>,
|
||||
_read_stop_sender: oneshot::Sender<()>,
|
||||
) -> Result<(Pid, Sid, u128), ()> {
|
||||
const ERR_S: &str = "Got A Raw Message, these are usually Debug Messages indicating that \
|
||||
something went wrong on network layer and connection will be closed";
|
||||
let mut pid_string = "".to_string();
|
||||
let cid_string = self.cid.to_string();
|
||||
|
||||
if self.init_handshake {
|
||||
self.send_handshake(&mut c2w_frame_s).await;
|
||||
}
|
||||
|
||||
match w2c_cid_frame_r.next().await {
|
||||
Some((
|
||||
_,
|
||||
Frame::Handshake {
|
||||
magic_number,
|
||||
version,
|
||||
},
|
||||
)) => {
|
||||
trace!(?magic_number, ?version, "recv handshake");
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&["", &cid_string, "Handshake"])
|
||||
.inc();
|
||||
if magic_number != VELOREN_MAGIC_NUMBER {
|
||||
error!(?magic_number, "connection with invalid magic_number");
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
self.metrics
|
||||
.frames_out_total
|
||||
.with_label_values(&["", &cid_string, "Raw"])
|
||||
.inc();
|
||||
debug!("sending client instructions before killing");
|
||||
c2w_frame_s
|
||||
.send(Frame::Raw(Self::WRONG_NUMBER.to_vec()))
|
||||
.await
|
||||
.unwrap();
|
||||
c2w_frame_s.send(Frame::Shutdown).await.unwrap();
|
||||
}
|
||||
return Err(());
|
||||
}
|
||||
if version != VELOREN_NETWORK_VERSION {
|
||||
error!(?version, "connection with wrong network version");
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug!("sending client instructions before killing");
|
||||
self.metrics
|
||||
.frames_out_total
|
||||
.with_label_values(&["", &cid_string, "Raw"])
|
||||
.inc();
|
||||
c2w_frame_s
|
||||
.send(Frame::Raw(
|
||||
format!(
|
||||
"{} Our Version: {:?}\nYour Version: {:?}\nClosing the \
|
||||
connection",
|
||||
Self::WRONG_VERSION,
|
||||
VELOREN_NETWORK_VERSION,
|
||||
version,
|
||||
)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
c2w_frame_s.send(Frame::Shutdown {}).await.unwrap();
|
||||
}
|
||||
return Err(());
|
||||
}
|
||||
debug!("handshake completed");
|
||||
if self.init_handshake {
|
||||
self.send_init(&mut c2w_frame_s, &pid_string).await;
|
||||
} else {
|
||||
self.send_handshake(&mut c2w_frame_s).await;
|
||||
}
|
||||
},
|
||||
Some((_, Frame::Shutdown)) => {
|
||||
info!("shutdown signal received");
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, "Shutdown"])
|
||||
.inc();
|
||||
return Err(());
|
||||
},
|
||||
Some((_, Frame::Raw(bytes))) => {
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, "Raw"])
|
||||
.inc();
|
||||
match std::str::from_utf8(bytes.as_slice()) {
|
||||
Ok(string) => error!(?string, ERR_S),
|
||||
_ => error!(?bytes, ERR_S),
|
||||
}
|
||||
return Err(());
|
||||
},
|
||||
Some((_, frame)) => {
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, frame.get_string()])
|
||||
.inc();
|
||||
return Err(());
|
||||
},
|
||||
None => return Err(()),
|
||||
};
|
||||
|
||||
match w2c_cid_frame_r.next().await {
|
||||
Some((_, Frame::Init { pid, secret })) => {
|
||||
debug!(?pid, "Participant send their ID");
|
||||
pid_string = pid.to_string();
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, "ParticipantId"])
|
||||
.inc();
|
||||
let stream_id_offset = if self.init_handshake {
|
||||
STREAM_ID_OFFSET1
|
||||
} else {
|
||||
self.send_init(&mut c2w_frame_s, &pid_string).await;
|
||||
STREAM_ID_OFFSET2
|
||||
};
|
||||
info!(?pid, "this Handshake is now configured!");
|
||||
Ok((pid, stream_id_offset, secret))
|
||||
},
|
||||
Some((_, Frame::Shutdown)) => {
|
||||
info!("shutdown signal received");
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, "Shutdown"])
|
||||
.inc();
|
||||
Err(())
|
||||
},
|
||||
Some((_, Frame::Raw(bytes))) => {
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, "Raw"])
|
||||
.inc();
|
||||
match std::str::from_utf8(bytes.as_slice()) {
|
||||
Ok(string) => error!(?string, ERR_S),
|
||||
_ => error!(?bytes, ERR_S),
|
||||
}
|
||||
Err(())
|
||||
},
|
||||
Some((_, frame)) => {
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&pid_string, &cid_string, frame.get_string()])
|
||||
.inc();
|
||||
Err(())
|
||||
},
|
||||
None => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_handshake(&self, c2w_frame_s: &mut mpsc::UnboundedSender<Frame>) {
|
||||
self.metrics
|
||||
.frames_out_total
|
||||
.with_label_values(&["", &self.cid.to_string(), "Handshake"])
|
||||
.inc();
|
||||
c2w_frame_s
|
||||
.send(Frame::Handshake {
|
||||
magic_number: VELOREN_MAGIC_NUMBER,
|
||||
version: VELOREN_NETWORK_VERSION,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn send_init(&self, c2w_frame_s: &mut mpsc::UnboundedSender<Frame>, pid_string: &str) {
|
||||
self.metrics
|
||||
.frames_out_total
|
||||
.with_label_values(&[pid_string, &self.cid.to_string(), "ParticipantId"])
|
||||
.inc();
|
||||
c2w_frame_s
|
||||
.send(Frame::Init {
|
||||
pid: self.local_pid,
|
||||
secret: self.secret,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
118
network/src/lib.rs
Normal file
118
network/src/lib.rs
Normal file
@ -0,0 +1,118 @@
|
||||
#![deny(unsafe_code)]
|
||||
#![cfg_attr(test, deny(rust_2018_idioms))]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
#![feature(try_trait, const_if_match)]
|
||||
|
||||
//! Crate to handle high level networking of messages with different
|
||||
//! requirements and priorities over a number of protocols
|
||||
//!
|
||||
//! To start with the `veloren_network` crate you should focus on the 3
|
||||
//! elementar structs [`Network`], [`Participant`] and [`Stream`].
|
||||
//!
|
||||
//! Say you have an application that wants to communicate with other application
|
||||
//! over a Network or on the same computer. Now each application instances the
|
||||
//! struct [`Network`] once with a new [`Pid`]. The Pid is necessary to identify
|
||||
//! other [`Networks`] over the network protocols (e.g. TCP, UDP)
|
||||
//!
|
||||
//! To connect to another application, you must know it's [`Address`]. One side
|
||||
//! will call [`connect`], the other [`connected`]. If successfull both
|
||||
//! applications will now get a [`Arc<Participant>`].
|
||||
//!
|
||||
//! This [`Participant`] represents the connection between those 2 applications.
|
||||
//! over the respective [`Address`] and with it the choosen network protocol.
|
||||
//! However messages can't be send directly via [`Participants`], instead you
|
||||
//! must open a [`Stream`] on it. Like above, one side has to call [`open`], the
|
||||
//! other [`opened`]. [`Streams`] can have a different priority and
|
||||
//! [`Promises`].
|
||||
//!
|
||||
//! You can now use the [`Stream`] to [`send`] and [`recv`] in both directions.
|
||||
//! You can send all kind of messages that implement [`serde`].
|
||||
//! As the receiving side needs to know the format, it sometimes is useful to
|
||||
//! always send a specific Enum and then handling it with a big `match`
|
||||
//! statement This create makes heavily use of `async`, except for [`send`]
|
||||
//! which returns always directly.
|
||||
//!
|
||||
//! For best practices see the `examples` folder of this crate containing useful
|
||||
//! code snippets, a simple client/server below. Of course due to the async
|
||||
//! nature, no strict client server separation is necessary
|
||||
//!
|
||||
//! # Examples
|
||||
//! ```rust
|
||||
//! use async_std::task::sleep;
|
||||
//! use futures::{executor::block_on, join};
|
||||
//! use veloren_network::{Address, Network, Pid, PROMISES_CONSISTENCY, PROMISES_ORDERED};
|
||||
//!
|
||||
//! // Client
|
||||
//! async fn client() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
//! sleep(std::time::Duration::from_secs(1)).await; // `connect` MUST be after `listen`
|
||||
//! let (client_network, f) = Network::new(Pid::new(), None);
|
||||
//! std::thread::spawn(f);
|
||||
//! let server = client_network
|
||||
//! .connect(Address::Tcp("127.0.0.1:12345".parse().unwrap()))
|
||||
//! .await?;
|
||||
//! let mut stream = server
|
||||
//! .open(10, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
//! .await?;
|
||||
//! stream.send("Hello World")?;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! // Server
|
||||
//! async fn server() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
//! let (server_network, f) = Network::new(Pid::new(), None);
|
||||
//! std::thread::spawn(f);
|
||||
//! server_network
|
||||
//! .listen(Address::Tcp("127.0.0.1:12345".parse().unwrap()))
|
||||
//! .await?;
|
||||
//! let client = server_network.connected().await?;
|
||||
//! let mut stream = client.opened().await?;
|
||||
//! let msg: String = stream.recv().await?;
|
||||
//! println!("got message: {}", msg);
|
||||
//! assert_eq!(msg, "Hello World");
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
//! block_on(async {
|
||||
//! let (result_c, result_s) = join!(client(), server(),);
|
||||
//! result_c?;
|
||||
//! result_s?;
|
||||
//! Ok(())
|
||||
//! })
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`Network`]: crate::api::Network
|
||||
//! [`Networks`]: crate::api::Network
|
||||
//! [`connect`]: crate::api::Network::connect
|
||||
//! [`connected`]: crate::api::Network::connected
|
||||
//! [`Arc<Participant>`]: crate::api::Participant
|
||||
//! [`Participant`]: crate::api::Participant
|
||||
//! [`Participants`]: crate::api::Participant
|
||||
//! [`open`]: crate::api::Participant::open
|
||||
//! [`opened`]: crate::api::Participant::opened
|
||||
//! [`Stream`]: crate::api::Stream
|
||||
//! [`Streams`]: crate::api::Stream
|
||||
//! [`send`]: crate::api::Stream::send
|
||||
//! [`recv`]: crate::api::Stream::recv
|
||||
//! [`Pid`]: crate::types::Pid
|
||||
//! [`Address`]: crate::api::Address
|
||||
//! [`Promises`]: crate::types::Promises
|
||||
|
||||
mod api;
|
||||
mod channel;
|
||||
mod message;
|
||||
mod metrics;
|
||||
mod participant;
|
||||
mod prios;
|
||||
mod protocols;
|
||||
mod scheduler;
|
||||
#[macro_use]
|
||||
mod types;
|
||||
|
||||
pub use api::{Address, Network, NetworkError, Participant, ParticipantError, Stream, StreamError};
|
||||
pub use message::MessageBuffer;
|
||||
pub use types::{
|
||||
Pid, Promises, PROMISES_COMPRESSED, PROMISES_CONSISTENCY, PROMISES_ENCRYPTED,
|
||||
PROMISES_GUARANTEED_DELIVERY, PROMISES_NONE, PROMISES_ORDERED,
|
||||
};
|
146
network/src/message.rs
Normal file
146
network/src/message.rs
Normal file
@ -0,0 +1,146 @@
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
//use std::collections::VecDeque;
|
||||
use crate::types::{Mid, Sid};
|
||||
use std::{io, sync::Arc};
|
||||
|
||||
//Todo: Evaluate switching to VecDeque for quickly adding and removing data
|
||||
// from front, back.
|
||||
// - It would prob requiere custom bincode code but thats possible.
|
||||
/// Support struct used for optimising sending the same Message to multiple
|
||||
/// [`Stream`]
|
||||
///
|
||||
/// For an example usage see: [`send_raw`]
|
||||
///
|
||||
/// [`Stream`]: crate::api::Stream
|
||||
/// [`send_raw`]: crate::api::Stream::send_raw
|
||||
pub struct MessageBuffer {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct OutgoingMessage {
|
||||
pub buffer: Arc<MessageBuffer>,
|
||||
pub cursor: u64,
|
||||
pub mid: Mid,
|
||||
pub sid: Sid,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct IncomingMessage {
|
||||
pub buffer: MessageBuffer,
|
||||
pub length: u64,
|
||||
pub mid: Mid,
|
||||
pub sid: Sid,
|
||||
}
|
||||
|
||||
pub(crate) fn serialize<M: Serialize>(message: &M) -> MessageBuffer {
|
||||
//this will never fail: https://docs.rs/bincode/0.8.0/bincode/fn.serialize.html
|
||||
let writer = bincode::serialize(message).unwrap();
|
||||
MessageBuffer { data: writer }
|
||||
}
|
||||
|
||||
//pub(crate) fn deserialize<M: DeserializeOwned>(buffer: MessageBuffer) ->
|
||||
// std::Result<M, std::Box<bincode::error::bincode::ErrorKind>> {
|
||||
pub(crate) fn deserialize<M: DeserializeOwned>(buffer: MessageBuffer) -> bincode::Result<M> {
|
||||
let span = buffer.data;
|
||||
//this might fail if you choose the wrong type for M. in that case probably X
|
||||
// got transfered while you assume Y. probably this means your application
|
||||
// logic is wrong. E.g. You expect a String, but just get a u8.
|
||||
bincode::deserialize(span.as_slice())
|
||||
}
|
||||
|
||||
///wouldn't trust this aaaassss much, fine for tests
|
||||
pub(crate) fn partial_eq_io_error(first: &io::Error, second: &io::Error) -> bool {
|
||||
if let Some(f) = first.raw_os_error() {
|
||||
if let Some(s) = second.raw_os_error() {
|
||||
f == s
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
let fk = first.kind();
|
||||
fk == second.kind() && fk != io::ErrorKind::Other
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn partial_eq_bincode(first: &bincode::ErrorKind, second: &bincode::ErrorKind) -> bool {
|
||||
match *first {
|
||||
bincode::ErrorKind::Io(ref f) => match *second {
|
||||
bincode::ErrorKind::Io(ref s) => partial_eq_io_error(f, s),
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidUtf8Encoding(f) => match *second {
|
||||
bincode::ErrorKind::InvalidUtf8Encoding(s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidBoolEncoding(f) => match *second {
|
||||
bincode::ErrorKind::InvalidBoolEncoding(s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidCharEncoding => match *second {
|
||||
bincode::ErrorKind::InvalidCharEncoding => true,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::InvalidTagEncoding(f) => match *second {
|
||||
bincode::ErrorKind::InvalidTagEncoding(s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::DeserializeAnyNotSupported => match *second {
|
||||
bincode::ErrorKind::DeserializeAnyNotSupported => true,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::SizeLimit => match *second {
|
||||
bincode::ErrorKind::SizeLimit => true,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::SequenceMustHaveLength => match *second {
|
||||
bincode::ErrorKind::SequenceMustHaveLength => true,
|
||||
_ => false,
|
||||
},
|
||||
bincode::ErrorKind::Custom(ref f) => match *second {
|
||||
bincode::ErrorKind::Custom(ref s) => f == s,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for MessageBuffer {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
//TODO: small messages!
|
||||
let len = self.data.len();
|
||||
if len > 20 {
|
||||
write!(
|
||||
f,
|
||||
"MessageBuffer(len: {}, {}, {}, {}, {:?}..{:?})",
|
||||
len,
|
||||
u32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]]),
|
||||
u32::from_le_bytes([self.data[4], self.data[5], self.data[6], self.data[7]]),
|
||||
u32::from_le_bytes([self.data[8], self.data[9], self.data[10], self.data[11]]),
|
||||
&self.data[13..16],
|
||||
&self.data[len - 8..len]
|
||||
)
|
||||
} else {
|
||||
write!(f, "MessageBuffer(len: {}, {:?})", len, &self.data[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::message::*;
|
||||
|
||||
#[test]
|
||||
fn serialize_test() {
|
||||
let msg = "abc";
|
||||
let mb = serialize(&msg);
|
||||
assert_eq!(mb.data.len(), 11);
|
||||
assert_eq!(mb.data[0], 3);
|
||||
assert_eq!(mb.data[1], 0);
|
||||
assert_eq!(mb.data[7], 0);
|
||||
assert_eq!(mb.data[8], 'a' as u8);
|
||||
assert_eq!(mb.data[8], 97);
|
||||
assert_eq!(mb.data[9], 'b' as u8);
|
||||
assert_eq!(mb.data[10], 'c' as u8);
|
||||
}
|
||||
}
|
397
network/src/metrics.rs
Normal file
397
network/src/metrics.rs
Normal file
@ -0,0 +1,397 @@
|
||||
use crate::types::{Cid, Frame, Pid};
|
||||
use prometheus::{
|
||||
core::{AtomicI64, GenericCounter},
|
||||
IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Opts, Registry,
|
||||
};
|
||||
use std::error::Error;
|
||||
use tracing::*;
|
||||
|
||||
//TODO: switch over to Counter for frames_count, message_count, bytes_send,
|
||||
// frames_message_count 1 NetworkMetrics per Network
|
||||
#[allow(dead_code)]
|
||||
pub struct NetworkMetrics {
|
||||
pub listen_requests_total: IntCounterVec,
|
||||
pub connect_requests_total: IntCounterVec,
|
||||
pub participants_connected_total: IntCounter,
|
||||
pub participants_disconnected_total: IntCounter,
|
||||
// opened Channels, seperated by PARTICIPANT
|
||||
pub channels_connected_total: IntCounterVec,
|
||||
pub channels_disconnected_total: IntCounterVec,
|
||||
// opened streams, seperated by PARTICIPANT
|
||||
pub streams_opened_total: IntCounterVec,
|
||||
pub streams_closed_total: IntCounterVec,
|
||||
pub network_info: IntGauge,
|
||||
// Frames counted a channel level, seperated by CHANNEL (and PARTICIPANT) AND FRAME TYPE,
|
||||
pub frames_out_total: IntCounterVec,
|
||||
pub frames_in_total: IntCounterVec,
|
||||
// Frames counted at protocol level, seperated by CHANNEL (and PARTICIPANT) AND FRAME TYPE,
|
||||
pub frames_wire_out_total: IntCounterVec,
|
||||
pub frames_wire_in_total: IntCounterVec,
|
||||
// throughput at protocol level, seperated by CHANNEL (and PARTICIPANT),
|
||||
pub wire_out_throughput: IntCounterVec,
|
||||
pub wire_in_throughput: IntCounterVec,
|
||||
// send(prio) Messages count, seperated by STREAM AND PARTICIPANT,
|
||||
pub message_out_total: IntCounterVec,
|
||||
// send(prio) Messages throughput, seperated by STREAM AND PARTICIPANT,
|
||||
pub message_out_throughput: IntCounterVec,
|
||||
// TODO: queued Messages, seperated by STREAM (add PART, CHANNEL),
|
||||
// queued Messages, seperated by PARTICIPANT
|
||||
pub queued_count: IntGaugeVec,
|
||||
// TODO: queued Messages bytes, seperated by STREAM (add PART, CHANNEL),
|
||||
// queued Messages bytes, seperated by PARTICIPANT
|
||||
pub queued_bytes: IntGaugeVec,
|
||||
// ping calculated based on last msg seperated by PARTICIPANT
|
||||
pub participants_ping: IntGaugeVec,
|
||||
}
|
||||
|
||||
impl NetworkMetrics {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(local_pid: &Pid) -> Result<Self, Box<dyn Error>> {
|
||||
let listen_requests_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"listen_requests_total",
|
||||
"shows the number of listen requests to the scheduler",
|
||||
),
|
||||
&["protocol"],
|
||||
)?;
|
||||
let connect_requests_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"connect_requests_total",
|
||||
"shows the number of connect requests to the scheduler",
|
||||
),
|
||||
&["protocol"],
|
||||
)?;
|
||||
let participants_connected_total = IntCounter::with_opts(Opts::new(
|
||||
"participants_connected_total",
|
||||
"shows the number of participants connected to the network",
|
||||
))?;
|
||||
let participants_disconnected_total = IntCounter::with_opts(Opts::new(
|
||||
"participants_disconnected_total",
|
||||
"shows the number of participants disconnected to the network",
|
||||
))?;
|
||||
let channels_connected_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"channels_connected_total",
|
||||
"number of all channels currently connected on the network",
|
||||
),
|
||||
&["participant"],
|
||||
)?;
|
||||
let channels_disconnected_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"channels_disconnected_total",
|
||||
"number of all channels currently disconnected on the network",
|
||||
),
|
||||
&["participant"],
|
||||
)?;
|
||||
let streams_opened_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"streams_opened_total",
|
||||
"number of all streams currently open on the network",
|
||||
),
|
||||
&["participant"],
|
||||
)?;
|
||||
let streams_closed_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"streams_closed_total",
|
||||
"number of all streams currently open on the network",
|
||||
),
|
||||
&["participant"],
|
||||
)?;
|
||||
let opts = Opts::new("network_info", "Static Network information")
|
||||
.const_label(
|
||||
"version",
|
||||
&format!(
|
||||
"{}.{}.{}",
|
||||
&crate::types::VELOREN_NETWORK_VERSION[0],
|
||||
&crate::types::VELOREN_NETWORK_VERSION[1],
|
||||
&crate::types::VELOREN_NETWORK_VERSION[2]
|
||||
),
|
||||
)
|
||||
.const_label("local_pid", &format!("{}", &local_pid));
|
||||
let network_info = IntGauge::with_opts(opts)?;
|
||||
let frames_out_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"frames_out_total",
|
||||
"number of all frames send per channel, at the channel level",
|
||||
),
|
||||
&["participant", "channel", "frametype"],
|
||||
)?;
|
||||
let frames_in_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"frames_in_total",
|
||||
"number of all frames received per channel, at the channel level",
|
||||
),
|
||||
&["participant", "channel", "frametype"],
|
||||
)?;
|
||||
let frames_wire_out_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"frames_wire_out_total",
|
||||
"number of all frames send per channel, at the protocol level",
|
||||
),
|
||||
&["channel", "frametype"],
|
||||
)?;
|
||||
let frames_wire_in_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"frames_wire_in_total",
|
||||
"number of all frames received per channel, at the protocol level",
|
||||
),
|
||||
&["channel", "frametype"],
|
||||
)?;
|
||||
let wire_out_throughput = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"wire_out_throughput",
|
||||
"throupgput of all data frames send per channel, at the protocol level",
|
||||
),
|
||||
&["channel"],
|
||||
)?;
|
||||
let wire_in_throughput = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"wire_in_throughput",
|
||||
"throupgput of all data frames send per channel, at the protocol level",
|
||||
),
|
||||
&["channel"],
|
||||
)?;
|
||||
//TODO IN
|
||||
let message_out_total = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"message_out_total",
|
||||
"number of messages send by streams on the network",
|
||||
),
|
||||
&["participant", "stream"],
|
||||
)?;
|
||||
//TODO IN
|
||||
let message_out_throughput = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"message_out_throughput",
|
||||
"throughput of messages send by streams on the network",
|
||||
),
|
||||
&["participant", "stream"],
|
||||
)?;
|
||||
let queued_count = IntGaugeVec::new(
|
||||
Opts::new(
|
||||
"queued_count",
|
||||
"queued number of messages by participant on the network",
|
||||
),
|
||||
&["channel"],
|
||||
)?;
|
||||
let queued_bytes = IntGaugeVec::new(
|
||||
Opts::new(
|
||||
"queued_bytes",
|
||||
"queued bytes of messages by participant on the network",
|
||||
),
|
||||
&["channel"],
|
||||
)?;
|
||||
let participants_ping = IntGaugeVec::new(
|
||||
Opts::new(
|
||||
"participants_ping",
|
||||
"ping time to participants on the network",
|
||||
),
|
||||
&["channel"],
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
listen_requests_total,
|
||||
connect_requests_total,
|
||||
participants_connected_total,
|
||||
participants_disconnected_total,
|
||||
channels_connected_total,
|
||||
channels_disconnected_total,
|
||||
streams_opened_total,
|
||||
streams_closed_total,
|
||||
network_info,
|
||||
frames_out_total,
|
||||
frames_in_total,
|
||||
frames_wire_out_total,
|
||||
frames_wire_in_total,
|
||||
wire_out_throughput,
|
||||
wire_in_throughput,
|
||||
message_out_total,
|
||||
message_out_throughput,
|
||||
queued_count,
|
||||
queued_bytes,
|
||||
participants_ping,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register(&self, registry: &Registry) -> Result<(), Box<dyn Error>> {
|
||||
registry.register(Box::new(self.listen_requests_total.clone()))?;
|
||||
registry.register(Box::new(self.connect_requests_total.clone()))?;
|
||||
registry.register(Box::new(self.participants_connected_total.clone()))?;
|
||||
registry.register(Box::new(self.participants_disconnected_total.clone()))?;
|
||||
registry.register(Box::new(self.channels_connected_total.clone()))?;
|
||||
registry.register(Box::new(self.channels_disconnected_total.clone()))?;
|
||||
registry.register(Box::new(self.streams_opened_total.clone()))?;
|
||||
registry.register(Box::new(self.streams_closed_total.clone()))?;
|
||||
registry.register(Box::new(self.network_info.clone()))?;
|
||||
registry.register(Box::new(self.frames_out_total.clone()))?;
|
||||
registry.register(Box::new(self.frames_in_total.clone()))?;
|
||||
registry.register(Box::new(self.frames_wire_out_total.clone()))?;
|
||||
registry.register(Box::new(self.frames_wire_in_total.clone()))?;
|
||||
registry.register(Box::new(self.wire_out_throughput.clone()))?;
|
||||
registry.register(Box::new(self.wire_in_throughput.clone()))?;
|
||||
registry.register(Box::new(self.message_out_total.clone()))?;
|
||||
registry.register(Box::new(self.message_out_throughput.clone()))?;
|
||||
registry.register(Box::new(self.queued_count.clone()))?;
|
||||
registry.register(Box::new(self.queued_bytes.clone()))?;
|
||||
registry.register(Box::new(self.participants_ping.clone()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//pub fn _is_100th_tick(&self) -> bool {
|
||||
// self.tick.load(Ordering::Relaxed).rem_euclid(100) == 0 }
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for NetworkMetrics {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "NetworkMetrics()")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub(crate) struct PidCidFrameCache<T: MetricVecBuilder> {
|
||||
metric: MetricVec<T>,
|
||||
pid: String,
|
||||
cache: Vec<[T::M; 8]>,
|
||||
}
|
||||
*/
|
||||
|
||||
pub(crate) struct PidCidFrameCache {
|
||||
metric: IntCounterVec,
|
||||
pid: String,
|
||||
cache: Vec<[GenericCounter<AtomicI64>; Frame::FRAMES_LEN as usize]>,
|
||||
}
|
||||
|
||||
impl PidCidFrameCache {
|
||||
const CACHE_SIZE: usize = 16;
|
||||
|
||||
pub fn new(metric: IntCounterVec, pid: Pid) -> Self {
|
||||
Self {
|
||||
metric,
|
||||
pid: pid.to_string(),
|
||||
cache: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn populate(&mut self, cid: Cid) {
|
||||
let start_cid = self.cache.len();
|
||||
for i in start_cid..=cid as usize {
|
||||
let cid = (i as Cid).to_string();
|
||||
let entry = [
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(0)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(1)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(2)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(3)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(4)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(5)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(6)]),
|
||||
self.metric
|
||||
.with_label_values(&[&self.pid, &cid, Frame::int_to_string(7)]),
|
||||
];
|
||||
self.cache.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_label_values(&mut self, cid: Cid, frame: &Frame) -> &GenericCounter<AtomicI64> {
|
||||
if cid > (Self::CACHE_SIZE as Cid) {
|
||||
warn!(
|
||||
?cid,
|
||||
"cid, getting quite high, is this a attack on the cache?"
|
||||
);
|
||||
}
|
||||
self.populate(cid);
|
||||
&self.cache[cid as usize][frame.get_int() as usize]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CidFrameCache {
|
||||
cache: [GenericCounter<AtomicI64>; Frame::FRAMES_LEN as usize],
|
||||
}
|
||||
|
||||
impl CidFrameCache {
|
||||
pub fn new(metric: IntCounterVec, cid: Cid) -> Self {
|
||||
let cid = cid.to_string();
|
||||
let cache = [
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(0)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(1)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(2)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(3)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(4)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(5)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(6)]),
|
||||
metric.with_label_values(&[&cid, Frame::int_to_string(7)]),
|
||||
];
|
||||
Self { cache }
|
||||
}
|
||||
|
||||
pub fn with_label_values(&mut self, frame: &Frame) -> &GenericCounter<AtomicI64> {
|
||||
&self.cache[frame.get_int() as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
metrics::*,
|
||||
types::{Frame, Pid},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn register_metrics() {
|
||||
let registry = Registry::new();
|
||||
let metrics = NetworkMetrics::new(&Pid::fake(1)).unwrap();
|
||||
metrics.register(®istry).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pid_cid_frame_cache() {
|
||||
let pid = Pid::fake(1);
|
||||
let frame1 = Frame::Raw("Foo".as_bytes().to_vec());
|
||||
let frame2 = Frame::Raw("Bar".as_bytes().to_vec());
|
||||
let metrics = NetworkMetrics::new(&pid).unwrap();
|
||||
let mut cache = PidCidFrameCache::new(metrics.frames_in_total, pid);
|
||||
let v1 = cache.with_label_values(1, &frame1);
|
||||
v1.inc();
|
||||
assert_eq!(v1.get(), 1);
|
||||
let v2 = cache.with_label_values(1, &frame1);
|
||||
v2.inc();
|
||||
assert_eq!(v2.get(), 2);
|
||||
let v3 = cache.with_label_values(1, &frame2);
|
||||
v3.inc();
|
||||
assert_eq!(v3.get(), 3);
|
||||
let v4 = cache.with_label_values(3, &frame1);
|
||||
v4.inc();
|
||||
assert_eq!(v4.get(), 1);
|
||||
let v5 = cache.with_label_values(3, &Frame::Shutdown);
|
||||
v5.inc();
|
||||
assert_eq!(v5.get(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cid_frame_cache() {
|
||||
let pid = Pid::fake(1);
|
||||
let frame1 = Frame::Raw("Foo".as_bytes().to_vec());
|
||||
let frame2 = Frame::Raw("Bar".as_bytes().to_vec());
|
||||
let metrics = NetworkMetrics::new(&pid).unwrap();
|
||||
let mut cache = CidFrameCache::new(metrics.frames_wire_out_total, 1);
|
||||
let v1 = cache.with_label_values(&frame1);
|
||||
v1.inc();
|
||||
assert_eq!(v1.get(), 1);
|
||||
let v2 = cache.with_label_values(&frame1);
|
||||
v2.inc();
|
||||
assert_eq!(v2.get(), 2);
|
||||
let v3 = cache.with_label_values(&frame2);
|
||||
v3.inc();
|
||||
assert_eq!(v3.get(), 3);
|
||||
let v4 = cache.with_label_values(&Frame::Shutdown);
|
||||
v4.inc();
|
||||
assert_eq!(v4.get(), 1);
|
||||
}
|
||||
}
|
308
network/src/mio_worker.rs
Normal file
308
network/src/mio_worker.rs
Normal file
@ -0,0 +1,308 @@
|
||||
use crate::{api::Promise, internal::Channel, message::OutGoingMessage, tcp_channel::TcpChannel};
|
||||
use enumset::EnumSet;
|
||||
use mio::{self, net::TcpListener, Poll, PollOpt, Ready, Token};
|
||||
use mio_extras::channel::{channel, Receiver, Sender};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{mpsc::TryRecvError, Arc, RwLock},
|
||||
time::Instant,
|
||||
};
|
||||
use tlid;
|
||||
use tracing::{debug, error, info, span, trace, warn, Level};
|
||||
use uvth::ThreadPool;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum TokenObjects {
|
||||
TcpListener(TcpListener),
|
||||
TcpChannel(TcpChannel),
|
||||
}
|
||||
|
||||
pub(crate) struct MioTokens {
|
||||
pool: tlid::Pool<tlid::Wrapping<usize>>,
|
||||
pub tokens: HashMap<Token, TokenObjects>, //TODO: move to Vec<Options> for faster lookup
|
||||
}
|
||||
|
||||
impl MioTokens {
|
||||
pub fn new(pool: tlid::Pool<tlid::Wrapping<usize>>) -> Self {
|
||||
MioTokens {
|
||||
pool,
|
||||
tokens: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct(&mut self) -> Token { Token(self.pool.next()) }
|
||||
|
||||
pub fn insert(&mut self, tok: Token, obj: TokenObjects) {
|
||||
trace!(?tok, ?obj, "added new token");
|
||||
self.tokens.insert(tok, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// MioStatistics should be copied in order to not hold locks for long
|
||||
#[derive(Clone, Default)]
|
||||
pub struct MioStatistics {
|
||||
nano_wait: u128,
|
||||
nano_busy: u128,
|
||||
}
|
||||
|
||||
pub(crate) enum CtrlMsg {
|
||||
Shutdown,
|
||||
Register(TokenObjects, Ready, PollOpt),
|
||||
OpenStream {
|
||||
pid: uuid::Uuid,
|
||||
prio: u8,
|
||||
promises: EnumSet<Promise>,
|
||||
},
|
||||
CloseStream {
|
||||
pid: uuid::Uuid,
|
||||
sid: u32,
|
||||
},
|
||||
Send(OutGoingMessage),
|
||||
}
|
||||
|
||||
/*
|
||||
The MioWorker runs in it's own thread,
|
||||
it has a given set of Channels to work with.
|
||||
It is monitored, and when it's thread is fully loaded it can be splitted up into 2 MioWorkers
|
||||
*/
|
||||
pub struct MioWorker {
|
||||
tag: u64, /* only relevant for logs */
|
||||
pid: uuid::Uuid,
|
||||
poll: Arc<Poll>,
|
||||
mio_statistics: Arc<RwLock<MioStatistics>>,
|
||||
ctrl_tx: Sender<CtrlMsg>,
|
||||
}
|
||||
|
||||
impl MioWorker {
|
||||
pub const CTRL_TOK: Token = Token(0);
|
||||
|
||||
pub fn new(
|
||||
tag: u64,
|
||||
pid: uuid::Uuid,
|
||||
thread_pool: Arc<ThreadPool>,
|
||||
mut token_pool: tlid::Pool<tlid::Wrapping<usize>>,
|
||||
) -> Self {
|
||||
let poll = Arc::new(Poll::new().unwrap());
|
||||
let poll_clone = poll.clone();
|
||||
let mio_statistics = Arc::new(RwLock::new(MioStatistics::default()));
|
||||
let mio_statistics_clone = mio_statistics.clone();
|
||||
|
||||
let (ctrl_tx, ctrl_rx) = channel();
|
||||
poll.register(&ctrl_rx, Self::CTRL_TOK, Ready::readable(), PollOpt::edge())
|
||||
.unwrap();
|
||||
// reserve 10 tokens in case they start with 0, //TODO: cleaner method
|
||||
for _ in 0..10 {
|
||||
token_pool.next();
|
||||
}
|
||||
|
||||
let mw = MioWorker {
|
||||
tag,
|
||||
pid,
|
||||
poll,
|
||||
mio_statistics,
|
||||
ctrl_tx,
|
||||
};
|
||||
thread_pool.execute(move || {
|
||||
mio_worker(
|
||||
tag,
|
||||
pid,
|
||||
poll_clone,
|
||||
mio_statistics_clone,
|
||||
token_pool,
|
||||
ctrl_rx,
|
||||
)
|
||||
});
|
||||
mw
|
||||
}
|
||||
|
||||
pub fn get_load_ratio(&self) -> f32 {
|
||||
let statistics = self.mio_statistics.read().unwrap();
|
||||
statistics.nano_busy as f32 / (statistics.nano_busy + statistics.nano_wait + 1) as f32
|
||||
}
|
||||
|
||||
//TODO: split 4->5 MioWorkers and merge 5->4 MioWorkers
|
||||
|
||||
pub(crate) fn get_tx(&self) -> Sender<CtrlMsg> { self.ctrl_tx.clone() }
|
||||
}
|
||||
|
||||
impl Drop for MioWorker {
|
||||
fn drop(&mut self) { let _ = self.ctrl_tx.send(CtrlMsg::Shutdown); }
|
||||
}
|
||||
|
||||
fn mio_worker(
|
||||
tag: u64,
|
||||
pid: uuid::Uuid,
|
||||
poll: Arc<Poll>,
|
||||
mio_statistics: Arc<RwLock<MioStatistics>>,
|
||||
mut token_pool: tlid::Pool<tlid::Wrapping<usize>>,
|
||||
ctrl_rx: Receiver<CtrlMsg>,
|
||||
) {
|
||||
let mut mio_tokens = MioTokens::new(token_pool);
|
||||
let mut events = mio::Events::with_capacity(1024);
|
||||
let mut buf: [u8; 65000] = [0; 65000];
|
||||
let span = span!(Level::INFO, "mio worker", ?tag);
|
||||
let _enter = span.enter();
|
||||
loop {
|
||||
let time_before_poll = Instant::now();
|
||||
if let Err(err) = poll.poll(&mut events, None) {
|
||||
error!("network poll error: {}", err);
|
||||
return;
|
||||
}
|
||||
let time_after_poll = Instant::now();
|
||||
for event in &events {
|
||||
match event.token() {
|
||||
MioWorker::CTRL_TOK => {
|
||||
if handle_ctl(&ctrl_rx, &mut mio_tokens, &poll, &mut buf, time_after_poll) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => handle_tok(
|
||||
pid,
|
||||
event,
|
||||
&mut mio_tokens,
|
||||
&poll,
|
||||
&mut buf,
|
||||
time_after_poll,
|
||||
),
|
||||
};
|
||||
}
|
||||
handle_statistics(&mio_statistics, time_before_poll, time_after_poll);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_ctl(
|
||||
ctrl_rx: &Receiver<CtrlMsg>,
|
||||
mio_tokens: &mut MioTokens,
|
||||
poll: &Arc<Poll>,
|
||||
buf: &mut [u8; 65000],
|
||||
time_after_poll: Instant,
|
||||
) -> bool {
|
||||
match ctrl_rx.try_recv() {
|
||||
Ok(CtrlMsg::Shutdown) => {
|
||||
debug!("Shutting Down");
|
||||
return true;
|
||||
},
|
||||
Ok(CtrlMsg::Register(handle, interest, opts)) => {
|
||||
let tok = mio_tokens.construct();
|
||||
match &handle {
|
||||
TokenObjects::TcpListener(h) => poll.register(h, tok, interest, opts).unwrap(),
|
||||
TokenObjects::TcpChannel(channel) => poll
|
||||
.register(&channel.tcpstream, tok, interest, opts)
|
||||
.unwrap(),
|
||||
}
|
||||
debug!(?handle, ?tok, "Registered new handle");
|
||||
mio_tokens.insert(tok, handle);
|
||||
},
|
||||
Ok(CtrlMsg::OpenStream {
|
||||
pid,
|
||||
prio,
|
||||
promises,
|
||||
}) => {
|
||||
for (tok, obj) in mio_tokens.tokens.iter_mut() {
|
||||
if let TokenObjects::TcpChannel(channel) = obj {
|
||||
channel.open_stream(prio, promises); //TODO: check participant
|
||||
channel.write(buf, time_after_poll);
|
||||
}
|
||||
}
|
||||
//TODO:
|
||||
},
|
||||
Ok(CtrlMsg::CloseStream { pid, sid }) => {
|
||||
//TODO:
|
||||
for to in mio_tokens.tokens.values_mut() {
|
||||
if let TokenObjects::TcpChannel(channel) = to {
|
||||
channel.close_stream(sid); //TODO: check participant
|
||||
channel.write(buf, time_after_poll);
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(_) => unimplemented!("dad"),
|
||||
Err(TryRecvError::Empty) => {},
|
||||
Err(err) => {
|
||||
//postbox_tx.send(Err(err.into()))?;
|
||||
return true;
|
||||
},
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn handle_tok(
|
||||
pid: uuid::Uuid,
|
||||
event: mio::Event,
|
||||
mio_tokens: &mut MioTokens,
|
||||
poll: &Arc<Poll>,
|
||||
buf: &mut [u8; 65000],
|
||||
time_after_poll: Instant,
|
||||
) {
|
||||
match mio_tokens.tokens.get_mut(&event.token()) {
|
||||
Some(e) => {
|
||||
trace!(?event, "event");
|
||||
match e {
|
||||
TokenObjects::TcpListener(listener) => match listener.accept() {
|
||||
Ok((mut remote_stream, _)) => {
|
||||
info!(?remote_stream, "remote connected");
|
||||
|
||||
let tok = mio_tokens.construct();
|
||||
poll.register(
|
||||
&remote_stream,
|
||||
tok,
|
||||
Ready::readable() | Ready::writable(),
|
||||
PollOpt::edge(),
|
||||
)
|
||||
.unwrap();
|
||||
trace!(?remote_stream, ?tok, "registered");
|
||||
let mut channel = TcpChannel::new(remote_stream);
|
||||
channel.handshake();
|
||||
channel.participant_id(pid);
|
||||
|
||||
mio_tokens
|
||||
.tokens
|
||||
.insert(tok, TokenObjects::TcpChannel(channel));
|
||||
},
|
||||
Err(err) => {
|
||||
error!(?err, "error during remote connected");
|
||||
},
|
||||
},
|
||||
TokenObjects::TcpChannel(channel) => {
|
||||
if event.readiness().is_readable() {
|
||||
trace!(?channel.tcpstream, "stream readable");
|
||||
channel.read(buf, time_after_poll);
|
||||
}
|
||||
if event.readiness().is_writable() {
|
||||
trace!(?channel.tcpstream, "stream writeable");
|
||||
channel.write(buf, time_after_poll);
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
None => panic!("Unexpected event token '{:?}'", &event.token()),
|
||||
};
|
||||
}
|
||||
|
||||
fn handle_statistics(
|
||||
mio_statistics: &Arc<RwLock<MioStatistics>>,
|
||||
time_before_poll: Instant,
|
||||
time_after_poll: Instant,
|
||||
) {
|
||||
let time_after_work = Instant::now();
|
||||
match mio_statistics.try_write() {
|
||||
Ok(mut mio_statistics) => {
|
||||
const OLD_KEEP_FACTOR: f64 = 0.995;
|
||||
//in order to weight new data stronger than older we fade them out with a
|
||||
// factor < 1. for 0.995 under full load (500 ticks a 1ms) we keep 8% of the old
|
||||
// value this means, that we start to see load comming up after
|
||||
// 500ms, but not for small spikes - as reordering for smaller spikes would be
|
||||
// to slow
|
||||
mio_statistics.nano_wait = (mio_statistics.nano_wait as f64 * OLD_KEEP_FACTOR) as u128
|
||||
+ time_after_poll.duration_since(time_before_poll).as_nanos();
|
||||
mio_statistics.nano_busy = (mio_statistics.nano_busy as f64 * OLD_KEEP_FACTOR) as u128
|
||||
+ time_after_work.duration_since(time_after_poll).as_nanos();
|
||||
|
||||
trace!(
|
||||
"current Load {}",
|
||||
mio_statistics.nano_busy as f32
|
||||
/ (mio_statistics.nano_busy + mio_statistics.nano_wait + 1) as f32
|
||||
);
|
||||
},
|
||||
Err(e) => warn!("statistics dropped because they are currently accecssed"),
|
||||
}
|
||||
}
|
625
network/src/participant.rs
Normal file
625
network/src/participant.rs
Normal file
@ -0,0 +1,625 @@
|
||||
use crate::{
|
||||
api::Stream,
|
||||
channel::Channel,
|
||||
message::{IncomingMessage, MessageBuffer, OutgoingMessage},
|
||||
metrics::{NetworkMetrics, PidCidFrameCache},
|
||||
prios::PrioManager,
|
||||
protocols::Protocols,
|
||||
types::{Cid, Frame, Pid, Prio, Promises, Sid},
|
||||
};
|
||||
use async_std::sync::RwLock;
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
future::FutureExt,
|
||||
select,
|
||||
sink::SinkExt,
|
||||
stream::StreamExt,
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tracing::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ChannelInfo {
|
||||
cid: Cid,
|
||||
cid_string: String, //optimisationmetrics
|
||||
b2w_frame_s: mpsc::UnboundedSender<Frame>,
|
||||
b2r_read_shutdown: oneshot::Sender<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StreamInfo {
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
b2a_msg_recv_s: mpsc::UnboundedSender<IncomingMessage>,
|
||||
closed: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
struct ControlChannels {
|
||||
a2b_steam_open_r: mpsc::UnboundedReceiver<(Prio, Promises, oneshot::Sender<Stream>)>,
|
||||
b2a_stream_opened_s: mpsc::UnboundedSender<Stream>,
|
||||
s2b_create_channel_r:
|
||||
mpsc::UnboundedReceiver<(Cid, Sid, Protocols, Vec<(Cid, Frame)>, oneshot::Sender<()>)>,
|
||||
a2b_close_stream_r: mpsc::UnboundedReceiver<Sid>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
s2b_shutdown_bparticipant_r: oneshot::Receiver<oneshot::Sender<async_std::io::Result<()>>>, /* own */
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BParticipant {
|
||||
remote_pid: Pid,
|
||||
remote_pid_string: String, //optimisation
|
||||
offset_sid: Sid,
|
||||
channels: Arc<RwLock<Vec<ChannelInfo>>>,
|
||||
streams: RwLock<HashMap<Sid, StreamInfo>>,
|
||||
running_mgr: AtomicUsize,
|
||||
run_channels: Option<ControlChannels>,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
}
|
||||
|
||||
impl BParticipant {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn new(
|
||||
remote_pid: Pid,
|
||||
offset_sid: Sid,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
) -> (
|
||||
Self,
|
||||
mpsc::UnboundedSender<(Prio, Promises, oneshot::Sender<Stream>)>,
|
||||
mpsc::UnboundedReceiver<Stream>,
|
||||
mpsc::UnboundedSender<(Cid, Sid, Protocols, Vec<(Cid, Frame)>, oneshot::Sender<()>)>,
|
||||
oneshot::Sender<oneshot::Sender<async_std::io::Result<()>>>,
|
||||
) {
|
||||
let (a2b_steam_open_s, a2b_steam_open_r) =
|
||||
mpsc::unbounded::<(Prio, Promises, oneshot::Sender<Stream>)>();
|
||||
let (b2a_stream_opened_s, b2a_stream_opened_r) = mpsc::unbounded::<Stream>();
|
||||
let (a2b_close_stream_s, a2b_close_stream_r) = mpsc::unbounded();
|
||||
let (s2b_shutdown_bparticipant_s, s2b_shutdown_bparticipant_r) = oneshot::channel();
|
||||
let (s2b_create_channel_s, s2b_create_channel_r) = mpsc::unbounded();
|
||||
|
||||
let run_channels = Some(ControlChannels {
|
||||
a2b_steam_open_r,
|
||||
b2a_stream_opened_s,
|
||||
s2b_create_channel_r,
|
||||
a2b_close_stream_r,
|
||||
a2b_close_stream_s,
|
||||
s2b_shutdown_bparticipant_r,
|
||||
});
|
||||
|
||||
(
|
||||
Self {
|
||||
remote_pid,
|
||||
remote_pid_string: remote_pid.to_string(),
|
||||
offset_sid,
|
||||
channels: Arc::new(RwLock::new(vec![])),
|
||||
streams: RwLock::new(HashMap::new()),
|
||||
running_mgr: AtomicUsize::new(0),
|
||||
run_channels,
|
||||
metrics,
|
||||
},
|
||||
a2b_steam_open_s,
|
||||
b2a_stream_opened_r,
|
||||
s2b_create_channel_s,
|
||||
s2b_shutdown_bparticipant_s,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn run(mut self, b2s_prio_statistic_s: mpsc::UnboundedSender<(Pid, u64, u64)>) {
|
||||
//those managers that listen on api::Participant need an additional oneshot for
|
||||
// shutdown scenario, those handled by scheduler will be closed by it.
|
||||
let (shutdown_send_mgr_sender, shutdown_send_mgr_receiver) = oneshot::channel();
|
||||
let (shutdown_stream_close_mgr_sender, shutdown_stream_close_mgr_receiver) =
|
||||
oneshot::channel();
|
||||
let (shutdown_open_mgr_sender, shutdown_open_mgr_receiver) = oneshot::channel();
|
||||
let (b2b_prios_flushed_s, b2b_prios_flushed_r) = oneshot::channel();
|
||||
let (w2b_frames_s, w2b_frames_r) = mpsc::unbounded::<(Cid, Frame)>();
|
||||
let (prios, a2p_msg_s, b2p_notify_empty_stream_s) =
|
||||
PrioManager::new(self.metrics.clone(), self.remote_pid_string.clone());
|
||||
|
||||
let run_channels = self.run_channels.take().unwrap();
|
||||
futures::join!(
|
||||
self.open_mgr(
|
||||
run_channels.a2b_steam_open_r,
|
||||
run_channels.a2b_close_stream_s.clone(),
|
||||
a2p_msg_s.clone(),
|
||||
shutdown_open_mgr_receiver,
|
||||
),
|
||||
self.handle_frames_mgr(
|
||||
w2b_frames_r,
|
||||
run_channels.b2a_stream_opened_s,
|
||||
run_channels.a2b_close_stream_s,
|
||||
a2p_msg_s.clone(),
|
||||
),
|
||||
self.create_channel_mgr(run_channels.s2b_create_channel_r, w2b_frames_s),
|
||||
self.send_mgr(
|
||||
prios,
|
||||
shutdown_send_mgr_receiver,
|
||||
b2b_prios_flushed_s,
|
||||
b2s_prio_statistic_s
|
||||
),
|
||||
self.stream_close_mgr(
|
||||
run_channels.a2b_close_stream_r,
|
||||
shutdown_stream_close_mgr_receiver,
|
||||
b2p_notify_empty_stream_s,
|
||||
),
|
||||
self.participant_shutdown_mgr(
|
||||
run_channels.s2b_shutdown_bparticipant_r,
|
||||
b2b_prios_flushed_r,
|
||||
vec!(
|
||||
shutdown_send_mgr_sender,
|
||||
shutdown_open_mgr_sender,
|
||||
shutdown_stream_close_mgr_sender
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async fn send_mgr(
|
||||
&self,
|
||||
mut prios: PrioManager,
|
||||
mut shutdown_send_mgr_receiver: oneshot::Receiver<()>,
|
||||
b2b_prios_flushed_s: oneshot::Sender<()>,
|
||||
mut b2s_prio_statistic_s: mpsc::UnboundedSender<(Pid, u64, u64)>,
|
||||
) {
|
||||
//This time equals the MINIMUM Latency in average, so keep it down and //Todo:
|
||||
// make it configureable or switch to await E.g. Prio 0 = await, prio 50
|
||||
// wait for more messages
|
||||
const TICK_TIME: Duration = Duration::from_millis(10);
|
||||
const FRAMES_PER_TICK: usize = 10005;
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
let mut closing_up = false;
|
||||
trace!("start send_mgr");
|
||||
let mut send_cache =
|
||||
PidCidFrameCache::new(self.metrics.frames_out_total.clone(), self.remote_pid);
|
||||
//while !self.closed.load(Ordering::Relaxed) {
|
||||
loop {
|
||||
let mut frames = VecDeque::new();
|
||||
prios.fill_frames(FRAMES_PER_TICK, &mut frames).await;
|
||||
let len = frames.len();
|
||||
if len > 0 {
|
||||
trace!("tick {}", len);
|
||||
}
|
||||
for (_, frame) in frames {
|
||||
self.send_frame(frame, &mut send_cache).await;
|
||||
}
|
||||
b2s_prio_statistic_s
|
||||
.send((self.remote_pid, len as u64, /* */ 0))
|
||||
.await
|
||||
.unwrap();
|
||||
async_std::task::sleep(TICK_TIME).await;
|
||||
//shutdown after all msg are send!
|
||||
if closing_up && (len == 0) {
|
||||
break;
|
||||
}
|
||||
//this IF below the break IF to give it another chance to close all streams
|
||||
// closed
|
||||
if !closing_up && shutdown_send_mgr_receiver.try_recv().unwrap().is_some() {
|
||||
closing_up = true;
|
||||
}
|
||||
}
|
||||
trace!("stop send_mgr");
|
||||
b2b_prios_flushed_s.send(()).unwrap();
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
//retruns false if sending isn't possible. In that case we have to render the
|
||||
// Participant `closed`
|
||||
#[must_use = "You need to check if the send was successful and report to client!"]
|
||||
async fn send_frame(
|
||||
&self,
|
||||
frame: Frame,
|
||||
frames_out_total_cache: &mut PidCidFrameCache,
|
||||
) -> bool {
|
||||
// find out ideal channel here
|
||||
//TODO: just take first
|
||||
let mut lock = self.channels.write().await;
|
||||
if let Some(ci) = lock.get_mut(0) {
|
||||
//note: this is technically wrong we should only increase when it suceeded, but
|
||||
// this requiered me to clone `frame` which is a to big performance impact for
|
||||
// error handling
|
||||
frames_out_total_cache
|
||||
.with_label_values(ci.cid, &frame)
|
||||
.inc();
|
||||
if let Err(e) = ci.b2w_frame_s.send(frame).await {
|
||||
warn!(
|
||||
?e,
|
||||
"the channel got closed unexpectedly, cleaning it up now."
|
||||
);
|
||||
let ci = lock.remove(0);
|
||||
if let Err(e) = ci.b2r_read_shutdown.send(()) {
|
||||
debug!(
|
||||
?e,
|
||||
"error shutdowning channel, which is prob fine as we detected it to no \
|
||||
longer work in the first place"
|
||||
);
|
||||
};
|
||||
//TODO
|
||||
warn!(
|
||||
"FIXME: the frame is actually drop. which is fine for now as the participant \
|
||||
will be closed, but not if we do channel-takeover"
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
error!("participant has no channel to communicate on");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_frames_mgr(
|
||||
&self,
|
||||
mut w2b_frames_r: mpsc::UnboundedReceiver<(Cid, Frame)>,
|
||||
mut b2a_stream_opened_s: mpsc::UnboundedSender<Stream>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start handle_frames_mgr");
|
||||
let mut messages = HashMap::new();
|
||||
let mut dropped_instant = Instant::now();
|
||||
let mut dropped_cnt = 0u64;
|
||||
let mut dropped_sid = Sid::new(0);
|
||||
|
||||
while let Some((cid, frame)) = w2b_frames_r.next().await {
|
||||
let cid_string = cid.to_string();
|
||||
//trace!("handling frame");
|
||||
self.metrics
|
||||
.frames_in_total
|
||||
.with_label_values(&[&self.remote_pid_string, &cid_string, frame.get_string()])
|
||||
.inc();
|
||||
match frame {
|
||||
Frame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
} => {
|
||||
let a2p_msg_s = a2p_msg_s.clone();
|
||||
let stream = self
|
||||
.create_stream(sid, prio, promises, a2p_msg_s, &a2b_close_stream_s)
|
||||
.await;
|
||||
b2a_stream_opened_s.send(stream).await.unwrap();
|
||||
trace!("opened frame from remote");
|
||||
},
|
||||
Frame::CloseStream { sid } => {
|
||||
// Closing is realised by setting a AtomicBool to true, however we also have a
|
||||
// guarantee that send or recv fails if the other one is destroyed
|
||||
// However Stream.send() is not async and their receiver isn't dropped if Steam
|
||||
// is dropped, so i need a way to notify the Stream that it's send messages will
|
||||
// be dropped... from remote, notify local
|
||||
trace!(
|
||||
?sid,
|
||||
"got remote request to close a stream, without flushing it, local \
|
||||
messages are dropped"
|
||||
);
|
||||
// no wait for flush here, as the remote wouldn't care anyway.
|
||||
if let Some(si) = self.streams.write().await.remove(&sid) {
|
||||
self.metrics
|
||||
.streams_closed_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
si.closed.store(true, Ordering::Relaxed);
|
||||
trace!(?sid, "closed stream from remote");
|
||||
} else {
|
||||
warn!(
|
||||
?sid,
|
||||
"couldn't find stream to close, either this is a duplicate message, \
|
||||
or the local copy of the Stream got closed simultaniously"
|
||||
);
|
||||
}
|
||||
},
|
||||
Frame::DataHeader { mid, sid, length } => {
|
||||
let imsg = IncomingMessage {
|
||||
buffer: MessageBuffer { data: Vec::new() },
|
||||
length,
|
||||
mid,
|
||||
sid,
|
||||
};
|
||||
messages.insert(mid, imsg);
|
||||
},
|
||||
Frame::Data {
|
||||
mid,
|
||||
start: _,
|
||||
mut data,
|
||||
} => {
|
||||
let finished = if let Some(imsg) = messages.get_mut(&mid) {
|
||||
imsg.buffer.data.append(&mut data);
|
||||
imsg.buffer.data.len() as u64 == imsg.length
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if finished {
|
||||
//debug!(?mid, "finished receiving message");
|
||||
let imsg = messages.remove(&mid).unwrap();
|
||||
if let Some(si) = self.streams.write().await.get_mut(&imsg.sid) {
|
||||
if let Err(e) = si.b2a_msg_recv_s.send(imsg).await {
|
||||
warn!(
|
||||
?e,
|
||||
?mid,
|
||||
"dropping message, as streams seem to be in act of beeing \
|
||||
dropped right now"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
//aggregate errors
|
||||
let n = Instant::now();
|
||||
if dropped_sid != imsg.sid
|
||||
|| n.duration_since(dropped_instant) > Duration::from_secs(1)
|
||||
{
|
||||
warn!(
|
||||
?dropped_cnt,
|
||||
"dropping multiple messages as stream no longer seems to \
|
||||
exist because it was dropped probably."
|
||||
);
|
||||
dropped_cnt = 0;
|
||||
dropped_instant = n;
|
||||
dropped_sid = imsg.sid;
|
||||
} else {
|
||||
dropped_cnt += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => unreachable!("never reaches frame!"),
|
||||
}
|
||||
}
|
||||
if dropped_cnt > 0 {
|
||||
warn!(
|
||||
?dropped_cnt,
|
||||
"dropping multiple messages as stream no longer seems to exist because it was \
|
||||
dropped probably."
|
||||
);
|
||||
}
|
||||
trace!("stop handle_frames_mgr");
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
async fn create_channel_mgr(
|
||||
&self,
|
||||
s2b_create_channel_r: mpsc::UnboundedReceiver<(
|
||||
Cid,
|
||||
Sid,
|
||||
Protocols,
|
||||
Vec<(Cid, Frame)>,
|
||||
oneshot::Sender<()>,
|
||||
)>,
|
||||
w2b_frames_s: mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start create_channel_mgr");
|
||||
s2b_create_channel_r
|
||||
.for_each_concurrent(
|
||||
None,
|
||||
|(cid, _, protocol, leftover_cid_frame, b2s_create_channel_done_s)| {
|
||||
// This channel is now configured, and we are running it in scope of the
|
||||
// participant.
|
||||
let w2b_frames_s = w2b_frames_s.clone();
|
||||
let channels = self.channels.clone();
|
||||
async move {
|
||||
let (channel, b2w_frame_s, b2r_read_shutdown) = Channel::new(cid);
|
||||
channels.write().await.push(ChannelInfo {
|
||||
cid,
|
||||
cid_string: cid.to_string(),
|
||||
b2w_frame_s,
|
||||
b2r_read_shutdown,
|
||||
});
|
||||
b2s_create_channel_done_s.send(()).unwrap();
|
||||
self.metrics
|
||||
.channels_connected_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
trace!(?cid, "running channel in participant");
|
||||
channel
|
||||
.run(protocol, w2b_frames_s, leftover_cid_frame)
|
||||
.await;
|
||||
self.metrics
|
||||
.channels_disconnected_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
trace!(?cid, "channel got closed");
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
trace!("stop create_channel_mgr");
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn open_mgr(
|
||||
&self,
|
||||
mut a2b_steam_open_r: mpsc::UnboundedReceiver<(Prio, Promises, oneshot::Sender<Stream>)>,
|
||||
a2b_close_stream_s: mpsc::UnboundedSender<Sid>,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
shutdown_open_mgr_receiver: oneshot::Receiver<()>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start open_mgr");
|
||||
let mut stream_ids = self.offset_sid;
|
||||
let mut send_cache =
|
||||
PidCidFrameCache::new(self.metrics.frames_out_total.clone(), self.remote_pid);
|
||||
let mut shutdown_open_mgr_receiver = shutdown_open_mgr_receiver.fuse();
|
||||
//from api or shutdown signal
|
||||
while let Some((prio, promises, p2a_return_stream)) = select! {
|
||||
next = a2b_steam_open_r.next().fuse() => next,
|
||||
_ = shutdown_open_mgr_receiver => None,
|
||||
} {
|
||||
debug!(?prio, ?promises, "got request to open a new steam");
|
||||
let a2p_msg_s = a2p_msg_s.clone();
|
||||
let sid = stream_ids;
|
||||
let stream = self
|
||||
.create_stream(sid, prio, promises, a2p_msg_s, &a2b_close_stream_s)
|
||||
.await;
|
||||
if self
|
||||
.send_frame(
|
||||
Frame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
},
|
||||
&mut send_cache,
|
||||
)
|
||||
.await
|
||||
{
|
||||
//On error, we drop this, so it gets closed and client will handle this as an
|
||||
// Err any way (:
|
||||
p2a_return_stream.send(stream).unwrap();
|
||||
stream_ids += Sid::from(1);
|
||||
}
|
||||
}
|
||||
trace!("stop open_mgr");
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// when activated this function will drop the participant completly and
|
||||
/// wait for everything to go right! Then return 1. Shutting down
|
||||
/// Streams for API and End user! 2. Wait for all "prio queued" Messages
|
||||
/// to be send. 3. Send Stream
|
||||
async fn participant_shutdown_mgr(
|
||||
&self,
|
||||
s2b_shutdown_bparticipant_r: oneshot::Receiver<oneshot::Sender<async_std::io::Result<()>>>,
|
||||
b2b_prios_flushed_r: oneshot::Receiver<()>,
|
||||
mut to_shutdown: Vec<oneshot::Sender<()>>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start participant_shutdown_mgr");
|
||||
let sender = s2b_shutdown_bparticipant_r.await.unwrap();
|
||||
debug!("closing all managers");
|
||||
for sender in to_shutdown.drain(..) {
|
||||
if let Err(e) = sender.send(()) {
|
||||
warn!(?e, "manager seems to be closed already, weird, maybe a bug");
|
||||
};
|
||||
}
|
||||
debug!("closing all streams");
|
||||
for (sid, si) in self.streams.write().await.drain() {
|
||||
trace!(?sid, "shutting down Stream");
|
||||
si.closed.store(true, Ordering::Relaxed);
|
||||
}
|
||||
debug!("waiting for prios to be flushed");
|
||||
b2b_prios_flushed_r.await.unwrap();
|
||||
debug!("closing all channels");
|
||||
for ci in self.channels.write().await.drain(..) {
|
||||
if let Err(e) = ci.b2r_read_shutdown.send(()) {
|
||||
debug!(?e, ?ci.cid, "seems like this read protocol got already dropped by closing the Stream itself, just ignoring the fact");
|
||||
};
|
||||
}
|
||||
//Wait for other bparticipants mgr to close via AtomicUsize
|
||||
const SLEEP_TIME: Duration = Duration::from_millis(5);
|
||||
async_std::task::sleep(SLEEP_TIME).await;
|
||||
let mut i: u32 = 1;
|
||||
while self.running_mgr.load(Ordering::Relaxed) > 1 {
|
||||
i += 1;
|
||||
if i.rem_euclid(10) == 1 {
|
||||
trace!(
|
||||
"waiting for bparticipant mgr to shut down, remaining {}",
|
||||
self.running_mgr.load(Ordering::Relaxed) - 1
|
||||
);
|
||||
}
|
||||
async_std::task::sleep(SLEEP_TIME * i).await;
|
||||
}
|
||||
trace!("all bparticipant mgr (except me) are shut down now");
|
||||
self.metrics.participants_disconnected_total.inc();
|
||||
sender.send(Ok(())).unwrap();
|
||||
trace!("stop participant_shutdown_mgr");
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn stream_close_mgr(
|
||||
&self,
|
||||
mut a2b_close_stream_r: mpsc::UnboundedReceiver<Sid>,
|
||||
shutdown_stream_close_mgr_receiver: oneshot::Receiver<()>,
|
||||
b2p_notify_empty_stream_s: std::sync::mpsc::Sender<(Sid, oneshot::Sender<()>)>,
|
||||
) {
|
||||
self.running_mgr.fetch_add(1, Ordering::Relaxed);
|
||||
trace!("start stream_close_mgr");
|
||||
let mut send_cache =
|
||||
PidCidFrameCache::new(self.metrics.frames_out_total.clone(), self.remote_pid);
|
||||
let mut shutdown_stream_close_mgr_receiver = shutdown_stream_close_mgr_receiver.fuse();
|
||||
|
||||
//from api or shutdown signal
|
||||
while let Some(sid) = select! {
|
||||
next = a2b_close_stream_r.next().fuse() => next,
|
||||
_ = shutdown_stream_close_mgr_receiver => None,
|
||||
} {
|
||||
//TODO: make this concurrent!
|
||||
//TODO: Performance, closing is slow!
|
||||
trace!(?sid, "got request from api to close steam");
|
||||
//This needs to first stop clients from sending any more.
|
||||
//Then it will wait for all pending messages (in prio) to be send to the
|
||||
// protocol After this happened the stream is closed
|
||||
//Only after all messages are send to the prococol, we can send the CloseStream
|
||||
// frame! If we would send it before, all followup messages couldn't
|
||||
// be handled at the remote side.
|
||||
|
||||
trace!(?sid, "stopping api to use this stream");
|
||||
match self.streams.read().await.get(&sid) {
|
||||
Some(si) => {
|
||||
si.closed.store(true, Ordering::Relaxed);
|
||||
},
|
||||
None => warn!("couldn't find the stream, might be simulanious close from remote"),
|
||||
}
|
||||
|
||||
//TODO: what happens if RIGHT NOW the remote sends a StreamClose and this
|
||||
// streams get closed and removed? RACE CONDITION
|
||||
trace!(?sid, "wait for stream to be flushed");
|
||||
let (s2b_stream_finished_closed_s, s2b_stream_finished_closed_r) = oneshot::channel();
|
||||
b2p_notify_empty_stream_s
|
||||
.send((sid, s2b_stream_finished_closed_s))
|
||||
.unwrap();
|
||||
s2b_stream_finished_closed_r.await.unwrap();
|
||||
|
||||
trace!(?sid, "stream was successfully flushed");
|
||||
self.metrics
|
||||
.streams_closed_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
//only now remove the Stream, that means we can still recv on it.
|
||||
self.streams.write().await.remove(&sid);
|
||||
self.send_frame(Frame::CloseStream { sid }, &mut send_cache)
|
||||
.await;
|
||||
}
|
||||
trace!("stop stream_close_mgr");
|
||||
self.running_mgr.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
async fn create_stream(
|
||||
&self,
|
||||
sid: Sid,
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
a2p_msg_s: std::sync::mpsc::Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
a2b_close_stream_s: &mpsc::UnboundedSender<Sid>,
|
||||
) -> Stream {
|
||||
let (b2a_msg_recv_s, b2a_msg_recv_r) = mpsc::unbounded::<IncomingMessage>();
|
||||
let closed = Arc::new(AtomicBool::new(false));
|
||||
self.streams.write().await.insert(sid, StreamInfo {
|
||||
prio,
|
||||
promises,
|
||||
b2a_msg_recv_s,
|
||||
closed: closed.clone(),
|
||||
});
|
||||
self.metrics
|
||||
.streams_opened_total
|
||||
.with_label_values(&[&self.remote_pid_string])
|
||||
.inc();
|
||||
Stream::new(
|
||||
self.remote_pid,
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
a2p_msg_s,
|
||||
b2a_msg_recv_r,
|
||||
closed.clone(),
|
||||
a2b_close_stream_s.clone(),
|
||||
)
|
||||
}
|
||||
}
|
603
network/src/prios.rs
Normal file
603
network/src/prios.rs
Normal file
@ -0,0 +1,603 @@
|
||||
//!Priorities are handled the following way.
|
||||
//!Prios from 0-63 are allowed.
|
||||
//!all 5 numbers the throughput is halved.
|
||||
//!E.g. in the same time 100 prio0 messages are send, only 50 prio5, 25 prio10,
|
||||
//! 12 prio15 or 6 prio20 messages are send. Note: TODO: prio0 will be send
|
||||
//! immeadiatly when found!
|
||||
|
||||
use crate::{
|
||||
message::OutgoingMessage,
|
||||
metrics::NetworkMetrics,
|
||||
types::{Frame, Prio, Sid},
|
||||
};
|
||||
use futures::channel::oneshot;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use tracing::*;
|
||||
|
||||
const PRIO_MAX: usize = 64;
|
||||
|
||||
struct PidSidInfo {
|
||||
len: u64,
|
||||
empty_notify: Option<oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
pub(crate) struct PrioManager {
|
||||
points: [u32; PRIO_MAX],
|
||||
messages: [VecDeque<(Sid, OutgoingMessage)>; PRIO_MAX],
|
||||
messages_rx: Receiver<(Prio, Sid, OutgoingMessage)>,
|
||||
sid_owned: HashMap<Sid, PidSidInfo>,
|
||||
//you can register to be notified if a pid_sid combination is flushed completly here
|
||||
sid_flushed_rx: Receiver<(Sid, oneshot::Sender<()>)>,
|
||||
queued: HashSet<u8>,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
pid: String,
|
||||
}
|
||||
|
||||
impl PrioManager {
|
||||
const FRAME_DATA_SIZE: u64 = 1400;
|
||||
const PRIOS: [u32; PRIO_MAX] = [
|
||||
100, 115, 132, 152, 174, 200, 230, 264, 303, 348, 400, 459, 528, 606, 696, 800, 919, 1056,
|
||||
1213, 1393, 1600, 1838, 2111, 2425, 2786, 3200, 3676, 4222, 4850, 5572, 6400, 7352, 8445,
|
||||
9701, 11143, 12800, 14703, 16890, 19401, 22286, 25600, 29407, 33779, 38802, 44572, 51200,
|
||||
58813, 67559, 77605, 89144, 102400, 117627, 135118, 155209, 178289, 204800, 235253, 270235,
|
||||
310419, 356578, 409600, 470507, 540470, 620838,
|
||||
];
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn new(
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
pid: String,
|
||||
) -> (
|
||||
Self,
|
||||
Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
Sender<(Sid, oneshot::Sender<()>)>,
|
||||
) {
|
||||
// (a2p_msg_s, a2p_msg_r)
|
||||
let (messages_tx, messages_rx) = channel();
|
||||
let (sid_flushed_tx, sid_flushed_rx) = channel();
|
||||
(
|
||||
Self {
|
||||
points: [0; PRIO_MAX],
|
||||
messages: [
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
VecDeque::new(),
|
||||
],
|
||||
messages_rx,
|
||||
queued: HashSet::new(), //TODO: optimize with u64 and 64 bits
|
||||
sid_flushed_rx,
|
||||
sid_owned: HashMap::new(),
|
||||
metrics,
|
||||
pid,
|
||||
},
|
||||
messages_tx,
|
||||
sid_flushed_tx,
|
||||
)
|
||||
}
|
||||
|
||||
async fn tick(&mut self) {
|
||||
// Check Range
|
||||
let mut messages = 0;
|
||||
let mut closed = 0;
|
||||
for (prio, sid, msg) in self.messages_rx.try_iter() {
|
||||
debug_assert!(prio as usize <= PRIO_MAX);
|
||||
messages += 1;
|
||||
self.metrics
|
||||
.message_out_total
|
||||
.with_label_values(&[&self.pid, &sid.to_string()])
|
||||
.inc();
|
||||
self.metrics
|
||||
.message_out_throughput
|
||||
.with_label_values(&[&self.pid, &sid.to_string()])
|
||||
.inc_by(msg.buffer.data.len() as i64);
|
||||
//trace!(?prio, ?sid, "tick");
|
||||
self.queued.insert(prio);
|
||||
self.messages[prio as usize].push_back((sid, msg));
|
||||
if let Some(cnt) = self.sid_owned.get_mut(&sid) {
|
||||
cnt.len += 1;
|
||||
} else {
|
||||
self.sid_owned.insert(sid, PidSidInfo {
|
||||
len: 1,
|
||||
empty_notify: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
//this must be AFTER messages
|
||||
for (sid, return_sender) in self.sid_flushed_rx.try_iter() {
|
||||
closed += 1;
|
||||
if let Some(cnt) = self.sid_owned.get_mut(&sid) {
|
||||
// register sender
|
||||
cnt.empty_notify = Some(return_sender);
|
||||
} else {
|
||||
// return immediately
|
||||
return_sender.send(()).unwrap();
|
||||
}
|
||||
}
|
||||
if messages > 0 || closed > 0 {
|
||||
trace!(?messages, ?closed, "tick");
|
||||
}
|
||||
}
|
||||
|
||||
//if None returned, we are empty!
|
||||
fn calc_next_prio(&self) -> Option<u8> {
|
||||
// compare all queued prios, max 64 operations
|
||||
let mut lowest = std::u32::MAX;
|
||||
let mut lowest_id = None;
|
||||
for &n in &self.queued {
|
||||
let n_points = self.points[n as usize];
|
||||
if n_points < lowest {
|
||||
lowest = n_points;
|
||||
lowest_id = Some(n)
|
||||
} else if n_points == lowest && lowest_id.is_some() && n < lowest_id.unwrap() {
|
||||
//on equial points lowest first!
|
||||
lowest_id = Some(n)
|
||||
}
|
||||
}
|
||||
lowest_id
|
||||
}
|
||||
|
||||
/// returns if msg is empty
|
||||
fn tick_msg<E: Extend<(Sid, Frame)>>(
|
||||
msg: &mut OutgoingMessage,
|
||||
msg_sid: Sid,
|
||||
frames: &mut E,
|
||||
) -> bool {
|
||||
let to_send = std::cmp::min(
|
||||
msg.buffer.data.len() as u64 - msg.cursor,
|
||||
Self::FRAME_DATA_SIZE,
|
||||
);
|
||||
if to_send > 0 {
|
||||
if msg.cursor == 0 {
|
||||
frames.extend(std::iter::once((msg_sid, Frame::DataHeader {
|
||||
mid: msg.mid,
|
||||
sid: msg.sid,
|
||||
length: msg.buffer.data.len() as u64,
|
||||
})));
|
||||
}
|
||||
frames.extend(std::iter::once((msg_sid, Frame::Data {
|
||||
mid: msg.mid,
|
||||
start: msg.cursor,
|
||||
data: msg.buffer.data[msg.cursor as usize..(msg.cursor + to_send) as usize]
|
||||
.to_vec(),
|
||||
})));
|
||||
};
|
||||
msg.cursor += to_send;
|
||||
msg.cursor >= msg.buffer.data.len() as u64
|
||||
}
|
||||
|
||||
/// no_of_frames = frames.len()
|
||||
/// Your goal is to try to find a realistic no_of_frames!
|
||||
/// no_of_frames should be choosen so, that all Frames can be send out till
|
||||
/// the next tick!
|
||||
/// - if no_of_frames is too high you will fill either the Socket buffer,
|
||||
/// or your internal buffer. In that case you will increase latency for
|
||||
/// high prio messages!
|
||||
/// - if no_of_frames is too low you wont saturate your Socket fully, thus
|
||||
/// have a lower bandwidth as possible
|
||||
pub async fn fill_frames<E: Extend<(Sid, Frame)>>(
|
||||
&mut self,
|
||||
no_of_frames: usize,
|
||||
frames: &mut E,
|
||||
) {
|
||||
for v in self.messages.iter_mut() {
|
||||
v.reserve_exact(no_of_frames)
|
||||
}
|
||||
self.tick().await;
|
||||
for _ in 0..no_of_frames {
|
||||
match self.calc_next_prio() {
|
||||
Some(prio) => {
|
||||
//let prio2 = self.calc_next_prio().unwrap();
|
||||
//trace!(?prio, "handle next prio");
|
||||
self.points[prio as usize] += Self::PRIOS[prio as usize];
|
||||
//pop message from front of VecDeque, handle it and push it back, so that all
|
||||
// => messages with same prio get a fair chance :)
|
||||
//TODO: evalaute not poping every time
|
||||
match self.messages[prio as usize].pop_front() {
|
||||
Some((sid, mut msg)) => {
|
||||
if Self::tick_msg(&mut msg, sid, frames) {
|
||||
//debug!(?m.mid, "finish message");
|
||||
//check if prio is empty
|
||||
if self.messages[prio as usize].is_empty() {
|
||||
self.queued.remove(&prio);
|
||||
}
|
||||
//decrease pid_sid counter by 1 again
|
||||
let cnt = self.sid_owned.get_mut(&sid).expect(
|
||||
"the pid_sid_owned counter works wrong, more pid,sid removed \
|
||||
than inserted",
|
||||
);
|
||||
cnt.len -= 1;
|
||||
if cnt.len == 0 {
|
||||
let cnt = self.sid_owned.remove(&sid).unwrap();
|
||||
if let Some(empty_notify) = cnt.empty_notify {
|
||||
empty_notify.send(()).unwrap();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!(?msg.mid, "repush message");
|
||||
self.messages[prio as usize].push_back((sid, msg));
|
||||
}
|
||||
},
|
||||
None => unreachable!("msg not in VecDeque, but queued"),
|
||||
}
|
||||
},
|
||||
None => {
|
||||
//QUEUE is empty, we are clearing the POINTS to not build up huge pipes of
|
||||
// POINTS on a prio from the past
|
||||
self.points = [0; PRIO_MAX];
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PrioManager {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut cnt = 0;
|
||||
for m in self.messages.iter() {
|
||||
cnt += m.len();
|
||||
}
|
||||
write!(f, "PrioManager(len: {}, queued: {:?})", cnt, &self.queued,)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
message::{MessageBuffer, OutgoingMessage},
|
||||
metrics::NetworkMetrics,
|
||||
prios::*,
|
||||
types::{Frame, Pid, Prio, Sid},
|
||||
};
|
||||
use futures::{channel::oneshot, executor::block_on};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::{mpsc::Sender, Arc},
|
||||
};
|
||||
|
||||
const SIZE: u64 = PrioManager::FRAME_DATA_SIZE;
|
||||
const USIZE: usize = PrioManager::FRAME_DATA_SIZE as usize;
|
||||
|
||||
fn mock_new() -> (
|
||||
PrioManager,
|
||||
Sender<(Prio, Sid, OutgoingMessage)>,
|
||||
Sender<(Sid, oneshot::Sender<()>)>,
|
||||
) {
|
||||
let pid = Pid::fake(1);
|
||||
PrioManager::new(
|
||||
Arc::new(NetworkMetrics::new(&pid).unwrap()),
|
||||
pid.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
fn mock_out(prio: Prio, sid: u64) -> (Prio, Sid, OutgoingMessage) {
|
||||
let sid = Sid::new(sid);
|
||||
(prio, sid, OutgoingMessage {
|
||||
buffer: Arc::new(MessageBuffer {
|
||||
data: vec![48, 49, 50],
|
||||
}),
|
||||
cursor: 0,
|
||||
mid: 1,
|
||||
sid,
|
||||
})
|
||||
}
|
||||
|
||||
fn mock_out_large(prio: Prio, sid: u64) -> (Prio, Sid, OutgoingMessage) {
|
||||
let sid = Sid::new(sid);
|
||||
let mut data = vec![48; USIZE];
|
||||
data.append(&mut vec![49; USIZE]);
|
||||
data.append(&mut vec![50; 20]);
|
||||
(prio, sid, OutgoingMessage {
|
||||
buffer: Arc::new(MessageBuffer { data }),
|
||||
cursor: 0,
|
||||
mid: 1,
|
||||
sid,
|
||||
})
|
||||
}
|
||||
|
||||
fn assert_header(frames: &mut VecDeque<(Sid, Frame)>, f_sid: u64, f_length: u64) {
|
||||
let frame = frames
|
||||
.pop_front()
|
||||
.expect("frames vecdeque doesn't contain enough frames!")
|
||||
.1;
|
||||
if let Frame::DataHeader { mid, sid, length } = frame {
|
||||
assert_eq!(mid, 1);
|
||||
assert_eq!(sid, Sid::new(f_sid));
|
||||
assert_eq!(length, f_length);
|
||||
} else {
|
||||
panic!("wrong frame type!, expected DataHeader");
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_data(frames: &mut VecDeque<(Sid, Frame)>, f_start: u64, f_data: Vec<u8>) {
|
||||
let frame = frames
|
||||
.pop_front()
|
||||
.expect("frames vecdeque doesn't contain enough frames!")
|
||||
.1;
|
||||
if let Frame::Data { mid, start, data } = frame {
|
||||
assert_eq!(mid, 1);
|
||||
assert_eq!(start, f_start);
|
||||
assert_eq!(data, f_data);
|
||||
} else {
|
||||
panic!("wrong frame type!, expected Data");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_p16() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out(16, 1337)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 1337, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_p16_p20() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out(16, 1337)).unwrap();
|
||||
msg_tx.send(mock_out(20, 42)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
assert_header(&mut frames, 1337, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 42, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_p20_p16() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out(20, 42)).unwrap();
|
||||
msg_tx.send(mock_out(16, 1337)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 1337, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 42, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_p16_p20() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out(20, 2)).unwrap();
|
||||
msg_tx.send(mock_out(16, 1)).unwrap();
|
||||
msg_tx.send(mock_out(16, 3)).unwrap();
|
||||
msg_tx.send(mock_out(16, 5)).unwrap();
|
||||
msg_tx.send(mock_out(20, 4)).unwrap();
|
||||
msg_tx.send(mock_out(20, 7)).unwrap();
|
||||
msg_tx.send(mock_out(16, 6)).unwrap();
|
||||
msg_tx.send(mock_out(20, 10)).unwrap();
|
||||
msg_tx.send(mock_out(16, 8)).unwrap();
|
||||
msg_tx.send(mock_out(20, 12)).unwrap();
|
||||
msg_tx.send(mock_out(16, 9)).unwrap();
|
||||
msg_tx.send(mock_out(16, 11)).unwrap();
|
||||
msg_tx.send(mock_out(20, 13)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
|
||||
for i in 1..14 {
|
||||
assert_header(&mut frames, i, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
}
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_fill_frames_p16_p20() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out(20, 2)).unwrap();
|
||||
msg_tx.send(mock_out(16, 1)).unwrap();
|
||||
msg_tx.send(mock_out(16, 3)).unwrap();
|
||||
msg_tx.send(mock_out(16, 5)).unwrap();
|
||||
msg_tx.send(mock_out(20, 4)).unwrap();
|
||||
msg_tx.send(mock_out(20, 7)).unwrap();
|
||||
msg_tx.send(mock_out(16, 6)).unwrap();
|
||||
msg_tx.send(mock_out(20, 10)).unwrap();
|
||||
msg_tx.send(mock_out(16, 8)).unwrap();
|
||||
msg_tx.send(mock_out(20, 12)).unwrap();
|
||||
msg_tx.send(mock_out(16, 9)).unwrap();
|
||||
msg_tx.send(mock_out(16, 11)).unwrap();
|
||||
msg_tx.send(mock_out(20, 13)).unwrap();
|
||||
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(3, &mut frames));
|
||||
for i in 1..4 {
|
||||
assert_header(&mut frames, i, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
}
|
||||
assert!(frames.is_empty());
|
||||
block_on(mgr.fill_frames(11, &mut frames));
|
||||
for i in 4..14 {
|
||||
assert_header(&mut frames, i, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
}
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_large_p16() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out_large(16, 1)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 1, SIZE * 2 + 20);
|
||||
assert_data(&mut frames, 0, vec![48; USIZE]);
|
||||
assert_data(&mut frames, SIZE, vec![49; USIZE]);
|
||||
assert_data(&mut frames, SIZE * 2, vec![50; 20]);
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_large_p16() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out_large(16, 1)).unwrap();
|
||||
msg_tx.send(mock_out_large(16, 2)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 1, SIZE * 2 + 20);
|
||||
assert_data(&mut frames, 0, vec![48; USIZE]);
|
||||
assert_header(&mut frames, 2, SIZE * 2 + 20);
|
||||
assert_data(&mut frames, 0, vec![48; USIZE]);
|
||||
assert_data(&mut frames, SIZE, vec![49; USIZE]);
|
||||
assert_data(&mut frames, SIZE, vec![49; USIZE]);
|
||||
assert_data(&mut frames, SIZE * 2, vec![50; 20]);
|
||||
assert_data(&mut frames, SIZE * 2, vec![50; 20]);
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_large_p16_sudden_p0() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
msg_tx.send(mock_out_large(16, 1)).unwrap();
|
||||
msg_tx.send(mock_out_large(16, 2)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(3, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 1, SIZE * 2 + 20);
|
||||
assert_data(&mut frames, 0, vec![48; USIZE]);
|
||||
assert_header(&mut frames, 2, SIZE * 2 + 20);
|
||||
assert_data(&mut frames, 0, vec![48; USIZE]);
|
||||
assert_data(&mut frames, SIZE, vec![49; USIZE]);
|
||||
|
||||
msg_tx.send(mock_out(0, 3)).unwrap();
|
||||
block_on(mgr.fill_frames(100, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 3, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
|
||||
assert_data(&mut frames, SIZE, vec![49; USIZE]);
|
||||
assert_data(&mut frames, SIZE * 2, vec![50; 20]);
|
||||
assert_data(&mut frames, SIZE * 2, vec![50; 20]);
|
||||
assert!(frames.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_p20_thousand_p16_at_once() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
for _ in 0..998 {
|
||||
msg_tx.send(mock_out(16, 2)).unwrap();
|
||||
}
|
||||
msg_tx.send(mock_out(20, 1)).unwrap();
|
||||
msg_tx.send(mock_out(16, 2)).unwrap();
|
||||
msg_tx.send(mock_out(16, 2)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(2000, &mut frames));
|
||||
|
||||
assert_header(&mut frames, 2, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 1, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 2, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 2, 3);
|
||||
//unimportant
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_p20_thousand_p16_later() {
|
||||
let (mut mgr, msg_tx, _flush_tx) = mock_new();
|
||||
for _ in 0..998 {
|
||||
msg_tx.send(mock_out(16, 2)).unwrap();
|
||||
}
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(2000, &mut frames));
|
||||
//^unimportant frames, gonna be dropped
|
||||
msg_tx.send(mock_out(20, 1)).unwrap();
|
||||
msg_tx.send(mock_out(16, 2)).unwrap();
|
||||
msg_tx.send(mock_out(16, 2)).unwrap();
|
||||
let mut frames = VecDeque::new();
|
||||
block_on(mgr.fill_frames(2000, &mut frames));
|
||||
|
||||
//important in that test is, that after the first frames got cleared i reset
|
||||
// the Points even though 998 prio 16 messages have been send at this
|
||||
// point and 0 prio20 messages the next mesasge is a prio16 message
|
||||
// again, and only then prio20! we dont want to build dept over a idling
|
||||
// connection
|
||||
assert_header(&mut frames, 2, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 1, 3);
|
||||
assert_data(&mut frames, 0, vec![48, 49, 50]);
|
||||
assert_header(&mut frames, 2, 3);
|
||||
//unimportant
|
||||
}
|
||||
}
|
723
network/src/protocols.rs
Normal file
723
network/src/protocols.rs
Normal file
@ -0,0 +1,723 @@
|
||||
use crate::{
|
||||
metrics::{CidFrameCache, NetworkMetrics},
|
||||
types::{Cid, Frame, Mid, Pid, Sid},
|
||||
};
|
||||
use async_std::{
|
||||
net::{TcpStream, UdpSocket},
|
||||
prelude::*,
|
||||
};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
future::FutureExt,
|
||||
lock::Mutex,
|
||||
select,
|
||||
sink::SinkExt,
|
||||
stream::StreamExt,
|
||||
};
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
use tracing::*;
|
||||
|
||||
// Reserving bytes 0, 10, 13 as i have enough space and want to make it easy to
|
||||
// detect a invalid client, e.g. sending an empty line would make 10 first char
|
||||
// const FRAME_RESERVED_1: u8 = 0;
|
||||
const FRAME_HANDSHAKE: u8 = 1;
|
||||
const FRAME_INIT: u8 = 2;
|
||||
const FRAME_SHUTDOWN: u8 = 3;
|
||||
const FRAME_OPEN_STREAM: u8 = 4;
|
||||
const FRAME_CLOSE_STREAM: u8 = 5;
|
||||
const FRAME_DATA_HEADER: u8 = 6;
|
||||
const FRAME_DATA: u8 = 7;
|
||||
const FRAME_RAW: u8 = 8;
|
||||
//const FRAME_RESERVED_2: u8 = 10;
|
||||
//const FRAME_RESERVED_3: u8 = 13;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Protocols {
|
||||
Tcp(TcpProtocol),
|
||||
Udp(UdpProtocol),
|
||||
//Mpsc(MpscChannel),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TcpProtocol {
|
||||
stream: TcpStream,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UdpProtocol {
|
||||
socket: Arc<UdpSocket>,
|
||||
remote_addr: SocketAddr,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
data_in: Mutex<mpsc::UnboundedReceiver<Vec<u8>>>,
|
||||
}
|
||||
|
||||
//TODO: PERFORMACE: Use BufWriter and BufReader from std::io!
|
||||
impl TcpProtocol {
|
||||
pub(crate) fn new(stream: TcpStream, metrics: Arc<NetworkMetrics>) -> Self {
|
||||
Self { stream, metrics }
|
||||
}
|
||||
|
||||
/// read_except and if it fails, close the protocol
|
||||
async fn read_except_or_close(
|
||||
cid: Cid,
|
||||
mut stream: &TcpStream,
|
||||
mut bytes: &mut [u8],
|
||||
w2c_cid_frame_s: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
) {
|
||||
if let Err(e) = stream.read_exact(&mut bytes).await {
|
||||
warn!(
|
||||
?e,
|
||||
"closing tcp protocol due to read error, sending close frame to gracefully \
|
||||
shutdown"
|
||||
);
|
||||
w2c_cid_frame_s.send((cid, Frame::Shutdown)).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_from_wire(
|
||||
&self,
|
||||
cid: Cid,
|
||||
w2c_cid_frame_s: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
end_receiver: oneshot::Receiver<()>,
|
||||
) {
|
||||
trace!("starting up tcp read()");
|
||||
let mut metrics_cache = CidFrameCache::new(self.metrics.frames_wire_in_total.clone(), cid);
|
||||
let throughput_cache = self
|
||||
.metrics
|
||||
.wire_in_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
let mut stream = self.stream.clone();
|
||||
let mut end_receiver = end_receiver.fuse();
|
||||
|
||||
loop {
|
||||
let mut bytes = [0u8; 1];
|
||||
let r = select! {
|
||||
r = stream.read_exact(&mut bytes).fuse() => r,
|
||||
_ = end_receiver => break,
|
||||
};
|
||||
if r.is_err() {
|
||||
info!("tcp stream closed, shutting down read");
|
||||
break;
|
||||
}
|
||||
let frame_no = bytes[0];
|
||||
let frame = match frame_no {
|
||||
FRAME_HANDSHAKE => {
|
||||
let mut bytes = [0u8; 19];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let magic_number = [
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
];
|
||||
Frame::Handshake {
|
||||
magic_number,
|
||||
version: [
|
||||
u32::from_le_bytes([bytes[7], bytes[8], bytes[9], bytes[10]]),
|
||||
u32::from_le_bytes([bytes[11], bytes[12], bytes[13], bytes[14]]),
|
||||
u32::from_le_bytes([bytes[15], bytes[16], bytes[17], bytes[18]]),
|
||||
],
|
||||
}
|
||||
},
|
||||
FRAME_INIT => {
|
||||
let mut bytes = [0u8; 16];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let pid = Pid::from_le_bytes(bytes);
|
||||
stream.read_exact(&mut bytes).await.unwrap();
|
||||
let secret = u128::from_le_bytes(bytes);
|
||||
Frame::Init { pid, secret }
|
||||
},
|
||||
FRAME_SHUTDOWN => Frame::Shutdown,
|
||||
FRAME_OPEN_STREAM => {
|
||||
let mut bytes = [0u8; 10];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
let prio = bytes[8];
|
||||
let promises = bytes[9];
|
||||
Frame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
}
|
||||
},
|
||||
FRAME_CLOSE_STREAM => {
|
||||
let mut bytes = [0u8; 8];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
Frame::CloseStream { sid }
|
||||
},
|
||||
FRAME_DATA_HEADER => {
|
||||
let mut bytes = [0u8; 24];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let mid = Mid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
|
||||
bytes[15],
|
||||
]);
|
||||
let length = u64::from_le_bytes([
|
||||
bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21],
|
||||
bytes[22], bytes[23],
|
||||
]);
|
||||
Frame::DataHeader { mid, sid, length }
|
||||
},
|
||||
FRAME_DATA => {
|
||||
let mut bytes = [0u8; 18];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let mid = Mid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
let start = u64::from_le_bytes([
|
||||
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
|
||||
bytes[15],
|
||||
]);
|
||||
let length = u16::from_le_bytes([bytes[16], bytes[17]]);
|
||||
let mut data = vec![0; length as usize];
|
||||
throughput_cache.inc_by(length as i64);
|
||||
Self::read_except_or_close(cid, &stream, &mut data, w2c_cid_frame_s).await;
|
||||
Frame::Data { mid, start, data }
|
||||
},
|
||||
FRAME_RAW => {
|
||||
let mut bytes = [0u8; 2];
|
||||
Self::read_except_or_close(cid, &stream, &mut bytes, w2c_cid_frame_s).await;
|
||||
let length = u16::from_le_bytes([bytes[0], bytes[1]]);
|
||||
let mut data = vec![0; length as usize];
|
||||
Self::read_except_or_close(cid, &stream, &mut data, w2c_cid_frame_s).await;
|
||||
Frame::Raw(data)
|
||||
},
|
||||
_ => {
|
||||
// report a RAW frame, but cannot rely on the next 2 bytes to be a size.
|
||||
// guessing 256 bytes, which might help to sort down issues
|
||||
let mut data = vec![0; 256];
|
||||
Self::read_except_or_close(cid, &stream, &mut data, w2c_cid_frame_s).await;
|
||||
Frame::Raw(data)
|
||||
},
|
||||
};
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
w2c_cid_frame_s.send((cid, frame)).await.unwrap();
|
||||
}
|
||||
trace!("shutting down tcp read()");
|
||||
}
|
||||
|
||||
/// read_except and if it fails, close the protocol
|
||||
async fn write_or_close(
|
||||
stream: &mut TcpStream,
|
||||
bytes: &[u8],
|
||||
to_wire_receiver: &mut mpsc::UnboundedReceiver<Frame>,
|
||||
) -> bool {
|
||||
match stream.write_all(&bytes).await {
|
||||
Err(e) => {
|
||||
warn!(
|
||||
?e,
|
||||
"got an error writing to tcp, going to close this channel"
|
||||
);
|
||||
to_wire_receiver.close();
|
||||
true
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
//dezerialize here as this is executed in a seperate thread PER channel.
|
||||
// Limites Throughput per single Receiver but stays in same thread (maybe as its
|
||||
// in a threadpool) for TCP, UDP and MPSC
|
||||
pub async fn write_to_wire(&self, cid: Cid, mut c2w_frame_r: mpsc::UnboundedReceiver<Frame>) {
|
||||
trace!("starting up tcp write()");
|
||||
let mut stream = self.stream.clone();
|
||||
let mut metrics_cache = CidFrameCache::new(self.metrics.frames_wire_out_total.clone(), cid);
|
||||
let throughput_cache = self
|
||||
.metrics
|
||||
.wire_out_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
while let Some(frame) = c2w_frame_r.next().await {
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
if match frame {
|
||||
Frame::Handshake {
|
||||
magic_number,
|
||||
version,
|
||||
} => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_HANDSHAKE.to_be_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &magic_number, &mut c2w_frame_r).await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&version[0].to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&version[1].to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&version[2].to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::Init { pid, secret } => {
|
||||
Self::write_or_close(&mut stream, &FRAME_INIT.to_be_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &pid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&secret.to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::Shutdown => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_SHUTDOWN.to_be_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
} => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_OPEN_STREAM.to_be_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &sid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &prio.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&promises.to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::CloseStream { sid } => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_CLOSE_STREAM.to_be_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &sid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
},
|
||||
Frame::DataHeader { mid, sid, length } => {
|
||||
Self::write_or_close(
|
||||
&mut stream,
|
||||
&FRAME_DATA_HEADER.to_be_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &mid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &sid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&length.to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
},
|
||||
Frame::Data { mid, start, data } => {
|
||||
throughput_cache.inc_by(data.len() as i64);
|
||||
Self::write_or_close(&mut stream, &FRAME_DATA.to_be_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &mid.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &start.to_le_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&(data.len() as u16).to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &data, &mut c2w_frame_r).await
|
||||
},
|
||||
Frame::Raw(data) => {
|
||||
Self::write_or_close(&mut stream, &FRAME_RAW.to_be_bytes(), &mut c2w_frame_r)
|
||||
.await
|
||||
|| Self::write_or_close(
|
||||
&mut stream,
|
||||
&(data.len() as u16).to_le_bytes(),
|
||||
&mut c2w_frame_r,
|
||||
)
|
||||
.await
|
||||
|| Self::write_or_close(&mut stream, &data, &mut c2w_frame_r).await
|
||||
},
|
||||
} {
|
||||
//failure
|
||||
return;
|
||||
}
|
||||
}
|
||||
trace!("shutting down tcp write()");
|
||||
}
|
||||
}
|
||||
|
||||
impl UdpProtocol {
|
||||
pub(crate) fn new(
|
||||
socket: Arc<UdpSocket>,
|
||||
remote_addr: SocketAddr,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
data_in: mpsc::UnboundedReceiver<Vec<u8>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
socket,
|
||||
remote_addr,
|
||||
metrics,
|
||||
data_in: Mutex::new(data_in),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_from_wire(
|
||||
&self,
|
||||
cid: Cid,
|
||||
w2c_cid_frame_s: &mut mpsc::UnboundedSender<(Cid, Frame)>,
|
||||
end_receiver: oneshot::Receiver<()>,
|
||||
) {
|
||||
trace!("starting up udp read()");
|
||||
let mut metrics_cache = CidFrameCache::new(self.metrics.frames_wire_in_total.clone(), cid);
|
||||
let throughput_cache = self
|
||||
.metrics
|
||||
.wire_in_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
let mut data_in = self.data_in.lock().await;
|
||||
let mut end_receiver = end_receiver.fuse();
|
||||
while let Some(bytes) = select! {
|
||||
r = data_in.next().fuse() => r,
|
||||
_ = end_receiver => None,
|
||||
} {
|
||||
trace!("got raw UDP message with len: {}", bytes.len());
|
||||
let frame_no = bytes[0];
|
||||
let frame = match frame_no {
|
||||
FRAME_HANDSHAKE => {
|
||||
let bytes = &bytes[1..20];
|
||||
let magic_number = [
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
];
|
||||
Frame::Handshake {
|
||||
magic_number,
|
||||
version: [
|
||||
u32::from_le_bytes([bytes[7], bytes[8], bytes[9], bytes[10]]),
|
||||
u32::from_le_bytes([bytes[11], bytes[12], bytes[13], bytes[14]]),
|
||||
u32::from_le_bytes([bytes[15], bytes[16], bytes[17], bytes[18]]),
|
||||
],
|
||||
}
|
||||
},
|
||||
FRAME_INIT => {
|
||||
let pid = Pid::from_le_bytes([
|
||||
bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
|
||||
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
|
||||
bytes[15], bytes[16],
|
||||
]);
|
||||
let secret = u128::from_le_bytes([
|
||||
bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22],
|
||||
bytes[23], bytes[24], bytes[25], bytes[26], bytes[27], bytes[28],
|
||||
bytes[29], bytes[30], bytes[31], bytes[32],
|
||||
]);
|
||||
Frame::Init { pid, secret }
|
||||
},
|
||||
FRAME_SHUTDOWN => Frame::Shutdown,
|
||||
FRAME_OPEN_STREAM => {
|
||||
let bytes = &bytes[1..11];
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
let prio = bytes[8];
|
||||
let promises = bytes[9];
|
||||
Frame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
}
|
||||
},
|
||||
FRAME_CLOSE_STREAM => {
|
||||
let bytes = &bytes[1..9];
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
Frame::CloseStream { sid }
|
||||
},
|
||||
FRAME_DATA_HEADER => {
|
||||
let bytes = &bytes[1..25];
|
||||
let mid = Mid::from_le_bytes([
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6],
|
||||
bytes[7],
|
||||
]);
|
||||
let sid = Sid::from_le_bytes([
|
||||
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
|
||||
bytes[15],
|
||||
]);
|
||||
let length = u64::from_le_bytes([
|
||||
bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21],
|
||||
bytes[22], bytes[23],
|
||||
]);
|
||||
Frame::DataHeader { mid, sid, length }
|
||||
},
|
||||
FRAME_DATA => {
|
||||
let mid = Mid::from_le_bytes([
|
||||
bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
|
||||
bytes[8],
|
||||
]);
|
||||
let start = u64::from_le_bytes([
|
||||
bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
|
||||
bytes[16],
|
||||
]);
|
||||
let length = u16::from_le_bytes([bytes[17], bytes[18]]);
|
||||
let mut data = vec![0; length as usize];
|
||||
throughput_cache.inc_by(length as i64);
|
||||
data.copy_from_slice(&bytes[19..]);
|
||||
Frame::Data { mid, start, data }
|
||||
},
|
||||
FRAME_RAW => {
|
||||
let length = u16::from_le_bytes([bytes[1], bytes[2]]);
|
||||
let mut data = vec![0; length as usize];
|
||||
data.copy_from_slice(&bytes[3..]);
|
||||
Frame::Raw(data)
|
||||
},
|
||||
_ => Frame::Raw(bytes),
|
||||
};
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
w2c_cid_frame_s.send((cid, frame)).await.unwrap();
|
||||
}
|
||||
trace!("shutting down udp read()");
|
||||
}
|
||||
|
||||
pub async fn write_to_wire(&self, cid: Cid, mut c2w_frame_r: mpsc::UnboundedReceiver<Frame>) {
|
||||
trace!("starting up udp write()");
|
||||
let mut buffer = [0u8; 2000];
|
||||
let mut metrics_cache = CidFrameCache::new(self.metrics.frames_wire_out_total.clone(), cid);
|
||||
let throughput_cache = self
|
||||
.metrics
|
||||
.wire_out_throughput
|
||||
.with_label_values(&[&cid.to_string()]);
|
||||
while let Some(frame) = c2w_frame_r.next().await {
|
||||
metrics_cache.with_label_values(&frame).inc();
|
||||
let len = match frame {
|
||||
Frame::Handshake {
|
||||
magic_number,
|
||||
version,
|
||||
} => {
|
||||
let x = FRAME_HANDSHAKE.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
buffer[1] = magic_number[0];
|
||||
buffer[2] = magic_number[1];
|
||||
buffer[3] = magic_number[2];
|
||||
buffer[4] = magic_number[3];
|
||||
buffer[5] = magic_number[4];
|
||||
buffer[6] = magic_number[5];
|
||||
buffer[7] = magic_number[6];
|
||||
let x = version[0].to_le_bytes();
|
||||
buffer[8] = x[0];
|
||||
buffer[9] = x[1];
|
||||
buffer[10] = x[2];
|
||||
buffer[11] = x[3];
|
||||
let x = version[1].to_le_bytes();
|
||||
buffer[12] = x[0];
|
||||
buffer[13] = x[1];
|
||||
buffer[14] = x[2];
|
||||
buffer[15] = x[3];
|
||||
let x = version[2].to_le_bytes();
|
||||
buffer[16] = x[0];
|
||||
buffer[17] = x[1];
|
||||
buffer[18] = x[2];
|
||||
buffer[19] = x[3];
|
||||
20
|
||||
},
|
||||
Frame::Init { pid, secret } => {
|
||||
let x = FRAME_INIT.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
let x = pid.to_le_bytes();
|
||||
buffer[1] = x[0];
|
||||
buffer[2] = x[1];
|
||||
buffer[3] = x[2];
|
||||
buffer[4] = x[3];
|
||||
buffer[5] = x[4];
|
||||
buffer[6] = x[5];
|
||||
buffer[7] = x[6];
|
||||
buffer[8] = x[7];
|
||||
buffer[9] = x[8];
|
||||
buffer[10] = x[9];
|
||||
buffer[11] = x[10];
|
||||
buffer[12] = x[11];
|
||||
buffer[13] = x[12];
|
||||
buffer[14] = x[13];
|
||||
buffer[15] = x[14];
|
||||
buffer[16] = x[15];
|
||||
let x = secret.to_le_bytes();
|
||||
buffer[17] = x[0];
|
||||
buffer[18] = x[1];
|
||||
buffer[19] = x[2];
|
||||
buffer[20] = x[3];
|
||||
buffer[21] = x[4];
|
||||
buffer[22] = x[5];
|
||||
buffer[23] = x[6];
|
||||
buffer[24] = x[7];
|
||||
buffer[25] = x[8];
|
||||
buffer[26] = x[9];
|
||||
buffer[27] = x[10];
|
||||
buffer[28] = x[11];
|
||||
buffer[29] = x[12];
|
||||
buffer[30] = x[13];
|
||||
buffer[31] = x[14];
|
||||
buffer[32] = x[15];
|
||||
33
|
||||
},
|
||||
Frame::Shutdown => {
|
||||
let x = FRAME_SHUTDOWN.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
1
|
||||
},
|
||||
Frame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
} => {
|
||||
let x = FRAME_OPEN_STREAM.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
let x = sid.to_le_bytes();
|
||||
buffer[1] = x[0];
|
||||
buffer[2] = x[1];
|
||||
buffer[3] = x[2];
|
||||
buffer[4] = x[3];
|
||||
buffer[5] = x[4];
|
||||
buffer[6] = x[5];
|
||||
buffer[7] = x[6];
|
||||
buffer[8] = x[7];
|
||||
let x = prio.to_le_bytes();
|
||||
buffer[9] = x[0];
|
||||
let x = promises.to_le_bytes();
|
||||
buffer[10] = x[0];
|
||||
11
|
||||
},
|
||||
Frame::CloseStream { sid } => {
|
||||
let x = FRAME_CLOSE_STREAM.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
let x = sid.to_le_bytes();
|
||||
buffer[1] = x[0];
|
||||
buffer[2] = x[1];
|
||||
buffer[3] = x[2];
|
||||
buffer[4] = x[3];
|
||||
buffer[5] = x[4];
|
||||
buffer[6] = x[5];
|
||||
buffer[7] = x[6];
|
||||
buffer[8] = x[7];
|
||||
9
|
||||
},
|
||||
Frame::DataHeader { mid, sid, length } => {
|
||||
let x = FRAME_DATA_HEADER.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
let x = mid.to_le_bytes();
|
||||
buffer[1] = x[0];
|
||||
buffer[2] = x[1];
|
||||
buffer[3] = x[2];
|
||||
buffer[4] = x[3];
|
||||
buffer[5] = x[4];
|
||||
buffer[6] = x[5];
|
||||
buffer[7] = x[6];
|
||||
buffer[8] = x[7];
|
||||
let x = sid.to_le_bytes();
|
||||
buffer[9] = x[0];
|
||||
buffer[10] = x[1];
|
||||
buffer[11] = x[2];
|
||||
buffer[12] = x[3];
|
||||
buffer[13] = x[4];
|
||||
buffer[14] = x[5];
|
||||
buffer[15] = x[6];
|
||||
buffer[16] = x[7];
|
||||
let x = length.to_le_bytes();
|
||||
buffer[17] = x[0];
|
||||
buffer[18] = x[1];
|
||||
buffer[19] = x[2];
|
||||
buffer[20] = x[3];
|
||||
buffer[21] = x[4];
|
||||
buffer[22] = x[5];
|
||||
buffer[23] = x[6];
|
||||
buffer[24] = x[7];
|
||||
25
|
||||
},
|
||||
Frame::Data { mid, start, data } => {
|
||||
let x = FRAME_DATA.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
let x = mid.to_le_bytes();
|
||||
buffer[1] = x[0];
|
||||
buffer[2] = x[1];
|
||||
buffer[3] = x[2];
|
||||
buffer[4] = x[3];
|
||||
buffer[5] = x[4];
|
||||
buffer[6] = x[5];
|
||||
buffer[7] = x[6];
|
||||
buffer[8] = x[7];
|
||||
let x = start.to_le_bytes();
|
||||
buffer[9] = x[0];
|
||||
buffer[10] = x[1];
|
||||
buffer[11] = x[2];
|
||||
buffer[12] = x[3];
|
||||
buffer[13] = x[4];
|
||||
buffer[14] = x[5];
|
||||
buffer[15] = x[6];
|
||||
buffer[16] = x[7];
|
||||
let x = (data.len() as u16).to_le_bytes();
|
||||
buffer[17] = x[0];
|
||||
buffer[18] = x[1];
|
||||
buffer[19..(data.len() + 19)].clone_from_slice(&data[..]);
|
||||
throughput_cache.inc_by(data.len() as i64);
|
||||
19 + data.len()
|
||||
},
|
||||
Frame::Raw(data) => {
|
||||
let x = FRAME_RAW.to_be_bytes();
|
||||
buffer[0] = x[0];
|
||||
let x = (data.len() as u16).to_le_bytes();
|
||||
buffer[1] = x[0];
|
||||
buffer[2] = x[1];
|
||||
buffer[3..(data.len() + 3)].clone_from_slice(&data[..]);
|
||||
3 + data.len()
|
||||
},
|
||||
};
|
||||
let mut start = 0;
|
||||
while start < len {
|
||||
trace!(?start, ?len, "splitting up udp frame in multiple packages");
|
||||
match self
|
||||
.socket
|
||||
.send_to(&buffer[start..len], self.remote_addr)
|
||||
.await
|
||||
{
|
||||
Ok(n) => {
|
||||
start += n;
|
||||
if n != len {
|
||||
error!(
|
||||
"THIS DOESNT WORK, as RECEIVER CURRENLTY ONLY HANDLES 1 FRAME per \
|
||||
UDP message. splitting up will fail!"
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(e) => error!(?e, "need to handle that error!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
trace!("shutting down udp write()");
|
||||
}
|
||||
}
|
594
network/src/scheduler.rs
Normal file
594
network/src/scheduler.rs
Normal file
@ -0,0 +1,594 @@
|
||||
use crate::{
|
||||
api::{Address, Participant},
|
||||
channel::Handshake,
|
||||
metrics::NetworkMetrics,
|
||||
participant::BParticipant,
|
||||
protocols::{Protocols, TcpProtocol, UdpProtocol},
|
||||
types::{Cid, Frame, Pid, Sid},
|
||||
};
|
||||
use async_std::{
|
||||
io, net,
|
||||
sync::{Mutex, RwLock},
|
||||
};
|
||||
use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
executor::ThreadPool,
|
||||
future::FutureExt,
|
||||
select,
|
||||
sink::SinkExt,
|
||||
stream::StreamExt,
|
||||
};
|
||||
use prometheus::Registry;
|
||||
use rand::Rng;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
use tracing::*;
|
||||
use tracing_futures::Instrument;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
struct ParticipantInfo {
|
||||
secret: u128,
|
||||
s2b_create_channel_s:
|
||||
mpsc::UnboundedSender<(Cid, Sid, Protocols, Vec<(Cid, Frame)>, oneshot::Sender<()>)>,
|
||||
s2b_shutdown_bparticipant_s:
|
||||
Option<oneshot::Sender<oneshot::Sender<async_std::io::Result<()>>>>,
|
||||
}
|
||||
|
||||
/// Naming of Channels `x2x`
|
||||
/// - a: api
|
||||
/// - s: scheduler
|
||||
/// - b: bparticipant
|
||||
/// - p: prios
|
||||
/// - r: protocol
|
||||
/// - w: wire
|
||||
/// - c: channel/handshake
|
||||
#[derive(Debug)]
|
||||
struct ControlChannels {
|
||||
a2s_listen_r: mpsc::UnboundedReceiver<(Address, oneshot::Sender<io::Result<()>>)>,
|
||||
a2s_connect_r: mpsc::UnboundedReceiver<(Address, oneshot::Sender<io::Result<Participant>>)>,
|
||||
a2s_scheduler_shutdown_r: oneshot::Receiver<()>,
|
||||
a2s_disconnect_r: mpsc::UnboundedReceiver<(Pid, oneshot::Sender<async_std::io::Result<()>>)>,
|
||||
b2s_prio_statistic_r: mpsc::UnboundedReceiver<(Pid, u64, u64)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ParticipantChannels {
|
||||
s2a_connected_s: mpsc::UnboundedSender<Participant>,
|
||||
a2s_disconnect_s: mpsc::UnboundedSender<(Pid, oneshot::Sender<async_std::io::Result<()>>)>,
|
||||
b2s_prio_statistic_s: mpsc::UnboundedSender<(Pid, u64, u64)>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scheduler {
|
||||
local_pid: Pid,
|
||||
local_secret: u128,
|
||||
closed: AtomicBool,
|
||||
pool: Arc<ThreadPool>,
|
||||
run_channels: Option<ControlChannels>,
|
||||
participant_channels: Arc<Mutex<Option<ParticipantChannels>>>,
|
||||
participants: Arc<RwLock<HashMap<Pid, ParticipantInfo>>>,
|
||||
channel_ids: Arc<AtomicU64>,
|
||||
channel_listener: RwLock<HashMap<Address, oneshot::Sender<()>>>,
|
||||
metrics: Arc<NetworkMetrics>,
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn new(
|
||||
local_pid: Pid,
|
||||
registry: Option<&Registry>,
|
||||
) -> (
|
||||
Self,
|
||||
mpsc::UnboundedSender<(Address, oneshot::Sender<io::Result<()>>)>,
|
||||
mpsc::UnboundedSender<(Address, oneshot::Sender<io::Result<Participant>>)>,
|
||||
mpsc::UnboundedReceiver<Participant>,
|
||||
oneshot::Sender<()>,
|
||||
) {
|
||||
let (a2s_listen_s, a2s_listen_r) =
|
||||
mpsc::unbounded::<(Address, oneshot::Sender<io::Result<()>>)>();
|
||||
let (a2s_connect_s, a2s_connect_r) =
|
||||
mpsc::unbounded::<(Address, oneshot::Sender<io::Result<Participant>>)>();
|
||||
let (s2a_connected_s, s2a_connected_r) = mpsc::unbounded::<Participant>();
|
||||
let (a2s_scheduler_shutdown_s, a2s_scheduler_shutdown_r) = oneshot::channel::<()>();
|
||||
let (a2s_disconnect_s, a2s_disconnect_r) =
|
||||
mpsc::unbounded::<(Pid, oneshot::Sender<async_std::io::Result<()>>)>();
|
||||
let (b2s_prio_statistic_s, b2s_prio_statistic_r) = mpsc::unbounded::<(Pid, u64, u64)>();
|
||||
|
||||
let run_channels = Some(ControlChannels {
|
||||
a2s_listen_r,
|
||||
a2s_connect_r,
|
||||
a2s_scheduler_shutdown_r,
|
||||
a2s_disconnect_r,
|
||||
b2s_prio_statistic_r,
|
||||
});
|
||||
|
||||
let participant_channels = ParticipantChannels {
|
||||
s2a_connected_s,
|
||||
a2s_disconnect_s,
|
||||
b2s_prio_statistic_s,
|
||||
};
|
||||
|
||||
let metrics = Arc::new(NetworkMetrics::new(&local_pid).unwrap());
|
||||
if let Some(registry) = registry {
|
||||
metrics.register(registry).unwrap();
|
||||
}
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let local_secret: u128 = rng.gen();
|
||||
|
||||
(
|
||||
Self {
|
||||
local_pid,
|
||||
local_secret,
|
||||
closed: AtomicBool::new(false),
|
||||
pool: Arc::new(ThreadPool::new().unwrap()),
|
||||
run_channels,
|
||||
participant_channels: Arc::new(Mutex::new(Some(participant_channels))),
|
||||
participants: Arc::new(RwLock::new(HashMap::new())),
|
||||
channel_ids: Arc::new(AtomicU64::new(0)),
|
||||
channel_listener: RwLock::new(HashMap::new()),
|
||||
metrics,
|
||||
},
|
||||
a2s_listen_s,
|
||||
a2s_connect_s,
|
||||
s2a_connected_r,
|
||||
a2s_scheduler_shutdown_s,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn run(mut self) {
|
||||
let run_channels = self.run_channels.take().unwrap();
|
||||
|
||||
futures::join!(
|
||||
self.listen_mgr(run_channels.a2s_listen_r),
|
||||
self.connect_mgr(run_channels.a2s_connect_r),
|
||||
self.disconnect_mgr(run_channels.a2s_disconnect_r),
|
||||
self.prio_adj_mgr(run_channels.b2s_prio_statistic_r),
|
||||
self.scheduler_shutdown_mgr(run_channels.a2s_scheduler_shutdown_r),
|
||||
);
|
||||
}
|
||||
|
||||
async fn listen_mgr(
|
||||
&self,
|
||||
a2s_listen_r: mpsc::UnboundedReceiver<(Address, oneshot::Sender<io::Result<()>>)>,
|
||||
) {
|
||||
trace!("start listen_mgr");
|
||||
a2s_listen_r
|
||||
.for_each_concurrent(None, |(address, s2a_listen_result_s)| {
|
||||
let address = address;
|
||||
|
||||
async move {
|
||||
debug!(?address, "got request to open a channel_creator");
|
||||
self.metrics
|
||||
.listen_requests_total
|
||||
.with_label_values(&[match address {
|
||||
Address::Tcp(_) => "tcp",
|
||||
Address::Udp(_) => "udp",
|
||||
Address::Mpsc(_) => "mpsc",
|
||||
}])
|
||||
.inc();
|
||||
let (end_sender, end_receiver) = oneshot::channel::<()>();
|
||||
self.channel_listener
|
||||
.write()
|
||||
.await
|
||||
.insert(address.clone(), end_sender);
|
||||
self.channel_creator(address, end_receiver, s2a_listen_result_s)
|
||||
.await;
|
||||
}
|
||||
})
|
||||
.await;
|
||||
trace!("stop listen_mgr");
|
||||
}
|
||||
|
||||
async fn connect_mgr(
|
||||
&self,
|
||||
mut a2s_connect_r: mpsc::UnboundedReceiver<(
|
||||
Address,
|
||||
oneshot::Sender<io::Result<Participant>>,
|
||||
)>,
|
||||
) {
|
||||
trace!("start connect_mgr");
|
||||
while let Some((addr, pid_sender)) = a2s_connect_r.next().await {
|
||||
let (protocol, handshake) = match addr {
|
||||
Address::Tcp(addr) => {
|
||||
self.metrics
|
||||
.connect_requests_total
|
||||
.with_label_values(&["tcp"])
|
||||
.inc();
|
||||
let stream = match net::TcpStream::connect(addr).await {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
pid_sender.send(Err(e)).unwrap();
|
||||
continue;
|
||||
},
|
||||
};
|
||||
info!("Connecting Tcp to: {}", stream.peer_addr().unwrap());
|
||||
(
|
||||
Protocols::Tcp(TcpProtocol::new(stream, self.metrics.clone())),
|
||||
false,
|
||||
)
|
||||
},
|
||||
Address::Udp(addr) => {
|
||||
self.metrics
|
||||
.connect_requests_total
|
||||
.with_label_values(&["udp"])
|
||||
.inc();
|
||||
let socket = match net::UdpSocket::bind("0.0.0.0:0").await {
|
||||
Ok(socket) => Arc::new(socket),
|
||||
Err(e) => {
|
||||
pid_sender.send(Err(e)).unwrap();
|
||||
continue;
|
||||
},
|
||||
};
|
||||
if let Err(e) = socket.connect(addr).await {
|
||||
pid_sender.send(Err(e)).unwrap();
|
||||
continue;
|
||||
};
|
||||
info!("Connecting Udp to: {}", addr);
|
||||
let (udp_data_sender, udp_data_receiver) = mpsc::unbounded::<Vec<u8>>();
|
||||
let protocol = UdpProtocol::new(
|
||||
socket.clone(),
|
||||
addr,
|
||||
self.metrics.clone(),
|
||||
udp_data_receiver,
|
||||
);
|
||||
self.pool.spawn_ok(
|
||||
Self::udp_single_channel_connect(socket.clone(), udp_data_sender)
|
||||
.instrument(tracing::info_span!("udp", ?addr)),
|
||||
);
|
||||
(Protocols::Udp(protocol), true)
|
||||
},
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
self.init_protocol(protocol, Some(pid_sender), handshake)
|
||||
.await;
|
||||
}
|
||||
trace!("stop connect_mgr");
|
||||
}
|
||||
|
||||
async fn disconnect_mgr(
|
||||
&self,
|
||||
mut a2s_disconnect_r: mpsc::UnboundedReceiver<(
|
||||
Pid,
|
||||
oneshot::Sender<async_std::io::Result<()>>,
|
||||
)>,
|
||||
) {
|
||||
trace!("start disconnect_mgr");
|
||||
while let Some((pid, return_once_successfull_shutdown)) = a2s_disconnect_r.next().await {
|
||||
//Closing Participants is done the following way:
|
||||
// 1. We drop our senders and receivers
|
||||
// 2. we need to close BParticipant, this will drop its senderns and receivers
|
||||
// 3. Participant will try to access the BParticipant senders and receivers with
|
||||
// their next api action, it will fail and be closed then.
|
||||
trace!(?pid, "got request to close participant");
|
||||
if let Some(mut pi) = self.participants.write().await.remove(&pid) {
|
||||
let (finished_sender, finished_receiver) = oneshot::channel();
|
||||
pi.s2b_shutdown_bparticipant_s
|
||||
.take()
|
||||
.unwrap()
|
||||
.send(finished_sender)
|
||||
.unwrap();
|
||||
drop(pi);
|
||||
let e = finished_receiver.await.unwrap();
|
||||
return_once_successfull_shutdown.send(e).unwrap();
|
||||
} else {
|
||||
debug!(?pid, "looks like participant is already dropped");
|
||||
return_once_successfull_shutdown.send(Ok(())).unwrap();
|
||||
}
|
||||
trace!(?pid, "closed participant");
|
||||
}
|
||||
trace!("stop disconnect_mgr");
|
||||
}
|
||||
|
||||
async fn prio_adj_mgr(
|
||||
&self,
|
||||
mut b2s_prio_statistic_r: mpsc::UnboundedReceiver<(Pid, u64, u64)>,
|
||||
) {
|
||||
trace!("start prio_adj_mgr");
|
||||
while let Some((_pid, _frame_cnt, _unused)) = b2s_prio_statistic_r.next().await {
|
||||
|
||||
//TODO adjust prios in participants here!
|
||||
}
|
||||
trace!("stop prio_adj_mgr");
|
||||
}
|
||||
|
||||
async fn scheduler_shutdown_mgr(&self, a2s_scheduler_shutdown_r: oneshot::Receiver<()>) {
|
||||
trace!("start scheduler_shutdown_mgr");
|
||||
a2s_scheduler_shutdown_r.await.unwrap();
|
||||
self.closed.store(true, Ordering::Relaxed);
|
||||
debug!("shutting down all BParticipants gracefully");
|
||||
let mut participants = self.participants.write().await;
|
||||
let mut waitings = vec![];
|
||||
for (pid, mut pi) in participants.drain() {
|
||||
trace!(?pid, "shutting down BParticipants");
|
||||
let (finished_sender, finished_receiver) = oneshot::channel();
|
||||
waitings.push((pid, finished_receiver));
|
||||
pi.s2b_shutdown_bparticipant_s
|
||||
.take()
|
||||
.unwrap()
|
||||
.send(finished_sender)
|
||||
.unwrap();
|
||||
}
|
||||
debug!("wait for partiticipants to be shut down");
|
||||
for (pid, recv) in waitings {
|
||||
if let Err(e) = recv.await {
|
||||
error!(
|
||||
?pid,
|
||||
?e,
|
||||
"failed to finish sending all remainding messages to participant when \
|
||||
shutting down"
|
||||
);
|
||||
};
|
||||
}
|
||||
//removing the possibility to create new participants, needed to close down
|
||||
// some mgr:
|
||||
self.participant_channels.lock().await.take();
|
||||
|
||||
trace!("stop scheduler_shutdown_mgr");
|
||||
}
|
||||
|
||||
async fn channel_creator(
|
||||
&self,
|
||||
addr: Address,
|
||||
s2s_stop_listening_r: oneshot::Receiver<()>,
|
||||
s2a_listen_result_s: oneshot::Sender<io::Result<()>>,
|
||||
) {
|
||||
trace!(?addr, "start up channel creator");
|
||||
match addr {
|
||||
Address::Tcp(addr) => {
|
||||
let listener = match net::TcpListener::bind(addr).await {
|
||||
Ok(listener) => {
|
||||
s2a_listen_result_s.send(Ok(())).unwrap();
|
||||
listener
|
||||
},
|
||||
Err(e) => {
|
||||
info!(
|
||||
?addr,
|
||||
?e,
|
||||
"listener couldn't be started due to error on tcp bind"
|
||||
);
|
||||
s2a_listen_result_s.send(Err(e)).unwrap();
|
||||
return;
|
||||
},
|
||||
};
|
||||
trace!(?addr, "listener bound");
|
||||
let mut incoming = listener.incoming();
|
||||
let mut end_receiver = s2s_stop_listening_r.fuse();
|
||||
while let Some(stream) = select! {
|
||||
next = incoming.next().fuse() => next,
|
||||
_ = end_receiver => None,
|
||||
} {
|
||||
let stream = stream.unwrap();
|
||||
info!("Accepting Tcp from: {}", stream.peer_addr().unwrap());
|
||||
let protocol = TcpProtocol::new(stream, self.metrics.clone());
|
||||
self.init_protocol(Protocols::Tcp(protocol), None, true)
|
||||
.await;
|
||||
}
|
||||
},
|
||||
Address::Udp(addr) => {
|
||||
let socket = match net::UdpSocket::bind(addr).await {
|
||||
Ok(socket) => {
|
||||
s2a_listen_result_s.send(Ok(())).unwrap();
|
||||
Arc::new(socket)
|
||||
},
|
||||
Err(e) => {
|
||||
info!(
|
||||
?addr,
|
||||
?e,
|
||||
"listener couldn't be started due to error on udp bind"
|
||||
);
|
||||
s2a_listen_result_s.send(Err(e)).unwrap();
|
||||
return;
|
||||
},
|
||||
};
|
||||
trace!(?addr, "listener bound");
|
||||
// receiving is done from here and will be piped to protocol as UDP does not
|
||||
// have any state
|
||||
let mut listeners = HashMap::new();
|
||||
let mut end_receiver = s2s_stop_listening_r.fuse();
|
||||
let mut data = [0u8; 9216];
|
||||
while let Ok((size, remote_addr)) = select! {
|
||||
next = socket.recv_from(&mut data).fuse() => next,
|
||||
_ = end_receiver => Err(std::io::Error::new(std::io::ErrorKind::Other, "")),
|
||||
} {
|
||||
let mut datavec = Vec::with_capacity(size);
|
||||
datavec.extend_from_slice(&data[0..size]);
|
||||
//Due to the async nature i cannot make of .entry() as it would lead to a still
|
||||
// borrowed in another branch situation
|
||||
#[allow(clippy::map_entry)]
|
||||
if !listeners.contains_key(&remote_addr) {
|
||||
info!("Accepting Udp from: {}", &remote_addr);
|
||||
let (udp_data_sender, udp_data_receiver) = mpsc::unbounded::<Vec<u8>>();
|
||||
listeners.insert(remote_addr, udp_data_sender);
|
||||
let protocol = UdpProtocol::new(
|
||||
socket.clone(),
|
||||
remote_addr,
|
||||
self.metrics.clone(),
|
||||
udp_data_receiver,
|
||||
);
|
||||
self.init_protocol(Protocols::Udp(protocol), None, false)
|
||||
.await;
|
||||
}
|
||||
let udp_data_sender = listeners.get_mut(&remote_addr).unwrap();
|
||||
udp_data_sender.send(datavec).await.unwrap();
|
||||
}
|
||||
},
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
trace!(?addr, "ending channel creator");
|
||||
}
|
||||
|
||||
async fn udp_single_channel_connect(
|
||||
socket: Arc<net::UdpSocket>,
|
||||
mut w2p_udp_package_s: mpsc::UnboundedSender<Vec<u8>>,
|
||||
) {
|
||||
let addr = socket.local_addr();
|
||||
trace!(?addr, "start udp_single_channel_connect");
|
||||
//TODO: implement real closing
|
||||
let (_end_sender, end_receiver) = oneshot::channel::<()>();
|
||||
|
||||
// receiving is done from here and will be piped to protocol as UDP does not
|
||||
// have any state
|
||||
let mut end_receiver = end_receiver.fuse();
|
||||
let mut data = [0u8; 9216];
|
||||
while let Ok(size) = select! {
|
||||
next = socket.recv(&mut data).fuse() => next,
|
||||
_ = end_receiver => Err(std::io::Error::new(std::io::ErrorKind::Other, "")),
|
||||
} {
|
||||
let mut datavec = Vec::with_capacity(size);
|
||||
datavec.extend_from_slice(&data[0..size]);
|
||||
w2p_udp_package_s.send(datavec).await.unwrap();
|
||||
}
|
||||
trace!(?addr, "stop udp_single_channel_connect");
|
||||
}
|
||||
|
||||
async fn init_protocol(
|
||||
&self,
|
||||
protocol: Protocols,
|
||||
s2a_return_pid_s: Option<oneshot::Sender<io::Result<Participant>>>,
|
||||
send_handshake: bool,
|
||||
) {
|
||||
//channels are unknown till PID is known!
|
||||
/* When A connects to a NETWORK, we, the listener answers with a Handshake.
|
||||
Pro: - Its easier to debug, as someone who opens a port gets a magic number back!
|
||||
Contra: - DOS posibility because we answer fist
|
||||
- Speed, because otherwise the message can be send with the creation
|
||||
*/
|
||||
let mut participant_channels = self.participant_channels.lock().await.clone().unwrap();
|
||||
// spawn is needed here, e.g. for TCP connect it would mean that only 1
|
||||
// participant can be in handshake phase ever! Someone could deadlock
|
||||
// the whole server easily for new clients UDP doesnt work at all, as
|
||||
// the UDP listening is done in another place.
|
||||
let cid = self.channel_ids.fetch_add(1, Ordering::Relaxed);
|
||||
let participants = self.participants.clone();
|
||||
let metrics = self.metrics.clone();
|
||||
let pool = self.pool.clone();
|
||||
let local_pid = self.local_pid;
|
||||
let local_secret = self.local_secret;
|
||||
// this is necessary for UDP to work at all and to remove code duplication
|
||||
self.pool.spawn_ok(
|
||||
async move {
|
||||
trace!(?cid, "open channel and be ready for Handshake");
|
||||
let handshake = Handshake::new(
|
||||
cid,
|
||||
local_pid,
|
||||
local_secret,
|
||||
metrics.clone(),
|
||||
send_handshake,
|
||||
);
|
||||
match handshake.setup(&protocol).await {
|
||||
Ok((pid, sid, secret, leftover_cid_frame)) => {
|
||||
trace!(
|
||||
?cid,
|
||||
?pid,
|
||||
"detected that my channel is ready!, activating it :)"
|
||||
);
|
||||
let mut participants = participants.write().await;
|
||||
if !participants.contains_key(&pid) {
|
||||
debug!(?cid, "new participant connected via a channel");
|
||||
let (
|
||||
bparticipant,
|
||||
a2b_steam_open_s,
|
||||
b2a_stream_opened_r,
|
||||
mut s2b_create_channel_s,
|
||||
s2b_shutdown_bparticipant_s,
|
||||
) = BParticipant::new(pid, sid, metrics.clone());
|
||||
|
||||
let participant = Participant::new(
|
||||
local_pid,
|
||||
pid,
|
||||
a2b_steam_open_s,
|
||||
b2a_stream_opened_r,
|
||||
participant_channels.a2s_disconnect_s,
|
||||
);
|
||||
|
||||
metrics.participants_connected_total.inc();
|
||||
participants.insert(pid, ParticipantInfo {
|
||||
secret,
|
||||
s2b_create_channel_s: s2b_create_channel_s.clone(),
|
||||
s2b_shutdown_bparticipant_s: Some(s2b_shutdown_bparticipant_s),
|
||||
});
|
||||
pool.spawn_ok(
|
||||
bparticipant
|
||||
.run(participant_channels.b2s_prio_statistic_s)
|
||||
.instrument(tracing::info_span!("participant", ?pid)),
|
||||
);
|
||||
//create a new channel within BParticipant and wait for it to run
|
||||
let (b2s_create_channel_done_s, b2s_create_channel_done_r) =
|
||||
oneshot::channel();
|
||||
//From now on wire connects directly with bparticipant!
|
||||
s2b_create_channel_s
|
||||
.send((
|
||||
cid,
|
||||
sid,
|
||||
protocol,
|
||||
leftover_cid_frame,
|
||||
b2s_create_channel_done_s,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
b2s_create_channel_done_r.await.unwrap();
|
||||
if let Some(pid_oneshot) = s2a_return_pid_s {
|
||||
// someone is waiting with `connect`, so give them their PID
|
||||
pid_oneshot.send(Ok(participant)).unwrap();
|
||||
} else {
|
||||
// noone is waiting on this Participant, return in to Network
|
||||
participant_channels
|
||||
.s2a_connected_s
|
||||
.send(participant)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
let pi = &participants[&pid];
|
||||
trace!("2nd+ channel of participant, going to compare security ids");
|
||||
if pi.secret != secret {
|
||||
warn!(
|
||||
?pid,
|
||||
?secret,
|
||||
"Detected incompatible Secret!, this is probably an attack!"
|
||||
);
|
||||
error!("just dropping here, TODO handle this correctly!");
|
||||
//TODO
|
||||
if let Some(pid_oneshot) = s2a_return_pid_s {
|
||||
// someone is waiting with `connect`, so give them their Error
|
||||
pid_oneshot
|
||||
.send(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
"invalid secret, denying connection",
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
return;
|
||||
}
|
||||
error!(
|
||||
"ufff i cant answer the pid_oneshot. as i need to create the SAME \
|
||||
participant. maybe switch to ARC"
|
||||
);
|
||||
}
|
||||
//From now on this CHANNEL can receiver other frames!
|
||||
// move directly to participant!
|
||||
},
|
||||
Err(()) => {
|
||||
if let Some(pid_oneshot) = s2a_return_pid_s {
|
||||
// someone is waiting with `connect`, so give them their Error
|
||||
pid_oneshot
|
||||
.send(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
"handshake failed, denying connection",
|
||||
)))
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
.instrument(tracing::trace_span!("")),
|
||||
); /*WORKAROUND FOR SPAN NOT TO GET LOST*/
|
||||
}
|
||||
}
|
190
network/src/tcp_channel.rs
Normal file
190
network/src/tcp_channel.rs
Normal file
@ -0,0 +1,190 @@
|
||||
use crate::{
|
||||
api::Promise,
|
||||
internal::{Channel, Stream, TcpFrame, VELOREN_MAGIC_NUMBER, VELOREN_NETWORK_VERSION},
|
||||
};
|
||||
use bincode;
|
||||
use enumset::EnumSet;
|
||||
use mio::{self, net::TcpStream};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
io::{Read, Write},
|
||||
time::Instant,
|
||||
};
|
||||
use tracing::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TcpChannel {
|
||||
stream_id_pool: tlid::Pool<tlid::Wrapping<u32>>, //TODO: stream_id unique per participant
|
||||
msg_id_pool: tlid::Pool<tlid::Wrapping<u64>>, //TODO: msg_id unique per participant
|
||||
participant_id: Option<uuid::Uuid>,
|
||||
pub tcpstream: TcpStream,
|
||||
pub streams: Vec<Stream>,
|
||||
pub send_queue: VecDeque<TcpFrame>,
|
||||
pub recv_queue: VecDeque<TcpFrame>,
|
||||
}
|
||||
|
||||
impl TcpChannel {
|
||||
pub fn new(tcpstream: TcpStream) -> Self {
|
||||
TcpChannel {
|
||||
stream_id_pool: tlid::Pool::new_full(),
|
||||
msg_id_pool: tlid::Pool::new_full(),
|
||||
participant_id: None,
|
||||
tcpstream,
|
||||
streams: Vec::new(),
|
||||
send_queue: VecDeque::new(),
|
||||
recv_queue: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame(&mut self, frame: TcpFrame) {
|
||||
match frame {
|
||||
TcpFrame::Handshake {
|
||||
magic_number,
|
||||
version,
|
||||
} => {
|
||||
if magic_number != VELOREN_MAGIC_NUMBER {
|
||||
error!("tcp connection with invalid handshake, closing connection");
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug!("sending client instructions before killing");
|
||||
let _ = self.tcpstream.write(
|
||||
"Handshake does not contain the magic number requiered by veloren \
|
||||
server.\nWe are not sure if you are a valid veloren client.\nClosing \
|
||||
the connection"
|
||||
.as_bytes(),
|
||||
);
|
||||
}
|
||||
}
|
||||
if version != VELOREN_NETWORK_VERSION {
|
||||
error!("tcp connection with wrong network version");
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
debug!("sending client instructions before killing");
|
||||
let _ = self.tcpstream.write(
|
||||
format!(
|
||||
"Handshake does not contain a correct magic number, but invalid \
|
||||
version.\nWe don't know how to communicate with you.\nOur \
|
||||
Version: {:?}\nYour Version: {:?}\nClosing the connection",
|
||||
VELOREN_NETWORK_VERSION, version,
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
}
|
||||
}
|
||||
info!(?self, "handshake completed");
|
||||
},
|
||||
TcpFrame::ParticipantId { pid } => {
|
||||
self.participant_id = Some(pid);
|
||||
info!("Participant: {} send their ID", pid);
|
||||
},
|
||||
TcpFrame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
} => {
|
||||
if let Some(pid) = self.participant_id {
|
||||
let sid = self.stream_id_pool.next();
|
||||
let stream = Stream::new(sid, prio, promises.clone());
|
||||
self.streams.push(stream);
|
||||
info!("Participant: {} opened a stream", pid);
|
||||
}
|
||||
},
|
||||
TcpFrame::CloseStream { sid } => {
|
||||
if let Some(pid) = self.participant_id {
|
||||
self.streams.retain(|stream| stream.sid() != sid);
|
||||
info!("Participant: {} closed a stream", pid);
|
||||
}
|
||||
},
|
||||
TcpFrame::DataHeader { id, length } => {
|
||||
info!("Data Header {}", id);
|
||||
},
|
||||
TcpFrame::Data { id, frame_no, data } => {
|
||||
info!("Data Package {}", id);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Channel for TcpChannel {
|
||||
fn read(&mut self, uninitialized_dirty_speed_buffer: &mut [u8; 65000], aprox_time: Instant) {
|
||||
match self.tcpstream.read(uninitialized_dirty_speed_buffer) {
|
||||
Ok(n) => {
|
||||
trace!("incomming message with len: {}", n);
|
||||
let mut cur = std::io::Cursor::new(&uninitialized_dirty_speed_buffer[..n]);
|
||||
while cur.position() < n as u64 {
|
||||
let r: Result<TcpFrame, _> = bincode::deserialize_from(&mut cur);
|
||||
match r {
|
||||
Ok(frame) => self.handle_frame(frame),
|
||||
Err(e) => {
|
||||
error!(
|
||||
?self,
|
||||
?e,
|
||||
"failure parsing a message with len: {}, starting with: {:?}",
|
||||
n,
|
||||
&uninitialized_dirty_speed_buffer[0..std::cmp::min(n, 10)]
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
debug!("would block");
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("{}", e);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn write(&mut self, uninitialized_dirty_speed_buffer: &mut [u8; 65000], aprox_time: Instant) {
|
||||
while let Some(elem) = self.send_queue.pop_front() {
|
||||
if let Ok(mut data) = bincode::serialize(&elem) {
|
||||
let total = data.len();
|
||||
match self.tcpstream.write(&data) {
|
||||
Ok(n) if n == total => {},
|
||||
Ok(n) => {
|
||||
error!("could only send part");
|
||||
//let data = data.drain(n..).collect(); //TODO:
|
||||
// validate n.. is correct
|
||||
// to_send.push_front(data);
|
||||
},
|
||||
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
debug!("would block");
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("{}", e);
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn open_stream(&mut self, prio: u8, promises: EnumSet<Promise>) -> u32 {
|
||||
// validate promises
|
||||
let sid = self.stream_id_pool.next();
|
||||
let stream = Stream::new(sid, prio, promises.clone());
|
||||
self.streams.push(stream);
|
||||
self.send_queue.push_back(TcpFrame::OpenStream {
|
||||
sid,
|
||||
prio,
|
||||
promises,
|
||||
});
|
||||
sid
|
||||
}
|
||||
|
||||
fn close_stream(&mut self, sid: u32) {
|
||||
self.streams.retain(|stream| stream.sid() != sid);
|
||||
self.send_queue.push_back(TcpFrame::CloseStream { sid });
|
||||
}
|
||||
|
||||
fn handshake(&mut self) {
|
||||
self.send_queue.push_back(TcpFrame::Handshake {
|
||||
magic_number: VELOREN_MAGIC_NUMBER.to_string(),
|
||||
version: VELOREN_NETWORK_VERSION,
|
||||
});
|
||||
}
|
||||
|
||||
fn participant_id(&mut self, pid: uuid::Uuid) {
|
||||
self.send_queue.push_back(TcpFrame::ParticipantId { pid });
|
||||
}
|
||||
}
|
341
network/src/types.rs
Normal file
341
network/src/types.rs
Normal file
@ -0,0 +1,341 @@
|
||||
use rand::Rng;
|
||||
|
||||
pub type Mid = u64;
|
||||
pub type Cid = u64;
|
||||
pub type Prio = u8;
|
||||
/// use promises to modify the behavior of [`Streams`].
|
||||
/// available promises are:
|
||||
/// * [`PROMISES_NONE`]
|
||||
/// * [`PROMISES_ORDERED`]
|
||||
/// * [`PROMISES_CONSISTENCY`]
|
||||
/// * [`PROMISES_GUARANTEED_DELIVERY`]
|
||||
/// * [`PROMISES_COMPRESSED`]
|
||||
/// * [`PROMISES_ENCRYPTED`]
|
||||
///
|
||||
/// [`Streams`]: crate::api::Stream
|
||||
pub type Promises = u8;
|
||||
|
||||
/// use for no special promises on this [`Stream`](crate::api::Stream).
|
||||
pub const PROMISES_NONE: Promises = 0;
|
||||
/// this will guarantee that the order of messages which are send on one side,
|
||||
/// is the same when received on the other.
|
||||
pub const PROMISES_ORDERED: Promises = 1;
|
||||
/// this will guarantee that messages received haven't been altered by errors,
|
||||
/// like bit flips, this is done with a checksum.
|
||||
pub const PROMISES_CONSISTENCY: Promises = 2;
|
||||
/// this will guarantee that the other side will receive every message exactly
|
||||
/// once no messages are droped
|
||||
pub const PROMISES_GUARANTEED_DELIVERY: Promises = 4;
|
||||
/// this will enable the internal compression on this
|
||||
/// [`Stream`](crate::api::Stream)
|
||||
pub const PROMISES_COMPRESSED: Promises = 8;
|
||||
/// this will enable the internal encryption on this
|
||||
/// [`Stream`](crate::api::Stream)
|
||||
pub const PROMISES_ENCRYPTED: Promises = 16;
|
||||
|
||||
pub(crate) const VELOREN_MAGIC_NUMBER: [u8; 7] = [86, 69, 76, 79, 82, 69, 78]; //VELOREN
|
||||
pub const VELOREN_NETWORK_VERSION: [u32; 3] = [0, 2, 0];
|
||||
pub(crate) const STREAM_ID_OFFSET1: Sid = Sid::new(0);
|
||||
pub(crate) const STREAM_ID_OFFSET2: Sid = Sid::new(u64::MAX / 2);
|
||||
|
||||
/// Support struct used for uniquely identifying [`Participant`] over the
|
||||
/// [`Network`].
|
||||
///
|
||||
/// [`Participant`]: crate::api::Participant
|
||||
/// [`Network`]: crate::api::Network
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Pid {
|
||||
internal: u128,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub(crate) struct Sid {
|
||||
internal: u64,
|
||||
}
|
||||
|
||||
// Used for Communication between Channel <----(TCP/UDP)----> Channel
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Frame {
|
||||
Handshake {
|
||||
magic_number: [u8; 7],
|
||||
version: [u32; 3],
|
||||
},
|
||||
Init {
|
||||
pid: Pid,
|
||||
secret: u128,
|
||||
},
|
||||
Shutdown, /* Shutsdown this channel gracefully, if all channels are shut down, Participant
|
||||
* is deleted */
|
||||
OpenStream {
|
||||
sid: Sid,
|
||||
prio: Prio,
|
||||
promises: Promises,
|
||||
},
|
||||
CloseStream {
|
||||
sid: Sid,
|
||||
},
|
||||
DataHeader {
|
||||
mid: Mid,
|
||||
sid: Sid,
|
||||
length: u64,
|
||||
},
|
||||
Data {
|
||||
mid: Mid,
|
||||
start: u64,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
/* WARNING: Sending RAW is only used for debug purposes in case someone write a new API
|
||||
* against veloren Server! */
|
||||
Raw(Vec<u8>),
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub const FRAMES_LEN: u8 = 8;
|
||||
|
||||
pub const fn int_to_string(i: u8) -> &'static str {
|
||||
match i {
|
||||
0 => "Handshake",
|
||||
1 => "Init",
|
||||
2 => "Shutdown",
|
||||
3 => "OpenStream",
|
||||
4 => "CloseStream",
|
||||
5 => "DataHeader",
|
||||
6 => "Data",
|
||||
7 => "Raw",
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_int(&self) -> u8 {
|
||||
match self {
|
||||
Frame::Handshake {
|
||||
magic_number: _,
|
||||
version: _,
|
||||
} => 0,
|
||||
Frame::Init { pid: _, secret: _ } => 1,
|
||||
Frame::Shutdown => 2,
|
||||
Frame::OpenStream {
|
||||
sid: _,
|
||||
prio: _,
|
||||
promises: _,
|
||||
} => 3,
|
||||
Frame::CloseStream { sid: _ } => 4,
|
||||
Frame::DataHeader {
|
||||
mid: _,
|
||||
sid: _,
|
||||
length: _,
|
||||
} => 5,
|
||||
Frame::Data {
|
||||
mid: _,
|
||||
start: _,
|
||||
data: _,
|
||||
} => 6,
|
||||
Frame::Raw(_) => 7,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string(&self) -> &str { Self::int_to_string(self.get_int()) }
|
||||
}
|
||||
|
||||
impl Pid {
|
||||
/// create a new Pid with a random interior value
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use veloren_network::{Network, Pid};
|
||||
///
|
||||
/// let pid = Pid::new();
|
||||
/// let _ = Network::new(pid, None);
|
||||
/// ```
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
internal: rand::thread_rng().gen(),
|
||||
}
|
||||
}
|
||||
|
||||
/// don't use fake! just for testing!
|
||||
/// This will panic if pid i greater than 7, as I do not want you to use
|
||||
/// this in production!
|
||||
#[doc(hidden)]
|
||||
pub fn fake(pid: u8) -> Self {
|
||||
assert!(pid < 8);
|
||||
Self {
|
||||
internal: pid as u128,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_le_bytes(&self) -> [u8; 16] { self.internal.to_le_bytes() }
|
||||
|
||||
pub(crate) fn from_le_bytes(bytes: [u8; 16]) -> Self {
|
||||
Self {
|
||||
internal: u128::from_le_bytes(bytes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sid {
|
||||
pub const fn new(internal: u64) -> Self { Self { internal } }
|
||||
|
||||
pub(crate) fn to_le_bytes(&self) -> [u8; 8] { self.internal.to_le_bytes() }
|
||||
|
||||
pub(crate) fn from_le_bytes(bytes: [u8; 8]) -> Self {
|
||||
Self {
|
||||
internal: u64::from_le_bytes(bytes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Pid {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
const BITS_PER_SIXLET: usize = 6;
|
||||
//only print last 6 chars of number as full u128 logs are unreadable
|
||||
const CHAR_COUNT: usize = 6;
|
||||
for i in 0..CHAR_COUNT {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
sixlet_to_str((self.internal >> (i * BITS_PER_SIXLET)) & 0x3F)
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Pid {
|
||||
fn default() -> Self { Pid::new() }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Pid {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) }
|
||||
}
|
||||
|
||||
impl std::ops::AddAssign for Sid {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
*self = Self {
|
||||
internal: self.internal + other.internal,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Sid {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
//only print last 6 chars of number as full u128 logs are unreadable
|
||||
write!(f, "{}", self.internal.rem_euclid(1000000))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Sid {
|
||||
fn from(internal: u64) -> Self { Sid { internal } }
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Sid {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.internal)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sixlet_to_str(sixlet: u128) -> char {
|
||||
match sixlet {
|
||||
0 => 'A',
|
||||
1 => 'B',
|
||||
2 => 'C',
|
||||
3 => 'D',
|
||||
4 => 'E',
|
||||
5 => 'F',
|
||||
6 => 'G',
|
||||
7 => 'H',
|
||||
8 => 'I',
|
||||
9 => 'J',
|
||||
10 => 'K',
|
||||
11 => 'L',
|
||||
12 => 'M',
|
||||
13 => 'N',
|
||||
14 => 'O',
|
||||
15 => 'P',
|
||||
16 => 'Q',
|
||||
17 => 'R',
|
||||
18 => 'S',
|
||||
19 => 'T',
|
||||
20 => 'U',
|
||||
21 => 'V',
|
||||
22 => 'W',
|
||||
23 => 'X',
|
||||
24 => 'Y',
|
||||
25 => 'Z',
|
||||
26 => 'a',
|
||||
27 => 'b',
|
||||
28 => 'c',
|
||||
29 => 'd',
|
||||
30 => 'e',
|
||||
31 => 'f',
|
||||
32 => 'g',
|
||||
33 => 'h',
|
||||
34 => 'i',
|
||||
35 => 'j',
|
||||
36 => 'k',
|
||||
37 => 'l',
|
||||
38 => 'm',
|
||||
39 => 'n',
|
||||
40 => 'o',
|
||||
41 => 'p',
|
||||
42 => 'q',
|
||||
43 => 'r',
|
||||
44 => 's',
|
||||
45 => 't',
|
||||
46 => 'u',
|
||||
47 => 'v',
|
||||
48 => 'w',
|
||||
49 => 'x',
|
||||
50 => 'y',
|
||||
51 => 'z',
|
||||
52 => '0',
|
||||
53 => '1',
|
||||
54 => '2',
|
||||
55 => '3',
|
||||
56 => '4',
|
||||
57 => '5',
|
||||
58 => '6',
|
||||
59 => '7',
|
||||
60 => '8',
|
||||
61 => '9',
|
||||
62 => '+',
|
||||
63 => '/',
|
||||
_ => '-',
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::types::*;
|
||||
|
||||
#[test]
|
||||
fn frame_int2str() {
|
||||
assert_eq!(Frame::int_to_string(3), "OpenStream");
|
||||
assert_eq!(Frame::int_to_string(7), "Raw");
|
||||
assert_eq!(Frame::int_to_string(8), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_get_int() {
|
||||
assert_eq!(Frame::get_int(&Frame::Raw("Foo".as_bytes().to_vec())), 7);
|
||||
assert_eq!(Frame::get_int(&Frame::Shutdown), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_creation() {
|
||||
Pid::new();
|
||||
assert_eq!(format!("{}", Pid::fake(2)), "CAAAAA");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sixlet_to_str() {
|
||||
assert_eq!(sixlet_to_str(0), 'A');
|
||||
assert_eq!(sixlet_to_str(63), '/');
|
||||
assert_eq!(sixlet_to_str(64), '-');
|
||||
}
|
||||
}
|
166
network/tests/closing.rs
Normal file
166
network/tests/closing.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use async_std::task;
|
||||
use task::block_on;
|
||||
use veloren_network::StreamError;
|
||||
mod helper;
|
||||
use helper::{network_participant_stream, tcp};
|
||||
|
||||
#[test]
|
||||
fn close_network() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_, _p1_a, mut s1_a, _, _p1_b, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
|
||||
assert_eq!(s1_a.send("Hello World"), Err(StreamError::StreamClosed));
|
||||
let msg1: Result<String, _> = block_on(s1_b.recv());
|
||||
assert_eq!(msg1, Err(StreamError::StreamClosed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn close_participant() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (n_a, p1_a, mut s1_a, n_b, p1_b, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
block_on(n_a.disconnect(p1_a)).unwrap();
|
||||
block_on(n_b.disconnect(p1_b)).unwrap();
|
||||
|
||||
assert_eq!(s1_a.send("Hello World"), Err(StreamError::StreamClosed));
|
||||
assert_eq!(
|
||||
block_on(s1_b.recv::<String>()),
|
||||
Err(StreamError::StreamClosed)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn close_stream() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, _) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
// s1_b is dropped directly while s1_a isn't
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
|
||||
assert_eq!(s1_a.send("Hello World"), Err(StreamError::StreamClosed));
|
||||
assert_eq!(
|
||||
block_on(s1_a.recv::<String>()),
|
||||
Err(StreamError::StreamClosed)
|
||||
);
|
||||
}
|
||||
|
||||
///THIS is actually a bug which currently luckily doesn't trigger, but with new
|
||||
/// async-std WE must make sure, if a stream is `drop`ed inside a `block_on`,
|
||||
/// that no panic is thrown.
|
||||
#[test]
|
||||
fn close_streams_in_block_on() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _p_a, s1_a, _n_b, _p_b, s1_b) = block_on(network_participant_stream(tcp()));
|
||||
block_on(async {
|
||||
//make it locally so that they are dropped later
|
||||
let mut s1_a = s1_a;
|
||||
let mut s1_b = s1_b;
|
||||
s1_a.send("ping").unwrap();
|
||||
assert_eq!(s1_b.recv().await, Ok("ping".to_string()));
|
||||
drop(s1_a);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_simple_3msg_then_close() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
s1_a.send(1u8).unwrap();
|
||||
s1_a.send(42).unwrap();
|
||||
s1_a.send("3rdMessage").unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok(1u8));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok(42));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("3rdMessage".to_string()));
|
||||
drop(s1_a);
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
assert_eq!(s1_b.send("Hello World"), Err(StreamError::StreamClosed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_first_then_receive() {
|
||||
// recv should still be possible even if stream got closed if they are in queue
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
s1_a.send(1u8).unwrap();
|
||||
s1_a.send(42).unwrap();
|
||||
s1_a.send("3rdMessage").unwrap();
|
||||
drop(s1_a);
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok(1u8));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok(42));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("3rdMessage".to_string()));
|
||||
assert_eq!(s1_b.send("Hello World"), Err(StreamError::StreamClosed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_1_then_close_stream() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
s1_a.send("this message must be received, even if stream is closed already!")
|
||||
.unwrap();
|
||||
drop(s1_a);
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
let exp = Ok("this message must be received, even if stream is closed already!".to_string());
|
||||
assert_eq!(block_on(s1_b.recv()), exp);
|
||||
println!("all received and done");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_100000_then_close_stream() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
for _ in 0..100000 {
|
||||
s1_a.send("woop_PARTY_HARD_woop").unwrap();
|
||||
}
|
||||
drop(s1_a);
|
||||
let exp = Ok("woop_PARTY_HARD_woop".to_string());
|
||||
println!("start receiving");
|
||||
block_on(async {
|
||||
for _ in 0..100000 {
|
||||
assert_eq!(s1_b.recv().await, exp);
|
||||
}
|
||||
});
|
||||
println!("all received and done");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_100000_then_close_stream_remote() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, _s1_b) = block_on(network_participant_stream(tcp()));
|
||||
for _ in 0..100000 {
|
||||
s1_a.send("woop_PARTY_HARD_woop").unwrap();
|
||||
}
|
||||
drop(s1_a);
|
||||
drop(_s1_b);
|
||||
//no receiving
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_100000_then_close_stream_remote2() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, _s1_b) = block_on(network_participant_stream(tcp()));
|
||||
for _ in 0..100000 {
|
||||
s1_a.send("woop_PARTY_HARD_woop").unwrap();
|
||||
}
|
||||
drop(_s1_b);
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
drop(s1_a);
|
||||
//no receiving
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_send_100000_then_close_stream_remote3() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, _s1_b) = block_on(network_participant_stream(tcp()));
|
||||
for _ in 0..100000 {
|
||||
s1_a.send("woop_PARTY_HARD_woop").unwrap();
|
||||
}
|
||||
drop(_s1_b);
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
drop(s1_a);
|
||||
//no receiving
|
||||
}
|
93
network/tests/helper.rs
Normal file
93
network/tests/helper.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use lazy_static::*;
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicU16, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::*;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use veloren_network::{Address, Network, Participant, Pid, Stream, PROMISES_NONE};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn setup(tracing: bool, mut sleep: u64) -> (u64, u64) {
|
||||
if tracing {
|
||||
sleep += 1000
|
||||
}
|
||||
if sleep > 0 {
|
||||
thread::sleep(Duration::from_millis(sleep));
|
||||
}
|
||||
|
||||
let _subscriber = if tracing {
|
||||
let filter = EnvFilter::from_default_env()
|
||||
.add_directive("trace".parse().unwrap())
|
||||
.add_directive("async_std::task::block_on=warn".parse().unwrap())
|
||||
.add_directive("veloren_network::tests=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::controller=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::channel=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::message=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::metrics=trace".parse().unwrap())
|
||||
.add_directive("veloren_network::types=trace".parse().unwrap());
|
||||
|
||||
Some(
|
||||
tracing_subscriber::FmtSubscriber::builder()
|
||||
// all spans/events with a level higher than TRACE (e.g, info, warn, etc.)
|
||||
// will be written to stdout.
|
||||
.with_max_level(Level::TRACE)
|
||||
.with_env_filter(filter)
|
||||
// sets this to be the default, global subscriber for this application.
|
||||
.try_init(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(0, 0)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn network_participant_stream(
|
||||
addr: Address,
|
||||
) -> (
|
||||
Network,
|
||||
Arc<Participant>,
|
||||
Stream,
|
||||
Network,
|
||||
Arc<Participant>,
|
||||
Stream,
|
||||
) {
|
||||
let (n_a, f_a) = Network::new(Pid::fake(1), None);
|
||||
std::thread::spawn(f_a);
|
||||
let (n_b, f_b) = Network::new(Pid::fake(2), None);
|
||||
std::thread::spawn(f_b);
|
||||
|
||||
n_a.listen(addr.clone()).await.unwrap();
|
||||
let p1_b = n_b.connect(addr).await.unwrap();
|
||||
let p1_a = n_a.connected().await.unwrap();
|
||||
|
||||
let s1_a = p1_a.open(10, PROMISES_NONE).await.unwrap();
|
||||
let s1_b = p1_b.opened().await.unwrap();
|
||||
|
||||
(n_a, p1_a, s1_a, n_b, p1_b, s1_b)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn tcp() -> veloren_network::Address {
|
||||
lazy_static! {
|
||||
static ref PORTS: AtomicU16 = AtomicU16::new(5000);
|
||||
}
|
||||
let port = PORTS.fetch_add(1, Ordering::Relaxed);
|
||||
veloren_network::Address::Tcp(SocketAddr::from(([127, 0, 0, 1], port)))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn udp() -> veloren_network::Address {
|
||||
lazy_static! {
|
||||
static ref PORTS: AtomicU16 = AtomicU16::new(5000);
|
||||
}
|
||||
let port = PORTS.fetch_add(1, Ordering::Relaxed);
|
||||
veloren_network::Address::Udp(SocketAddr::from(([127, 0, 0, 1], port)))
|
||||
}
|
184
network/tests/integration.rs
Normal file
184
network/tests/integration.rs
Normal file
@ -0,0 +1,184 @@
|
||||
use async_std::task;
|
||||
use task::block_on;
|
||||
use veloren_network::{NetworkError, StreamError};
|
||||
mod helper;
|
||||
use helper::{network_participant_stream, tcp, udp};
|
||||
use std::io::ErrorKind;
|
||||
use veloren_network::{Address, Network, Pid, PROMISES_CONSISTENCY, PROMISES_ORDERED};
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn network_20s() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, _, _n_b, _, _) = block_on(network_participant_stream(tcp()));
|
||||
std::thread::sleep(std::time::Duration::from_secs(30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_simple() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
s1_a.send("Hello World").unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("Hello World".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_simple_3msg() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
s1_a.send("Hello World").unwrap();
|
||||
s1_a.send(1337).unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("Hello World".to_string()));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok(1337));
|
||||
s1_a.send("3rdMessage").unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("3rdMessage".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_simple_udp() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(udp()));
|
||||
|
||||
s1_a.send("Hello World").unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("Hello World".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stream_simple_udp_3msg() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(udp()));
|
||||
|
||||
s1_a.send("Hello World").unwrap();
|
||||
s1_a.send(1337).unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("Hello World".to_string()));
|
||||
assert_eq!(block_on(s1_b.recv()), Ok(1337));
|
||||
s1_a.send("3rdMessage").unwrap();
|
||||
assert_eq!(block_on(s1_b.recv()), Ok("3rdMessage".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn tcp_and_udp_2_connections() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (network, f) = Network::new(Pid::new(), None);
|
||||
let (remote, fr) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f);
|
||||
std::thread::spawn(fr);
|
||||
block_on(async {
|
||||
remote
|
||||
.listen(Address::Tcp("0.0.0.0:2000".parse().unwrap()))
|
||||
.await?;
|
||||
remote
|
||||
.listen(Address::Udp("0.0.0.0:2001".parse().unwrap()))
|
||||
.await?;
|
||||
let p1 = network
|
||||
.connect(Address::Tcp("127.0.0.1:2000".parse().unwrap()))
|
||||
.await?;
|
||||
let p2 = network
|
||||
.connect(Address::Udp("127.0.0.1:2001".parse().unwrap()))
|
||||
.await?;
|
||||
assert!(std::sync::Arc::ptr_eq(&p1, &p2));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_listen_on_used_ports() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (network, f) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f);
|
||||
let udp1 = udp();
|
||||
let tcp1 = tcp();
|
||||
block_on(network.listen(udp1.clone()))?;
|
||||
block_on(network.listen(tcp1.clone()))?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
|
||||
let (network2, f2) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f2);
|
||||
let e1 = block_on(network2.listen(udp1));
|
||||
let e2 = block_on(network2.listen(tcp1));
|
||||
match e1 {
|
||||
Err(NetworkError::ListenFailed(e)) if e.kind() == ErrorKind::AddrInUse => (),
|
||||
_ => assert!(false),
|
||||
};
|
||||
match e2 {
|
||||
Err(NetworkError::ListenFailed(e)) if e.kind() == ErrorKind::AddrInUse => (),
|
||||
_ => assert!(false),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// There is a bug an impris-desktop-1 which fails the DOC tests,
|
||||
/// it fails exactly `api_stream_send_main` and `api_stream_recv_main` by
|
||||
/// deadlocking at different times!
|
||||
/// So i rather put the same test into a unit test, these are now duplicate to
|
||||
/// the api, but are left here, just to be save!
|
||||
#[test]
|
||||
fn api_stream_send_main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
// Create a Network, listen on Port `1200` and wait for a Stream to be opened,
|
||||
// then answer `Hello World`
|
||||
let (network, f) = Network::new(Pid::new(), None);
|
||||
let (remote, fr) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f);
|
||||
std::thread::spawn(fr);
|
||||
block_on(async {
|
||||
network
|
||||
.listen(Address::Tcp("127.0.0.1:1200".parse().unwrap()))
|
||||
.await?;
|
||||
let remote_p = remote
|
||||
.connect(Address::Tcp("127.0.0.1:1200".parse().unwrap()))
|
||||
.await?;
|
||||
// keep it alive
|
||||
let _stream_p = remote_p
|
||||
.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
.await?;
|
||||
let participant_a = network.connected().await?;
|
||||
let mut stream_a = participant_a.opened().await?;
|
||||
//Send Message
|
||||
stream_a.send("Hello World")?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_stream_recv_main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
// Create a Network, listen on Port `1220` and wait for a Stream to be opened,
|
||||
// then listen on it
|
||||
let (network, f) = Network::new(Pid::new(), None);
|
||||
let (remote, fr) = Network::new(Pid::new(), None);
|
||||
std::thread::spawn(f);
|
||||
std::thread::spawn(fr);
|
||||
block_on(async {
|
||||
network
|
||||
.listen(Address::Tcp("127.0.0.1:1220".parse().unwrap()))
|
||||
.await?;
|
||||
let remote_p = remote
|
||||
.connect(Address::Tcp("127.0.0.1:1220".parse().unwrap()))
|
||||
.await?;
|
||||
let mut stream_p = remote_p
|
||||
.open(16, PROMISES_ORDERED | PROMISES_CONSISTENCY)
|
||||
.await?;
|
||||
stream_p.send("Hello World")?;
|
||||
let participant_a = network.connected().await?;
|
||||
let mut stream_a = participant_a.opened().await?;
|
||||
//Send Message
|
||||
assert_eq!("Hello World".to_string(), stream_a.recv::<String>().await?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_parse() {
|
||||
let (_, _) = helper::setup(false, 0);
|
||||
let (_n_a, _, mut s1_a, _n_b, _, mut s1_b) = block_on(network_participant_stream(tcp()));
|
||||
|
||||
s1_a.send(1337).unwrap();
|
||||
match block_on(s1_b.recv::<String>()) {
|
||||
Err(StreamError::DeserializeError(_)) => assert!(true),
|
||||
_ => assert!(false, "this should fail, but it doesnt!"),
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ use common::{
|
||||
vol::{ReadVol, RectVolSize},
|
||||
};
|
||||
use log::{debug, error};
|
||||
use metrics::ServerMetrics;
|
||||
use metrics::{ServerMetrics, TickMetrics};
|
||||
use specs::{join::Join, Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt};
|
||||
use std::{
|
||||
i32,
|
||||
@ -80,6 +80,7 @@ pub struct Server {
|
||||
|
||||
server_info: ServerInfo,
|
||||
metrics: ServerMetrics,
|
||||
tick_metrics: TickMetrics,
|
||||
|
||||
server_settings: ServerSettings,
|
||||
}
|
||||
@ -215,6 +216,14 @@ impl Server {
|
||||
|
||||
state.ecs_mut().insert(DeletedEntities::default());
|
||||
|
||||
let mut metrics = ServerMetrics::new();
|
||||
// register all metrics submodules here
|
||||
let tick_metrics = TickMetrics::new(metrics.registry(), metrics.tick_clone())
|
||||
.expect("Failed to initialize server tick metrics submodule.");
|
||||
metrics
|
||||
.run(settings.metrics_address)
|
||||
.expect("Failed to initialize server metrics submodule.");
|
||||
|
||||
let this = Self {
|
||||
state,
|
||||
world: Arc::new(world),
|
||||
@ -233,8 +242,8 @@ impl Server {
|
||||
git_date: common::util::GIT_DATE.to_string(),
|
||||
auth_provider: settings.auth_server_address.clone(),
|
||||
},
|
||||
metrics: ServerMetrics::new(settings.metrics_address)
|
||||
.expect("Failed to initialize server metrics submodule."),
|
||||
metrics,
|
||||
tick_metrics,
|
||||
server_settings: settings.clone(),
|
||||
};
|
||||
|
||||
@ -401,90 +410,91 @@ impl Server {
|
||||
let total_sys_ran_in_dispatcher_nanos = terrain_nanos + waypoint_nanos;
|
||||
|
||||
// Report timing info
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["new connections"])
|
||||
.set((before_message_system - before_new_connections).as_nanos() as i64);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["state tick"])
|
||||
.set(
|
||||
(before_handle_events - before_state_tick).as_nanos() as i64
|
||||
- total_sys_ran_in_dispatcher_nanos,
|
||||
);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["handle server events"])
|
||||
.set((before_update_terrain_and_regions - before_handle_events).as_nanos() as i64);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["update terrain and region map"])
|
||||
.set((before_sync - before_update_terrain_and_regions).as_nanos() as i64);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["world tick"])
|
||||
.set((before_entity_cleanup - before_world_tick).as_nanos() as i64);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["entity cleanup"])
|
||||
.set((end_of_server_tick - before_entity_cleanup).as_nanos() as i64);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["entity sync"])
|
||||
.set(entity_sync_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["message"])
|
||||
.set(message_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["sentinel"])
|
||||
.set(sentinel_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["subscription"])
|
||||
.set(subscription_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["terrain sync"])
|
||||
.set(terrain_sync_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["terrain"])
|
||||
.set(terrain_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["waypoint"])
|
||||
.set(waypoint_nanos);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["persistence:stats"])
|
||||
.set(stats_persistence_nanos);
|
||||
|
||||
// Report other info
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.player_online
|
||||
.set(self.state.ecs().read_storage::<Client>().join().count() as i64);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.time_of_day
|
||||
.set(self.state.ecs().read_resource::<TimeOfDay>().0);
|
||||
if self.metrics.is_100th_tick() {
|
||||
if self.tick_metrics.is_100th_tick() {
|
||||
let mut chonk_cnt = 0;
|
||||
let chunk_cnt = self.state.terrain().iter().fold(0, |a, (_, c)| {
|
||||
chonk_cnt += 1;
|
||||
a + c.sub_chunks_len()
|
||||
});
|
||||
self.metrics.chonks_count.set(chonk_cnt as i64);
|
||||
self.metrics.chunks_count.set(chunk_cnt as i64);
|
||||
self.tick_metrics.chonks_count.set(chonk_cnt as i64);
|
||||
self.tick_metrics.chunks_count.set(chunk_cnt as i64);
|
||||
|
||||
let entity_count = self.state.ecs().entities().join().count();
|
||||
self.metrics.entity_count.set(entity_count as i64);
|
||||
self.tick_metrics.entity_count.set(entity_count as i64);
|
||||
}
|
||||
//self.metrics.entity_count.set(self.state.);
|
||||
self.metrics
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["metrics"])
|
||||
.set(end_of_server_tick.elapsed().as_nanos() as i64);
|
||||
self.metrics.tick();
|
||||
|
||||
// 8) Finish the tick, pass control back to the frontend.
|
||||
|
||||
@ -588,7 +598,7 @@ impl Server {
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn number_of_players(&self) -> i64 { self.metrics.player_online.get() }
|
||||
pub fn number_of_players(&self) -> i64 { self.tick_metrics.player_online.get() }
|
||||
}
|
||||
|
||||
impl Drop for Server {
|
||||
|
@ -6,14 +6,14 @@ use std::{
|
||||
error::Error,
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
pub struct ServerMetrics {
|
||||
pub struct TickMetrics {
|
||||
pub chonks_count: IntGauge,
|
||||
pub chunks_count: IntGauge,
|
||||
pub player_online: IntGauge,
|
||||
@ -23,77 +23,116 @@ pub struct ServerMetrics {
|
||||
pub start_time: IntGauge,
|
||||
pub time_of_day: Gauge,
|
||||
pub light_count: IntGauge,
|
||||
running: Arc<AtomicBool>,
|
||||
pub handle: Option<thread::JoinHandle<()>>,
|
||||
pub every_100th: i8,
|
||||
tick: Arc<AtomicU64>,
|
||||
}
|
||||
|
||||
impl ServerMetrics {
|
||||
pub fn new(addr: SocketAddr) -> Result<Self, Box<dyn Error>> {
|
||||
let opts = Opts::new(
|
||||
pub struct ServerMetrics {
|
||||
running: Arc<AtomicBool>,
|
||||
handle: Option<thread::JoinHandle<()>>,
|
||||
registry: Option<Registry>,
|
||||
tick: Arc<AtomicU64>,
|
||||
}
|
||||
|
||||
impl TickMetrics {
|
||||
pub fn new(registry: &Registry, tick: Arc<AtomicU64>) -> Result<Self, Box<dyn Error>> {
|
||||
let player_online = IntGauge::with_opts(Opts::new(
|
||||
"player_online",
|
||||
"shows the number of clients connected to the server",
|
||||
);
|
||||
let player_online = IntGauge::with_opts(opts)?;
|
||||
let opts = Opts::new(
|
||||
))?;
|
||||
let entity_count = IntGauge::with_opts(Opts::new(
|
||||
"entity_count",
|
||||
"number of all entities currently active on the server",
|
||||
);
|
||||
let entity_count = IntGauge::with_opts(opts)?;
|
||||
))?;
|
||||
let opts = Opts::new("veloren_build_info", "Build information")
|
||||
.const_label("hash", &common::util::GIT_HASH)
|
||||
.const_label("version", "");
|
||||
let build_info = IntGauge::with_opts(opts)?;
|
||||
let opts = Opts::new(
|
||||
let start_time = IntGauge::with_opts(Opts::new(
|
||||
"veloren_start_time",
|
||||
"start time of the server in seconds since EPOCH",
|
||||
);
|
||||
let start_time = IntGauge::with_opts(opts)?;
|
||||
let opts = Opts::new("time_of_day", "ingame time in ingame-seconds");
|
||||
let time_of_day = Gauge::with_opts(opts)?;
|
||||
let opts = Opts::new(
|
||||
))?;
|
||||
let time_of_day =
|
||||
Gauge::with_opts(Opts::new("time_of_day", "ingame time in ingame-seconds"))?;
|
||||
let light_count = IntGauge::with_opts(Opts::new(
|
||||
"light_count",
|
||||
"number of all lights currently active on the server",
|
||||
);
|
||||
let light_count = IntGauge::with_opts(opts)?;
|
||||
let opts = Opts::new(
|
||||
))?;
|
||||
let chonks_count = IntGauge::with_opts(Opts::new(
|
||||
"chonks_count",
|
||||
"number of all chonks currently active on the server",
|
||||
);
|
||||
let chonks_count = IntGauge::with_opts(opts)?;
|
||||
let opts = Opts::new(
|
||||
))?;
|
||||
let chunks_count = IntGauge::with_opts(Opts::new(
|
||||
"chunks_count",
|
||||
"number of all chunks currently active on the server",
|
||||
);
|
||||
let chunks_count = IntGauge::with_opts(opts)?;
|
||||
let vec = IntGaugeVec::new(
|
||||
))?;
|
||||
let tick_time = IntGaugeVec::from(IntGaugeVec::new(
|
||||
Opts::new("tick_time", "time in ns requiered for a tick of the server"),
|
||||
&["period"],
|
||||
)?;
|
||||
let tick_time = IntGaugeVec::from(vec);
|
||||
)?);
|
||||
|
||||
let since_the_epoch = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards");
|
||||
start_time.set(since_the_epoch.as_secs().try_into()?);
|
||||
|
||||
let registry = Registry::new();
|
||||
//registry.register(Box::new(chonks_count.clone())).unwrap();
|
||||
registry.register(Box::new(player_online.clone()))?;
|
||||
registry.register(Box::new(entity_count.clone()))?;
|
||||
registry.register(Box::new(build_info.clone()))?;
|
||||
registry.register(Box::new(start_time.clone()))?;
|
||||
registry.register(Box::new(time_of_day.clone()))?;
|
||||
//registry.register(Box::new(light_count.clone())).unwrap();
|
||||
registry.register(Box::new(chonks_count.clone()))?;
|
||||
registry.register(Box::new(chunks_count.clone()))?;
|
||||
registry.register(Box::new(tick_time.clone()))?;
|
||||
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
let running2 = running.clone();
|
||||
Ok(Self {
|
||||
chonks_count,
|
||||
chunks_count,
|
||||
player_online,
|
||||
entity_count,
|
||||
tick_time,
|
||||
build_info,
|
||||
start_time,
|
||||
time_of_day,
|
||||
light_count,
|
||||
tick,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_100th_tick(&self) -> bool { self.tick.load(Ordering::Relaxed).rem_euclid(100) == 0 }
|
||||
}
|
||||
|
||||
impl ServerMetrics {
|
||||
pub fn new() -> Self {
|
||||
let running = Arc::new(AtomicBool::new(false));
|
||||
let tick = Arc::new(AtomicU64::new(0));
|
||||
let registry = Some(Registry::new());
|
||||
|
||||
Self {
|
||||
running,
|
||||
handle: None,
|
||||
registry,
|
||||
tick,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn registry(&self) -> &Registry {
|
||||
match self.registry {
|
||||
Some(ref r) => r,
|
||||
None => panic!("You cannot longer register new metrics after the server has started!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, addr: SocketAddr) -> Result<(), Box<dyn Error>> {
|
||||
self.running.store(true, Ordering::Relaxed);
|
||||
let running2 = self.running.clone();
|
||||
|
||||
let registry = self
|
||||
.registry
|
||||
.take()
|
||||
.expect("ServerMetrics must be already started");
|
||||
|
||||
//TODO: make this a job
|
||||
let handle = Some(thread::spawn(move || {
|
||||
self.handle = Some(thread::spawn(move || {
|
||||
let server = Server::new(addr, move |request| {
|
||||
router!(request,
|
||||
(GET) (/metrics) => {
|
||||
@ -106,7 +145,7 @@ impl ServerMetrics {
|
||||
_ => rouille::Response::empty_404()
|
||||
)
|
||||
})
|
||||
.expect("Failed to start server");
|
||||
.expect("Failed to start server");
|
||||
info!("Started server metrics: {}", addr);
|
||||
while running2.load(Ordering::Relaxed) {
|
||||
server.poll();
|
||||
@ -114,32 +153,12 @@ impl ServerMetrics {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(Self {
|
||||
chonks_count,
|
||||
chunks_count,
|
||||
player_online,
|
||||
entity_count,
|
||||
tick_time,
|
||||
build_info,
|
||||
start_time,
|
||||
time_of_day,
|
||||
light_count,
|
||||
running,
|
||||
handle,
|
||||
every_100th: 0,
|
||||
})
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_100th_tick(&mut self) -> bool {
|
||||
self.every_100th += 1;
|
||||
if self.every_100th == 100 {
|
||||
self.every_100th = 0;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn tick(&self) -> u64 { self.tick.fetch_add(1, Ordering::Relaxed) + 1 }
|
||||
|
||||
pub fn tick_clone(&self) -> Arc<AtomicU64> { self.tick.clone() }
|
||||
}
|
||||
|
||||
impl Drop for ServerMetrics {
|
||||
|
Loading…
Reference in New Issue
Block a user