Node management (#5)
* Add modules * Implemented waku config struct * Implemented waku management functions * Use optional config in waku_new * Added config docs * Fix tests * Dbg error on gh actions * Added fail result to dbg * Removed gh actions dbg * NodeConfig -> WakuNodeConfig * Removed duplicated test * Implemented safety layer on top of node * Add exclusive running test * Use static instead of const for global flag * Do not allow for double initialization * Update submodule to latest master commit with responses fixes * Merge tests
This commit is contained in:
parent
84d251ff1b
commit
d320e55701
|
@ -11,6 +11,12 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -28,6 +34,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.60.1"
|
version = "0.60.1"
|
||||||
|
@ -57,6 +69,27 @@ version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bs58"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cexpr"
|
name = "cexpr"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -107,6 +140,55 @@ dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core2"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-mac"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding"
|
||||||
|
version = "2.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -126,6 +208,36 @@ dependencies = [
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -147,12 +259,49 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-mac",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac-drbg"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"generic-array",
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
|
@ -197,6 +346,54 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsecp256k1"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"base64",
|
||||||
|
"digest",
|
||||||
|
"hmac-drbg",
|
||||||
|
"libsecp256k1-core",
|
||||||
|
"libsecp256k1-gen-ecmult",
|
||||||
|
"libsecp256k1-gen-genmult",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsecp256k1-core"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451"
|
||||||
|
dependencies = [
|
||||||
|
"crunchy",
|
||||||
|
"digest",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsecp256k1-gen-ecmult"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809"
|
||||||
|
dependencies = [
|
||||||
|
"libsecp256k1-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsecp256k1-gen-genmult"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c"
|
||||||
|
dependencies = [
|
||||||
|
"libsecp256k1-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.17"
|
version = "0.4.17"
|
||||||
|
@ -218,6 +415,49 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multiaddr"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref",
|
||||||
|
"bs58",
|
||||||
|
"byteorder",
|
||||||
|
"data-encoding",
|
||||||
|
"multihash",
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"unsigned-varint",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multihash"
|
||||||
|
version = "0.16.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c346cf9999c631f002d8f977c4eaeaa0e6386f16007202308d0b3757522c2cc"
|
||||||
|
dependencies = [
|
||||||
|
"core2",
|
||||||
|
"multihash-derive",
|
||||||
|
"unsigned-varint",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multihash-derive"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"synstructure",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.1"
|
version = "7.1.1"
|
||||||
|
@ -234,6 +474,12 @@ version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.3.0"
|
version = "6.3.0"
|
||||||
|
@ -246,6 +492,53 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-crate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"thiserror",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.43"
|
version = "1.0.43"
|
||||||
|
@ -264,6 +557,36 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
@ -324,18 +647,43 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.9.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
"opaque-debug",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.100"
|
version = "1.0.100"
|
||||||
|
@ -347,6 +695,18 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "synstructure"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -362,16 +722,113 @@ version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsigned-varint"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "waku"
|
name = "waku"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"hex",
|
||||||
|
"libsecp256k1",
|
||||||
|
"multiaddr",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"waku-sys",
|
"waku-sys",
|
||||||
|
@ -384,6 +841,12 @@ dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
version = "4.3.0"
|
version = "4.3.0"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5b42c98780fe938ff79c54229aa80cdd47a17568
|
Subproject commit 2881d0cd5eb7b9083c9fa31d21cc066ef2ae1337
|
|
@ -6,6 +6,9 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
waku-sys = { path = "../waku-sys" }
|
hex = "0.4"
|
||||||
|
libsecp256k1 = "0.7"
|
||||||
|
multiaddr = "0.14"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
waku-sys = { path = "../waku-sys" }
|
||||||
|
|
|
@ -18,10 +18,10 @@ pub(crate) enum JsonResponse<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waku response, just a `Result` with an `String` error.
|
/// Waku response, just a `Result` with an `String` error.
|
||||||
/// Convenient we can transform a [`JsonResponse`] into a [`Response`] (`Result`)
|
/// Convenient we can transform a [`JsonResponse`] into a [`std::result::Result`]
|
||||||
type Response<T> = Result<T, String>;
|
pub type Result<T> = std::result::Result<T, String>;
|
||||||
|
|
||||||
impl<T> From<JsonResponse<T>> for Response<T> {
|
impl<T> From<JsonResponse<T>> for Result<T> {
|
||||||
fn from(response: JsonResponse<T>) -> Self {
|
fn from(response: JsonResponse<T>) -> Self {
|
||||||
match response {
|
match response {
|
||||||
JsonResponse::Result(t) => Ok(t),
|
JsonResponse::Result(t) => Ok(t),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod events;
|
mod events;
|
||||||
mod general;
|
mod general;
|
||||||
|
mod node_management;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// std
|
||||||
|
// crates
|
||||||
|
use libsecp256k1::SecretKey;
|
||||||
|
use multiaddr::Multiaddr;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
// internal
|
||||||
|
|
||||||
|
/// Waku node configuration
|
||||||
|
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct WakuNodeConfig {
|
||||||
|
/// Listening IP address. Default `0.0.0.0`
|
||||||
|
host: Option<std::net::IpAddr>,
|
||||||
|
/// Libp2p TCP listening port. Default `60000`. Use `0` for **random**
|
||||||
|
port: Option<usize>,
|
||||||
|
/// External address to advertise to other nodes. Can be ip4, ip6 or dns4, dns6.
|
||||||
|
/// If null, the multiaddress(es) generated from the ip and port specified in the config (or default ones) will be used.
|
||||||
|
/// Default: null
|
||||||
|
advertise_addr: Option<Multiaddr>,
|
||||||
|
/// Secp256k1 private key in Hex format (`0x123...abc`). Default random
|
||||||
|
#[serde(with = "secret_key_serde")]
|
||||||
|
node_key: Option<SecretKey>,
|
||||||
|
/// Interval in seconds for pinging peers to keep the connection alive. Default `20`
|
||||||
|
keep_alive_interval: Option<usize>,
|
||||||
|
/// Enable relay protocol. Default `true`
|
||||||
|
relay: Option<bool>,
|
||||||
|
/// The minimum number of peers required on a topic to allow broadcasting a message. Default `0`
|
||||||
|
min_peers_to_publish: Option<usize>,
|
||||||
|
/// Enable filter protocol. Default `false`
|
||||||
|
filter: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
mod secret_key_serde {
|
||||||
|
use libsecp256k1::SecretKey;
|
||||||
|
use serde::de::Error;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
pub fn serialize<S>(key: &Option<SecretKey>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let as_string: Option<String> = key.as_ref().map(|key| hex::encode(key.serialize()));
|
||||||
|
as_string.serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<SecretKey>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let as_string: Option<String> = Option::<String>::deserialize(deserializer)?;
|
||||||
|
match as_string {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(s) => {
|
||||||
|
let key_bytes = hex::decode(s).map_err(|e| D::Error::custom(format!("{e}")))?;
|
||||||
|
Ok(Some(
|
||||||
|
SecretKey::parse_slice(&key_bytes)
|
||||||
|
.map_err(|e| D::Error::custom(format!("{e}")))?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
mod config;
|
||||||
|
mod node;
|
||||||
|
|
||||||
|
// std
|
||||||
|
use multiaddr::Multiaddr;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
// crates
|
||||||
|
// internal
|
||||||
|
use crate::general::Result;
|
||||||
|
|
||||||
|
pub use config::WakuNodeConfig;
|
||||||
|
|
||||||
|
/// Shared flag to check if a waku node is already running in the current process
|
||||||
|
static WAKU_NODE_INITIALIZED: Mutex<bool> = Mutex::new(false);
|
||||||
|
|
||||||
|
/// Marker trait to disallow undesired waku node states in the handle
|
||||||
|
pub trait WakuNodeState {}
|
||||||
|
|
||||||
|
/// Waku node initialized state
|
||||||
|
pub struct Initialized;
|
||||||
|
|
||||||
|
/// Waku node running state
|
||||||
|
pub struct Running;
|
||||||
|
|
||||||
|
impl WakuNodeState for Initialized {}
|
||||||
|
impl WakuNodeState for Running {}
|
||||||
|
|
||||||
|
pub struct WakuNodeHandle<State: WakuNodeState>(PhantomData<State>);
|
||||||
|
|
||||||
|
impl<State: WakuNodeState> WakuNodeHandle<State> {
|
||||||
|
pub fn peer_id(&self) -> Result<String> {
|
||||||
|
node::waku_peer_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen_addresses(&self) -> Result<Vec<Multiaddr>> {
|
||||||
|
node::waku_listen_addressses()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn stop_node() -> Result<()> {
|
||||||
|
let mut node_initialized = WAKU_NODE_INITIALIZED
|
||||||
|
.lock()
|
||||||
|
.expect("Access to the mutex at some point");
|
||||||
|
*node_initialized = false;
|
||||||
|
node::waku_stop().map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WakuNodeHandle<Initialized> {
|
||||||
|
pub fn start(self) -> Result<WakuNodeHandle<Running>> {
|
||||||
|
node::waku_start().map(|_| WakuNodeHandle(Default::default()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(self) -> Result<()> {
|
||||||
|
stop_node()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WakuNodeHandle<Running> {
|
||||||
|
pub fn stop(self) -> Result<()> {
|
||||||
|
stop_node()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeHandle<Initialized>> {
|
||||||
|
let mut node_initialized = WAKU_NODE_INITIALIZED
|
||||||
|
.lock()
|
||||||
|
.expect("Access to the mutex at some point");
|
||||||
|
if *node_initialized {
|
||||||
|
return Err("Waku node is already initialized".into());
|
||||||
|
}
|
||||||
|
*node_initialized = true;
|
||||||
|
node::waku_new(config).map(|_| WakuNodeHandle(Default::default()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::waku_new;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exclusive_running() {
|
||||||
|
let handle1 = waku_new(None).unwrap();
|
||||||
|
let handle2 = waku_new(None);
|
||||||
|
assert!(handle2.is_err());
|
||||||
|
let stop_handle = handle1.start().unwrap();
|
||||||
|
stop_handle.stop().unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
// std
|
||||||
|
use multiaddr::Multiaddr;
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
// crates
|
||||||
|
// internal
|
||||||
|
use super::config::WakuNodeConfig;
|
||||||
|
use crate::general::{JsonResponse, Result};
|
||||||
|
|
||||||
|
/// Instantiates a Waku node
|
||||||
|
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_newchar-jsonconfig)
|
||||||
|
pub fn waku_new(config: Option<WakuNodeConfig>) -> Result<bool> {
|
||||||
|
let config = config.unwrap_or_default();
|
||||||
|
let s_config = serde_json::to_string(&config)
|
||||||
|
.expect("Serialization from properly built NodeConfig should never fail");
|
||||||
|
let result: &str = unsafe {
|
||||||
|
CStr::from_ptr(waku_sys::waku_new(
|
||||||
|
CString::new(s_config)
|
||||||
|
.expect("CString should build properly from the serialized node config")
|
||||||
|
.into_raw(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
.to_str()
|
||||||
|
.expect("Response should always succeed to load to a &str");
|
||||||
|
let json_response: JsonResponse<bool> =
|
||||||
|
serde_json::from_str(result).expect("JsonResponse should always succeed to deserialize");
|
||||||
|
json_response.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start a Waku node mounting all the protocols that were enabled during the Waku node instantiation.
|
||||||
|
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_start)
|
||||||
|
pub fn waku_start() -> Result<bool> {
|
||||||
|
let response = unsafe { CStr::from_ptr(waku_sys::waku_start()) }
|
||||||
|
.to_str()
|
||||||
|
.expect("Response should always succeed to load to a &str");
|
||||||
|
|
||||||
|
let json_response: JsonResponse<bool> =
|
||||||
|
serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize");
|
||||||
|
json_response.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stops a Waku node
|
||||||
|
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_stop)
|
||||||
|
pub fn waku_stop() -> Result<bool> {
|
||||||
|
let response = unsafe { CStr::from_ptr(waku_sys::waku_start()) }
|
||||||
|
.to_str()
|
||||||
|
.expect("Response should always succeed to load to a &str");
|
||||||
|
|
||||||
|
let json_response: JsonResponse<bool> =
|
||||||
|
serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize");
|
||||||
|
json_response.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the execution is successful, the result is the peer ID as a string (base58 encoded)
|
||||||
|
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_stop)
|
||||||
|
pub fn waku_peer_id() -> Result<String> {
|
||||||
|
let response = unsafe { CStr::from_ptr(waku_sys::waku_peerid()) }
|
||||||
|
.to_str()
|
||||||
|
.expect("Response should always succeed to load to a &str");
|
||||||
|
|
||||||
|
let json_response: JsonResponse<String> =
|
||||||
|
serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize");
|
||||||
|
|
||||||
|
json_response.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the multiaddresses the Waku node is listening to
|
||||||
|
/// as per [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_listen_addresses)
|
||||||
|
pub fn waku_listen_addressses() -> Result<Vec<Multiaddr>> {
|
||||||
|
let response = unsafe { CStr::from_ptr(waku_sys::waku_listen_addresses()) }
|
||||||
|
.to_str()
|
||||||
|
.expect("Response should always succeed to load to a &str");
|
||||||
|
|
||||||
|
let json_response: JsonResponse<Vec<Multiaddr>> =
|
||||||
|
serde_json::from_str(response).expect("JsonResponse should always succeed to deserialize");
|
||||||
|
|
||||||
|
json_response.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::waku_new;
|
||||||
|
use crate::node_management::node::{
|
||||||
|
waku_listen_addressses, waku_peer_id, waku_start, waku_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn waku_flow() {
|
||||||
|
waku_new(None).unwrap();
|
||||||
|
waku_start().unwrap();
|
||||||
|
// test peer id call, since we cannot start different instances of the node
|
||||||
|
let id = waku_peer_id().unwrap();
|
||||||
|
dbg!(&id);
|
||||||
|
assert!(!id.is_empty());
|
||||||
|
|
||||||
|
// test addresses, since we cannot start different instances of the node
|
||||||
|
let addresses = waku_listen_addressses().unwrap();
|
||||||
|
dbg!(&addresses);
|
||||||
|
assert!(!addresses.is_empty());
|
||||||
|
|
||||||
|
waku_stop().unwrap();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue