From d320e557010c27342a1f8a1705c3d8650b21f5ff Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Mon, 3 Oct 2022 15:21:19 +0200 Subject: [PATCH] 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 --- Cargo.lock | 463 +++++++++++++++++++++++++++++ waku-sys/vendor | 2 +- waku/Cargo.toml | 7 +- waku/src/general/mod.rs | 6 +- waku/src/lib.rs | 1 + waku/src/node_management/config.rs | 62 ++++ waku/src/node_management/mod.rs | 87 ++++++ waku/src/node_management/node.rs | 102 +++++++ 8 files changed, 724 insertions(+), 6 deletions(-) create mode 100644 waku/src/node_management/config.rs create mode 100644 waku/src/node_management/mod.rs create mode 100644 waku/src/node_management/node.rs diff --git a/Cargo.lock b/Cargo.lock index 60280c9..d680613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + [[package]] name = "atty" version = "0.2.14" @@ -28,6 +34,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bindgen" version = "0.60.1" @@ -57,6 +69,27 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "cexpr" version = "0.6.0" @@ -107,6 +140,55 @@ dependencies = [ "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]] name = "either" version = "1.8.0" @@ -126,6 +208,36 @@ dependencies = [ "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]] name = "glob" version = "0.3.0" @@ -147,12 +259,49 @@ dependencies = [ "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]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "indexmap" version = "1.9.1" @@ -197,6 +346,54 @@ dependencies = [ "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]] name = "log" version = "0.4.17" @@ -218,6 +415,49 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "nom" version = "7.1.1" @@ -234,6 +474,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "os_str_bytes" version = "6.3.0" @@ -246,6 +492,53 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "proc-macro2" version = "1.0.43" @@ -264,6 +557,36 @@ dependencies = [ "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]] name = "regex" version = "1.6.0" @@ -324,18 +647,43 @@ dependencies = [ "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]] name = "shlex" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.100" @@ -347,6 +695,18 @@ dependencies = [ "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]] name = "termcolor" version = "1.1.3" @@ -362,16 +722,113 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "unicode-ident" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "waku" version = "0.1.0" dependencies = [ + "hex", + "libsecp256k1", + "multiaddr", "serde", "serde_json", "waku-sys", @@ -384,6 +841,12 @@ dependencies = [ "bindgen", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "which" version = "4.3.0" diff --git a/waku-sys/vendor b/waku-sys/vendor index 5b42c98..2881d0c 160000 --- a/waku-sys/vendor +++ b/waku-sys/vendor @@ -1 +1 @@ -Subproject commit 5b42c98780fe938ff79c54229aa80cdd47a17568 +Subproject commit 2881d0cd5eb7b9083c9fa31d21cc066ef2ae1337 diff --git a/waku/Cargo.toml b/waku/Cargo.toml index 341bf33..8acbf30 100644 --- a/waku/Cargo.toml +++ b/waku/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -waku-sys = { path = "../waku-sys" } +hex = "0.4" +libsecp256k1 = "0.7" +multiaddr = "0.14" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" \ No newline at end of file +serde_json = "1.0" +waku-sys = { path = "../waku-sys" } diff --git a/waku/src/general/mod.rs b/waku/src/general/mod.rs index edf2a50..43e1b27 100644 --- a/waku/src/general/mod.rs +++ b/waku/src/general/mod.rs @@ -18,10 +18,10 @@ pub(crate) enum JsonResponse { } /// Waku response, just a `Result` with an `String` error. -/// Convenient we can transform a [`JsonResponse`] into a [`Response`] (`Result`) -type Response = Result; +/// Convenient we can transform a [`JsonResponse`] into a [`std::result::Result`] +pub type Result = std::result::Result; -impl From> for Response { +impl From> for Result { fn from(response: JsonResponse) -> Self { match response { JsonResponse::Result(t) => Ok(t), diff --git a/waku/src/lib.rs b/waku/src/lib.rs index 3a1615a..95aa506 100644 --- a/waku/src/lib.rs +++ b/waku/src/lib.rs @@ -1,5 +1,6 @@ mod events; mod general; +mod node_management; #[cfg(test)] mod tests { diff --git a/waku/src/node_management/config.rs b/waku/src/node_management/config.rs new file mode 100644 index 0000000..4f8db6c --- /dev/null +++ b/waku/src/node_management/config.rs @@ -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, + /// Libp2p TCP listening port. Default `60000`. Use `0` for **random** + port: Option, + /// 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, + /// Secp256k1 private key in Hex format (`0x123...abc`). Default random + #[serde(with = "secret_key_serde")] + node_key: Option, + /// Interval in seconds for pinging peers to keep the connection alive. Default `20` + keep_alive_interval: Option, + /// Enable relay protocol. Default `true` + relay: Option, + /// The minimum number of peers required on a topic to allow broadcasting a message. Default `0` + min_peers_to_publish: Option, + /// Enable filter protocol. Default `false` + filter: Option, +} + +mod secret_key_serde { + use libsecp256k1::SecretKey; + use serde::de::Error; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(key: &Option, serializer: S) -> Result + where + S: Serializer, + { + let as_string: Option = key.as_ref().map(|key| hex::encode(key.serialize())); + as_string.serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let as_string: Option = Option::::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}")))?, + )) + } + } + } +} diff --git a/waku/src/node_management/mod.rs b/waku/src/node_management/mod.rs new file mode 100644 index 0000000..c19d941 --- /dev/null +++ b/waku/src/node_management/mod.rs @@ -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 = 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(PhantomData); + +impl WakuNodeHandle { + pub fn peer_id(&self) -> Result { + node::waku_peer_id() + } + + pub fn listen_addresses(&self) -> Result> { + 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 { + pub fn start(self) -> Result> { + node::waku_start().map(|_| WakuNodeHandle(Default::default())) + } + + pub fn stop(self) -> Result<()> { + stop_node() + } +} + +impl WakuNodeHandle { + pub fn stop(self) -> Result<()> { + stop_node() + } +} + +pub fn waku_new(config: Option) -> Result> { + 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(); + } +} diff --git a/waku/src/node_management/node.rs b/waku/src/node_management/node.rs new file mode 100644 index 0000000..5f02897 --- /dev/null +++ b/waku/src/node_management/node.rs @@ -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) -> Result { + 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 = + 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 { + 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 = + 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 { + 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 = + 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 { + 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 = + 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> { + 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> = + 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(); + } +}