diff --git a/Cargo.lock b/Cargo.lock index fdcb2707b948b3aff4a9c16de31eeba7c39cb7c5..8671f8c1da6e24ee007f6a0567839a0dd3281d2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,23 +58,6 @@ name = "base58" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "base64" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.9.1" @@ -152,23 +135,6 @@ dependencies = [ "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "core-foundation" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -178,15 +144,6 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-deque" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-epoch" version = "0.3.1" @@ -201,19 +158,6 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-epoch" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-utils" version = "0.2.2" @@ -222,14 +166,6 @@ dependencies = [ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-utils" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dtoa" version = "0.4.2" @@ -428,7 +364,7 @@ dependencies = [ "serde_derive 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)", - "websocket 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -491,11 +427,6 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "futures" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "gcc" version = "0.3.54" @@ -506,24 +437,6 @@ name = "httparse" version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "hyper" -version = "0.10.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "idna" version = "0.1.4" @@ -557,16 +470,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "1.0.0" @@ -587,14 +490,6 @@ name = "linked-hash-map" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.4.1" @@ -621,14 +516,6 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mio" version = "0.6.14" @@ -658,20 +545,6 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "native-tls" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "net2" version = "0.2.32" @@ -868,14 +741,6 @@ dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rust-crypto" version = "0.2.36" @@ -914,45 +779,11 @@ name = "safemem" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "schannel" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scoped-tls" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "security-framework" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "security-framework-sys" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde" version = "1.0.57" @@ -980,7 +811,7 @@ dependencies = [ [[package]] name = "sha1" -version = "0.2.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -993,6 +824,11 @@ dependencies = [ "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "slab" version = "0.4.0" @@ -1067,15 +903,6 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term" version = "0.5.1" @@ -1130,164 +957,11 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-core" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-io" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-tls" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "ucd-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicode-bidi" version = "0.3.4" @@ -1349,37 +1023,11 @@ name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "version_check" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "websocket" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" version = "0.2.8" @@ -1409,6 +1057,23 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ws" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1431,8 +1096,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum backtrace 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbdd17cd962b570302f5297aea8648d5923e22e555c2ed2d8b2e34eca646bf6d" "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" -"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9263aa6a38da271eec5c91a83ce1e800f093c8535788d403d626d8d5c3f8f007" "checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" @@ -1443,14 +1106,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" -"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4e2817eb773f770dcb294127c011e22771899c21d18fce7dd739c0b9832e81" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" @@ -1459,29 +1117,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" -"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45" @@ -1505,22 +1156,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustbreak 2.0.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)" = "676cb04876f4391d5d2f2c9029d10cfe5fe28ad625ad8460531bed1191477083" "checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" -"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" "checksum serde 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "9478f147957b713a156ce5e4529d77275bbcfddc29563b794939b36230df8ca8" "checksum serde_derive 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "1bdba9c305f1aeff7e83e2ff0685a141780de943cee66bdd89b63913b2b69c86" "checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1" -"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" +"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9cc12b39fdf4c9a07f88bffac2d628f0118ed5ac077a4b0feece61fadf1429e5" +"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d7b10278336e7fd9dc259399a0f9ff419616738b6a841b136c362e16db626" "checksum sqlite3-src 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "46e0bc115b563b1ee6c665ef895b56bf488522f57d1c6571887547c57c8f5a88" @@ -1530,28 +1177,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.13.10 (registry+https://github.com/rust-lang/crates.io-index)" = "77961dcdac942fa8bc033c16f3a790b311c8a27d00811b878ebd8cf9b7ba39d5" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ee337e5f4e501fc32966fec6fe0ca0cc1c237b0b1b14a335f8bfe3c5f06e286" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" -"checksum tokio-fs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76766830bbf9a2d5bfb50c95350d56a2e79e2c80f675967fff448bc615899708" -"checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" -"checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b" -"checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" -"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d" -"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9" -"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" -"checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" @@ -1562,13 +1194,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum websocket 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eb277e7f4c23dc49176f74ae200e77651764efb2c25f56ad2d22623b63826369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ccf752fee5350ca505fdb0b34d503b17d1528bd867561b7aa91d6ea750d5e972" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/Cargo.toml b/Cargo.toml index d718f4841291111a7ce8bbedf80889222c7c0a59..3eecdcaed45e67aa65b3fbca4941d536e73be393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,16 +7,16 @@ license = "AGPL-3.0" [dependencies] duniter-core = { path = "./core" } -duniter-tui = { path = "./tui" } -duniter-ws2p = { path = "./ws2p", optional = true } +duniter-tui = { path = "./tui", optional = true } +duniter-ws2p = { path = "./ws2p" } [features] -default = ["ws2p"] -ws2p = ["duniter-ws2p"] +default = ["tui","ssl"] +ssl = ["duniter-ws2p/ssl"] +tui = ["duniter-tui"] # Treat warnings as a build error. strict = [] - [workspace] members = [ "blockchain", diff --git a/src/main.rs b/src/main.rs index d8e7d606e6bacb619f58c9ba45988f829ec32c46..938abebfb094f4ad0d98440ec975644e4859872f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,13 +23,13 @@ )] extern crate duniter_core; +#[cfg(feature = "tui")] extern crate duniter_tui; -#[cfg(feature = "ws2p")] extern crate duniter_ws2p; pub use duniter_core::DuniterCore; +#[cfg(feature = "tui")] pub use duniter_tui::TuiModule; -#[cfg(feature = "ws2p")] pub use duniter_ws2p::WS2PModule; /// Main function @@ -45,16 +45,16 @@ fn main() { //duniter_core.plug::<GvaModule>(); //duniter_core.plug::<PoolModule>(); //duniter_core.plug::<PowModule>(); - duniter_core.plug::<TuiModule>(); - plug_ws2p_module(&mut duniter_core); + plug_tui_module(&mut duniter_core); + duniter_core.plug::<WS2PModule>(); duniter_core.start_blockchain(); }; } -/// Plug WS2P Module -#[cfg(feature = "ws2p")] -fn plug_ws2p_module(duniter_core: &mut DuniterCore) { - duniter_core.plug::<WS2PModule>(); +/// Plug TUI Module +#[cfg(feature = "tui")] +fn plug_tui_module(duniter_core: &mut DuniterCore) { + duniter_core.plug::<TuiModule>(); } -#[cfg(not(feature = "ws2p"))] -fn plug_ws2p_module(_duniter_core: &mut DuniterCore) {} +#[cfg(not(feature = "tui"))] +fn plug_tui_module(_duniter_core: &mut DuniterCore) {} diff --git a/ws2p/Cargo.toml b/ws2p/Cargo.toml index 955f268c5a60cc526dfc1280b56fd190bb860d51..89e831f711682a8f1323dee5eb20e6f7620a9ef8 100644 --- a/ws2p/Cargo.toml +++ b/ws2p/Cargo.toml @@ -26,8 +26,9 @@ sqlite = "0.23.9" serde = "1.0.24" serde_derive = "1.0.24" serde_json = "1.0.9" -websocket = "0.20.2" +ws = "0.7.6" [features] +ssl = ["ws/ssl"] # Treat warnings as a build error. strict = [] \ No newline at end of file diff --git a/ws2p/constants.rs b/ws2p/constants.rs index 7d33b80de435b96c4fc4d93a3c79637aa932b5c7..bc8844462cb4e4e94db783f0ce47d604b17d3c69 100644 --- a/ws2p/constants.rs +++ b/ws2p/constants.rs @@ -13,9 +13,9 @@ pub static WS2P_OUTCOMING_INTERVAL: &'static u64 = &300; pub static WS2P_DEFAULT_OUTCOMING_QUOTA: &'static usize = &10; pub static WS2P_NEGOTIATION_TIMEOUT: &'static u64 = &15; //pub static WS2P_REQUEST_TIMEOUT : &'static u64 = &30; -pub static WS2P_CONNECTION_TIMEOUT: &'static u64 = &120; +pub static WS2P_EXPIRE_TIMEOUT: &'static u64 = &120; pub static WS2P_SPAM_INTERVAL_IN_MILLI_SECS: &'static u64 = &80; -pub static WS2P_SPAM_LIMIT: &'static u64 = &6; +pub static WS2P_SPAM_LIMIT: &'static usize = &6; pub static WS2P_SPAM_SLEEP_TIME_IN_SEC: &'static u64 = &100; pub static DURATION_BEFORE_RECORDING_ENDPOINT: &'static u64 = &180; pub static BLOCKS_REQUEST_INTERVAL: &'static u64 = &60; diff --git a/ws2p/datas.rs b/ws2p/datas.rs new file mode 100644 index 0000000000000000000000000000000000000000..c9341419c3cf86284262d715736b06c6410bc96f --- /dev/null +++ b/ws2p/datas.rs @@ -0,0 +1,576 @@ +// Copyright (C) 2018 The Duniter Project Developers. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +use constants::*; +use duniter_crypto::keys::*; +use duniter_dal::dal_requests::DALRequest; +use duniter_documents::Blockstamp; +use duniter_message::DuniterMessage; +use duniter_network::network_endpoint::*; +use duniter_network::network_head::*; +use duniter_network::*; +use std::sync::mpsc; +use *; + +#[derive(Debug)] +pub struct WS2PModuleDatas { + pub followers: Vec<mpsc::Sender<DuniterMessage>>, + pub currency: Option<String>, + pub key_pair: Option<KeyPairEnum>, + pub conf: Option<WS2PConf>, + pub main_thread_channel: ( + mpsc::Sender<WS2PThreadSignal>, + mpsc::Receiver<WS2PThreadSignal>, + ), + pub ws2p_endpoints: HashMap<NodeFullId, (NetworkEndpoint, WS2PConnectionState)>, + pub websockets: HashMap<NodeFullId, WsSender>, + pub requests_awaiting_response: HashMap<ModuleReqId, (NetworkRequest, NodeFullId, SystemTime)>, + pub heads_cache: HashMap<NodeFullId, NetworkHead>, + pub my_head: Option<NetworkHead>, + pub uids_cache: HashMap<PubKey, String>, +} + +impl WS2PModuleDatas { + pub fn open_db(db_path: &PathBuf) -> Result<sqlite::Connection, sqlite::Error> { + let conn: sqlite::Connection; + if !db_path.as_path().exists() { + conn = sqlite::open(db_path.as_path())?; + conn.execute( + "CREATE TABLE endpoints (hash_full_id TEXT, status INTEGER, node_id INTEGER, pubkey TEXT, + api INTEGER, version INTEGER, endpoint TEXT, last_check INTEGER);", + )?; + } else { + conn = sqlite::open(db_path.as_path())?; + } + Ok(conn) + } + pub fn parse_ws2p_conf( + duniter_conf: &DuniterConf, + ws2p_json_conf: &serde_json::Value, + ) -> WS2PConf { + let mut sync_endpoints = Vec::new(); + match ws2p_json_conf.get("sync_peers") { + Some(peers) => { + let array_peers = peers.as_array().expect("Conf: Fail to parse conf file !"); + for peer in array_peers { + let pubkey = match peer.get("pubkey") { + Some(pubkey) => PubKey::Ed25519( + ed25519::PublicKey::from_base58( + pubkey + .as_str() + .expect("WS2PConf Error : fail to parse sync endpoint pubkey"), + ).expect("WS2PConf Error : fail to parse sync endpoint pubkey"), + ), + None => panic!( + "Fail to load ws2p conf : \ + WrongFormat : not found pubkey field !" + ), + }; + match peer.get("ws2p_endpoints") { + Some(endpoints) => { + let array_endpoints = endpoints + .as_array() + .expect("Conf: Fail to parse conf file !"); + for endpoint in array_endpoints { + sync_endpoints.push( + NetworkEndpoint::parse_from_raw( + endpoint.as_str().expect("WS2P: Fail to get ep.as_str() !"), + pubkey, + 0, + 0, + ).expect(&format!( + "WS2PConf Error : fail to parse sync Endpoint = {:?}", + endpoint.as_str().expect("WS2P: Fail to get ep.as_str() !") + )), + ); + } + } + None => panic!( + "Fail to load conf : \ + WrongFormat : not found ws2p_endpoints field !" + ), + }; + } + } + None => panic!( + "Configuration Error : \ + You must declare at least one node on which to synchronize !" + ), + }; + WS2PConf { + outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA, + node_id: NodeUUID(duniter_conf.my_node_id()), + sync_endpoints, + } + } + pub fn send_dal_request(&self, req: &DALRequest) { + for follower in &self.followers { + if follower + .send(DuniterMessage::DALRequest(req.clone())) + .is_err() + { + // handle error + } + } + } + pub fn send_network_event(&self, event: &NetworkEvent) { + for follower in &self.followers { + match follower.send(DuniterMessage::NetworkEvent(event.clone())) { + Ok(_) => { + debug!("Send NetworkEvent to one follower."); + } + Err(_) => { + warn!("Fail to send NetworkEvent to one follower !"); + } + } + } + } + pub fn get_network_consensus(&self) -> Result<Blockstamp, NetworkConsensusError> { + let mut count_known_blockstamps = 0; + let mut farthest_blockstamp = Blockstamp::default(); + let mut blockstamps_occurences: HashMap<Blockstamp, usize> = + HashMap::with_capacity(*WS2P_DEFAULT_OUTCOMING_QUOTA); + let mut dominant_blockstamp = Blockstamp::default(); + let mut dominant_blockstamp_occurences = 0; + for (_ws2p_full_id, head) in self.heads_cache.clone() { + count_known_blockstamps += 1; + let blockstamps_occurences_copy = blockstamps_occurences.clone(); + match blockstamps_occurences_copy.get(&head.blockstamp()) { + Some(occurences) => { + let mut occurences_mut = blockstamps_occurences + .get_mut(&head.blockstamp()) + .expect("WS2P: Fail to get_mut blockstamps_occurences !"); + *occurences_mut += 1; + if *occurences > dominant_blockstamp_occurences { + dominant_blockstamp_occurences = *occurences; + dominant_blockstamp = head.blockstamp(); + } + } + None => { + blockstamps_occurences.insert(head.blockstamp(), 0); + } + } + if head.blockstamp().id.0 > farthest_blockstamp.id.0 { + farthest_blockstamp = head.blockstamp(); + } + } + if count_known_blockstamps < 5 { + return Err(NetworkConsensusError::InsufficientData( + count_known_blockstamps, + )); + } else if farthest_blockstamp == dominant_blockstamp { + return Ok(dominant_blockstamp); + } + Err(NetworkConsensusError::Fork()) + } + fn count_established_connections(&self) -> usize { + let mut count_established_connections = 0; + for (_ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() { + if let WS2PConnectionState::Established = state { + count_established_connections += 1; + } + } + count_established_connections + } + pub fn connect_to_know_endpoints(&mut self) -> () { + info!("WS2P: connect to know endpoints..."); + let mut count_established_connections = 0; + let mut reachable_endpoints = Vec::new(); + let mut unreachable_endpoints = Vec::new(); + for (_ws2p_full_id, (ep, state)) in self.ws2p_endpoints.clone() { + match state { + WS2PConnectionState::Established => count_established_connections += 1, + WS2PConnectionState::NeverTry + | WS2PConnectionState::Close + | WS2PConnectionState::Denial => reachable_endpoints.push(ep), + _ => unreachable_endpoints.push(ep), + } + } + let mut free_outcoming_rooms = self + .conf + .clone() + .expect("WS2P: Fail to get conf !") + .outcoming_quota - count_established_connections; + while free_outcoming_rooms > 0 { + let ep = if !reachable_endpoints.is_empty() { + reachable_endpoints + .pop() + .expect("WS2P: Fail to pop() reachable_endpoints !") + } else if !unreachable_endpoints.is_empty() { + unreachable_endpoints + .pop() + .expect("WS2P: Fail to pop() unreachable_endpoints !") + } else { + break; + }; + if cfg!(feature = "ssl") || ep.port() != 443 { + self.connect_to_without_checking_quotas(&ep); + free_outcoming_rooms -= 1; + } + } + } + pub fn connect_to(&mut self, endpoint: &NetworkEndpoint) -> () { + // Add endpoint to endpoints list (if there isn't already) + match self.ws2p_endpoints.get( + &endpoint + .node_full_id() + .expect("WS2P: Fail to get ep.node_full_id() !"), + ) { + Some(_) => { + self.ws2p_endpoints + .get_mut( + &endpoint + .node_full_id() + .expect("WS2P: Fail to get ep.node_full_id() !"), + ) + .expect("WS2P: Fail to get_mut() a ws2p_endpoint !") + .1 = WS2PConnectionState::NeverTry; + } + None => { + self.ws2p_endpoints.insert( + endpoint + .node_full_id() + .expect("WS2P: Fail to get ep.node_full_id() !"), + (endpoint.clone(), WS2PConnectionState::NeverTry), + ); + } + }; + if self + .conf + .clone() + .expect("WS2P: Fail to get conf !") + .outcoming_quota > self.count_established_connections() + { + self.connect_to_without_checking_quotas(&endpoint); + } + } + fn close_connection(&mut self, ws2p_full_id: &NodeFullId, reason: WS2PCloseConnectionReason) { + match reason { + WS2PCloseConnectionReason::NegociationTimeout => {} + WS2PCloseConnectionReason::AuthMessInvalidSig + | WS2PCloseConnectionReason::Timeout + | WS2PCloseConnectionReason::Unknow => { + self.ws2p_endpoints + .get_mut(ws2p_full_id) + .expect("Failure : attempt to delete a non-existent connection !") + .1 = WS2PConnectionState::Close + } + } + let _result = self + .websockets + .get(&ws2p_full_id) + .expect("Try to close an unexistant websocket !") + .0 + .close(ws::CloseCode::Normal); + self.websockets.remove(ws2p_full_id).expect(&format!( + "Fatal error : no websocket for {} !", + ws2p_full_id + ));; + } + pub fn ws2p_conn_message_pretreatment(&mut self, message: WS2PConnectionMessage) -> WS2PSignal { + let ws2p_full_id = message.0; + match message.1 { + WS2PConnectionMessagePayload::WrongUrl + | WS2PConnectionMessagePayload::FailOpenWS + | WS2PConnectionMessagePayload::FailToSplitWS => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = WS2PConnectionState::WSError; + return WS2PSignal::WSError(ws2p_full_id); + } + WS2PConnectionMessagePayload::TryToSendConnectMess => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = WS2PConnectionState::TryToSendConnectMess; + } + WS2PConnectionMessagePayload::FailSendConnectMess => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to mut ep !") + .1 = WS2PConnectionState::Unreachable; + } + WS2PConnectionMessagePayload::WebsocketOk(sender) => { + self.websockets.insert(ws2p_full_id, sender); + } + WS2PConnectionMessagePayload::ValidConnectMessage(response, new_con_state) => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = new_con_state; + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("Endpoint don't exist !") + .1 = WS2PConnectionState::ConnectMessOk; + debug!("Send: {:#?}", response); + self.websockets + .get_mut(&ws2p_full_id) + .expect(&format!( + "Fatal error : no websocket for {} !", + ws2p_full_id + )) + .0 + .send(Message::text(response)) + .expect("WS2P: Fail to send OK Message !"); + } + WS2PConnectionMessagePayload::ValidAckMessage(r, new_con_state) => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = new_con_state; + if let WS2PConnectionState::AckMessOk = self.ws2p_endpoints[&ws2p_full_id].1 { + trace!("DEBUG : Send: {:#?}", r); + self.websockets + .get_mut(&ws2p_full_id) + .expect(&format!( + "Fatal error : no websocket for {} !", + ws2p_full_id + )) + .0 + .send(Message::text(r)) + .expect("WS2P: Fail to send Message in websocket !"); + } + } + WS2PConnectionMessagePayload::ValidOk(new_con_state) => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = new_con_state; + match self.ws2p_endpoints[&ws2p_full_id].1 { + WS2PConnectionState::OkMessOkWaitingAckMess => {} + WS2PConnectionState::Established => { + return WS2PSignal::ConnectionEstablished(ws2p_full_id) + } + _ => { + self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::Unknow); + return WS2PSignal::Empty; + } + } + } + WS2PConnectionMessagePayload::DalRequest(req_id, req_body) => { + return WS2PSignal::DalRequest(ws2p_full_id, req_id, req_body); + } + WS2PConnectionMessagePayload::PeerCard(body, ws2p_endpoints) => { + return WS2PSignal::PeerCard(ws2p_full_id, body, ws2p_endpoints); + } + WS2PConnectionMessagePayload::Heads(heads) => { + let mut applied_heads = Vec::with_capacity(heads.len()); + for head in heads { + if let Some(head) = NetworkHead::from_json_value(&head) { + if head.verify() + && (self.my_head.is_none() + || head.node_full_id() + != self + .my_head + .clone() + .expect("WS2P: Fail to clone my_head") + .node_full_id()) + && head.apply(&mut self.heads_cache) + { + applied_heads.push(head); + } + } + } + return WS2PSignal::Heads(ws2p_full_id, applied_heads); + } + WS2PConnectionMessagePayload::Document(network_doc) => { + return WS2PSignal::Document(ws2p_full_id, network_doc); + } + WS2PConnectionMessagePayload::ReqResponse(req_id, response) => { + if self.requests_awaiting_response.len() > req_id.0 as usize { + if let Some((ref ws2p_request, ref recipient_fulld_id, ref _timestamp)) = + self.requests_awaiting_response.remove(&req_id) + { + return WS2PSignal::ReqResponse( + req_id, + *ws2p_request, + *recipient_fulld_id, + response, + ); + } + } + } + WS2PConnectionMessagePayload::NegociationTimeout => { + match self.ws2p_endpoints[&ws2p_full_id].1 { + WS2PConnectionState::AckMessOk | WS2PConnectionState::ConnectMessOk => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = WS2PConnectionState::Denial + } + WS2PConnectionState::WaitingConnectMess => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = WS2PConnectionState::NoResponse + } + _ => { + self.ws2p_endpoints + .get_mut(&ws2p_full_id) + .expect("WS2P: Fail to get mut ep !") + .1 = WS2PConnectionState::Unreachable + } + } + self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::NegociationTimeout); + return WS2PSignal::NegociationTimeout(ws2p_full_id); + } + WS2PConnectionMessagePayload::Timeout => { + self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::Timeout); + return WS2PSignal::Timeout(ws2p_full_id); + } + WS2PConnectionMessagePayload::UnknowMessage => { + warn!("WS2P : Receive Unknow Message from {}.", &ws2p_full_id.1) + } + WS2PConnectionMessagePayload::WrongFormatMessage => warn!( + "WS2P : Receive Wrong Format Message from {}.", + &ws2p_full_id.1 + ), + WS2PConnectionMessagePayload::InvalidMessage => return WS2PSignal::Empty, + WS2PConnectionMessagePayload::Close => { + if self.websockets.contains_key(&ws2p_full_id) { + self.close_connection( + &ws2p_full_id, + WS2PCloseConnectionReason::AuthMessInvalidSig, + ) + } + } + } + let connections_count = self.websockets.len(); + if connections_count == 0 { + return WS2PSignal::NoConnection; + } + // Detect timeout requests + let mut requests_timeout = Vec::new(); + for &(ref req, ref _ws2p_full_id, ref timestamp) in + self.requests_awaiting_response.clone().values() + { + if SystemTime::now().duration_since(*timestamp).unwrap() > Duration::new(20, 0) { + requests_timeout.push(req.get_req_full_id()); + warn!("request timeout : {:?}", req); + } + } + // Delete (and resend) timeout requests + for req_id in requests_timeout { + //let ws2p_endpoints = self.ws2p_endpoints.clone(); + let _request_option = self.requests_awaiting_response.remove(&req_id.1); + /*if let Some((request, _, _)) = request_option { + let _request_result = self.send_request_to_specific_node( + &get_random_connection(&ws2p_endpoints), + &request, + ); + }*/ + } + WS2PSignal::Empty + } + + /*pub fn send_request_to_all_connections( + &mut self, + ws2p_request: &NetworkRequest, + ) -> Result<(), SendRequestError> { + let mut count_successful_sending: usize = 0; + let mut errors: Vec<ws::Error> = Vec::new(); + match *ws2p_request { + NetworkRequest::GetCurrent(req_full_id, _receiver) => { + for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() { + if let WS2PConnectionState::Established = state { + let ws2p_request = NetworkRequest::GetCurrent( + ModuleReqFullId( + req_full_id.0, + ModuleReqId( + (self.requests_awaiting_response.len() + + count_successful_sending) + as u32, + ), + ), + ws2p_full_id, + ); + match self.send_request_to_specific_node(&ws2p_full_id, &ws2p_request) { + Ok(_) => count_successful_sending += 1, + Err(e) => errors.push(e), + }; + } + } + } + /* NetworkRequest::GetBlock(req_full_id, number) => {} */ + NetworkRequest::GetBlocks(_req_full_id, _receiver, _count, _from_number) => {} + NetworkRequest::GetRequirementsPending(req_full_id, _receiver, min_cert) => { + for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() { + if let WS2PConnectionState::Established = state { + let ws2p_request = NetworkRequest::GetRequirementsPending( + ModuleReqFullId( + req_full_id.0, + ModuleReqId(self.requests_awaiting_response.len() as u32), + ), + ws2p_full_id, + min_cert, + ); + match self.send_request_to_specific_node(&ws2p_full_id, &ws2p_request) { + Ok(_) => count_successful_sending += 1, + Err(e) => errors.push(e), + }; + } + } + } + _ => { + return Err(SendRequestError::RequestTypeMustNotBeTransmitted()); + } + } + debug!("count_successful_sending = {}", count_successful_sending); + if !errors.is_empty() { + return Err(SendRequestError::WSError(count_successful_sending, errors)); + } + Ok(()) + }*/ + + pub fn send_request_to_specific_node( + &mut self, + receiver_ws2p_full_id: &NodeFullId, + ws2p_request: &NetworkRequest, + ) -> ws::Result<()> { + self.websockets + .get_mut(receiver_ws2p_full_id) + .expect("WS2P: Fail to get mut websocket !") + .0 + .send(Message::text( + network_request_to_json(ws2p_request).to_string(), + ))?; + self.requests_awaiting_response.insert( + ws2p_request.get_req_id(), + (*ws2p_request, *receiver_ws2p_full_id, SystemTime::now()), + ); + debug!( + "send request {} to {}", + network_request_to_json(ws2p_request).to_string(), + receiver_ws2p_full_id + ); + Ok(()) + } + + fn connect_to_without_checking_quotas(&mut self, endpoint: &NetworkEndpoint) { + let endpoint_copy = endpoint.clone(); + let conductor_sender_copy = self.main_thread_channel.0.clone(); + let currency_copy = self.currency.clone(); + let key_pair_copy = self.key_pair; + thread::spawn(move || { + let _result = connect_to_ws2p_endpoint( + &endpoint_copy, + &conductor_sender_copy, + ¤cy_copy.expect("WS2PError : No currency !"), + key_pair_copy.expect("WS2PError : No key_pair !"), + ); + }); + } +} diff --git a/ws2p/heads.rs b/ws2p/heads.rs new file mode 100644 index 0000000000000000000000000000000000000000..1ed46725874a89d572587b7aa101e0072a3a05a7 --- /dev/null +++ b/ws2p/heads.rs @@ -0,0 +1,64 @@ +// Copyright (C) 2018 The Duniter Project Developers. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +use duniter_documents::Blockstamp; +use duniter_network::network_head::*; +use *; + +pub fn generate_my_head( + network_keypair: &KeyPairEnum, + conf: &WS2PConf, + soft_name: &str, + soft_version: &str, + my_current_blockstamp: &Blockstamp, + my_uid: Option<String>, +) -> NetworkHead { + let message = NetworkHeadMessage::V2(NetworkHeadMessageV2 { + api: String::from("WS2POCA"), + version: 1, + pubkey: network_keypair.public_key(), + blockstamp: *my_current_blockstamp, + node_uuid: conf.node_id, + software: String::from(soft_name), + soft_version: String::from(soft_version), + prefix: 1, + free_member_room: None, + free_mirror_room: None, + }); + let message_v2 = NetworkHeadMessage::V2(NetworkHeadMessageV2 { + api: String::from("WS2POCA"), + version: 2, + pubkey: network_keypair.public_key(), + blockstamp: *my_current_blockstamp, + node_uuid: conf.node_id, + software: String::from(soft_name), + soft_version: String::from(soft_version), + prefix: 1, + free_member_room: Some(0), + free_mirror_room: Some(0), + }); + NetworkHead::V2(Box::new(NetworkHeadV2 { + message: message.clone(), + sig: network_keypair + .private_key() + .sign(message.to_string().as_bytes()), + message_v2: message_v2.clone(), + sig_v2: network_keypair + .private_key() + .sign(message_v2.to_string().as_bytes()), + step: 0, + uid: my_uid, + })) +} diff --git a/ws2p/lib.rs b/ws2p/lib.rs index dc696d57c50c293ba687b5496891f207b75c016a..035c2fc40ecbe836d33f1dce55697d6f97d0e931 100644 --- a/ws2p/lib.rs +++ b/ws2p/lib.rs @@ -41,31 +41,13 @@ extern crate duniter_module; extern crate duniter_network; extern crate rand; extern crate sqlite; -extern crate websocket; - -use std::collections::HashMap; -use std::ops::Deref; -use std::path::PathBuf; -use std::str::from_utf8; -use std::sync::mpsc; -use std::thread; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use duniter_crypto::keys::*; -use duniter_dal::dal_event::DALEvent; -use duniter_dal::dal_requests::{DALReqBlockchain, DALRequest, DALResBlockchain, DALResponse}; -use duniter_documents::Blockstamp; -use duniter_message::DuniterMessage; -use duniter_module::*; -use duniter_network::network_endpoint::*; -use duniter_network::network_head::*; -use duniter_network::*; -use parsers::blocks::parse_json_block; -use websocket::{ClientBuilder, Message}; +extern crate ws; mod ack_message; mod connect_message; pub mod constants; +mod datas; +mod heads; mod ok_message; pub mod parsers; pub mod serializer; @@ -76,26 +58,45 @@ pub mod ws2p_requests; use ack_message::WS2PAckMessageV1; use connect_message::WS2PConnectMessageV1; use constants::*; +use datas::*; +use duniter_crypto::keys::*; +use duniter_dal::dal_event::DALEvent; +use duniter_dal::dal_requests::{DALReqBlockchain, DALRequest, DALResBlockchain, DALResponse}; +use duniter_documents::Blockstamp; +use duniter_message::DuniterMessage; +use duniter_module::*; +use duniter_network::network_endpoint::*; +use duniter_network::network_head::*; +use duniter_network::*; use ok_message::WS2POkMessageV1; -use rand::Rng; +use parsers::blocks::parse_json_block; +use std::collections::HashMap; +use std::ops::Deref; +use std::path::PathBuf; +use std::sync::mpsc; +use std::thread; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use ws::Message; use ws2p_connection::*; use ws2p_requests::network_request_to_json; #[derive(Debug, Clone, PartialEq, Eq, Hash)] +/// WS2P Configuration pub struct WS2PConf { + /// Node unique identifier pub node_id: NodeUUID, + /// Limit of outcoming connections pub outcoming_quota: usize, + /// Default WS2P endpoints provides by configuration file pub sync_endpoints: Vec<NetworkEndpoint>, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum WS2PConfParseError { - UnknowError(), -} - #[derive(Debug)] +/// Store a Signal receive from network (after message treatment) pub enum WS2PSignal { + /// Receive a websocket error from a connextion. `NodeFullId` store the identifier of connection. WSError(NodeFullId), + /// A new connection is successfully established with `NodeFullId`. ConnectionEstablished(NodeFullId), NegociationTimeout(NodeFullId), Timeout(NodeFullId), @@ -117,32 +118,12 @@ pub enum NetworkConsensusError { #[derive(Debug)] pub enum SendRequestError { RequestTypeMustNotBeTransmitted(), - WSError(usize, Vec<websocket::WebSocketError>), + WSError(usize, Vec<ws::Error>), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct WS2PModule {} -#[derive(Debug)] -pub struct WS2PModuleDatas { - pub followers: Vec<mpsc::Sender<DuniterMessage>>, - pub currency: Option<String>, - pub key_pair: Option<KeyPairEnum>, - pub conf: Option<WS2PConf>, - pub main_thread_channel: ( - mpsc::Sender<WS2PThreadSignal>, - mpsc::Receiver<WS2PThreadSignal>, - ), - pub ws2p_endpoints: HashMap<NodeFullId, (NetworkEndpoint, WS2PConnectionState)>, - pub connections_meta_datas: HashMap<NodeFullId, WS2PConnectionMetaData>, - pub websockets: HashMap<NodeFullId, WebsocketSender>, - pub threads_senders_channels: HashMap<NodeFullId, mpsc::Sender<WS2POrderForListeningThread>>, - pub requests_awaiting_response: HashMap<ModuleReqId, (NetworkRequest, NodeFullId, SystemTime)>, - pub heads_cache: HashMap<NodeFullId, NetworkHead>, - pub my_head: Option<NetworkHead>, - pub uids_cache: HashMap<PubKey, String>, -} - #[derive(Debug)] pub enum WS2PThreadSignal { DuniterMessage(Box<DuniterMessage>), @@ -159,26 +140,6 @@ pub trait WS2PMessage: Sized { //fn parse_and_verify(v: serde_json::Value, currency: String) -> bool; } -pub fn get_random_connection<S: ::std::hash::BuildHasher>( - connections: &HashMap<NodeFullId, (NetworkEndpoint, WS2PConnectionState), S>, -) -> NodeFullId { - let mut rng = rand::thread_rng(); - let mut loop_count = 0; - loop { - for (ws2p_full_id, (_ep, state)) in &(*connections) { - if loop_count > 10 { - return *ws2p_full_id; - } - if let WS2PConnectionState::Established = state { - if rng.gen::<bool>() { - return *ws2p_full_id; - } - } - } - loop_count += 1; - } -} - impl Default for WS2PModule { fn default() -> WS2PModule { WS2PModule {} @@ -198,6 +159,9 @@ impl DuniterModule<DuniterMessage> for WS2PModule { fn default_conf() -> serde_json::Value { json!({ "sync_peers": [{ + "pubkey": "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx", + "ws2p_endpoints": ["WS2P c1c39a0a i3.ifee.fr 80 /ws2p"] + },{ "pubkey": "7v2J4badvfWQ6qwRdCwhhJfAsmKwoxRUNpJHiJHj7zef", "ws2p_endpoints": ["WS2P b48824f0 g1.monnaielibreoccitanie.org 80 /ws2p"] }] @@ -220,9 +184,7 @@ impl DuniterModule<DuniterMessage> for WS2PModule { conf: None, main_thread_channel: mpsc::channel(), ws2p_endpoints: HashMap::new(), - connections_meta_datas: HashMap::new(), websockets: HashMap::new(), - threads_senders_channels: HashMap::new(), requests_awaiting_response: HashMap::new(), heads_cache: HashMap::new(), my_head: None, @@ -294,7 +256,9 @@ impl DuniterModule<DuniterMessage> for WS2PModule { let dal_enpoints = ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P"))); for ep in dal_enpoints { - if ep.api() == NetworkEndpointApi(String::from("WS2P")) && ep.port() != 443 { + if ep.api() == NetworkEndpointApi(String::from("WS2P")) + && (cfg!(feature = "ssl") || ep.port() != 443) + { count += 1; ws2p_module.ws2p_endpoints.insert( ep.node_full_id() @@ -347,15 +311,14 @@ impl DuniterModule<DuniterMessage> for WS2PModule { ); } else { if ws2p_module.my_head.is_none() { - ws2p_module.my_head = - Some(WS2PModuleDatas::generate_my_head( - &key_pair, - &conf.clone(), - soft_name, - soft_version, - ¤t_blockstamp, - None, - )); + ws2p_module.my_head = Some(heads::generate_my_head( + &key_pair, + &conf.clone(), + soft_name, + soft_version, + ¤t_blockstamp, + None, + )); } ws2p_module.send_network_event( &NetworkEvent::ReceiveHeads(vec![ @@ -407,8 +370,6 @@ impl DuniterModule<DuniterMessage> for WS2PModule { *req_id, *receiver, *count, *from, ), ); - } else { - warn!("WS2PModule : No WS2P connections !"); } } else { let _blocks_request_result = ws2p_module @@ -430,7 +391,7 @@ impl DuniterModule<DuniterMessage> for WS2PModule { "WS2PModule : current_blockstamp = {}", current_blockstamp ); - ws2p_module.my_head = Some(WS2PModuleDatas::generate_my_head( + ws2p_module.my_head = Some(heads::generate_my_head( &key_pair, &conf.clone(), soft_name, @@ -448,12 +409,12 @@ impl DuniterModule<DuniterMessage> for WS2PModule { trace!("Send my HEAD: {:#?}", my_json_head); let _results: Result< (), - websocket::WebSocketError, + ws::Error, > = ws2p_module .websockets .iter_mut() .map(|ws| { - (ws.1).0.send_message(&Message::text( + (ws.1).0.send(Message::text( json!({ "name": "HEAD", "body": { @@ -483,7 +444,7 @@ impl DuniterModule<DuniterMessage> for WS2PModule { current_blockstamp = *current_blockstamp_; if ws2p_module.my_head.is_none() { ws2p_module.my_head = - Some(WS2PModuleDatas::generate_my_head( + Some(heads::generate_my_head( &key_pair, &conf.clone(), soft_name, @@ -526,14 +487,14 @@ impl DuniterModule<DuniterMessage> for WS2PModule { ); // Resent to other modules connections that match receive uids for (node_full_id, (ep, conn_state)) in - ws2p_module.ws2p_endpoints.clone() + &ws2p_module.ws2p_endpoints { if let Some(uid_option) = uids.get(&node_full_id.1) { ws2p_module.send_network_event( &NetworkEvent::ConnectionStateChange( - node_full_id, - conn_state as u32, + *node_full_id, + *conn_state as u32, uid_option.clone(), ep.get_url(false), ), @@ -554,8 +515,6 @@ impl DuniterModule<DuniterMessage> for WS2PModule { { WS2PSignal::NoConnection => { warn!("WS2PSignal::NoConnection"); - last_ws2p_connecting_wave = SystemTime::now(); - ws2p_module.connect_to_know_endpoints(); } WS2PSignal::ConnectionEstablished(ws2p_full_id) => { let req_id = @@ -569,6 +528,11 @@ impl DuniterModule<DuniterMessage> for WS2PModule { ws2p_full_id, ), ); + if ws2p_module.uids_cache.get(&ws2p_full_id.1).is_none() { + ws2p_module.send_dal_request(&DALRequest::BlockchainRequest( + DALReqBlockchain::UIDs(vec![ws2p_full_id.1]), + )); + } ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange( ws2p_full_id, WS2PConnectionState::Established as u32, @@ -607,27 +571,27 @@ impl DuniterModule<DuniterMessage> for WS2PModule { //trace!("WS2PSignal::PeerCard({})", ws2p_full_id); //ws2p_module.send_network_event(NetworkEvent::ReceivePeers(_)); for ep in ws2p_endpoints { - if ep.port() != 443 { - match ws2p_module.ws2p_endpoints.get( - &ep.node_full_id() - .expect("WS2P: Fail to get ep.node_full_id() !"), - ) { - Some(_) => {} - None => { - if let Some(_api) = - ws2p_db::string_to_api(&ep.api().0.clone()) - { - endpoints_to_update_status.insert( - ep.node_full_id().expect( - "WS2P: Fail to get ep.node_full_id() !", - ), - SystemTime::now(), - ); - } + match ws2p_module.ws2p_endpoints.get( + &ep.node_full_id() + .expect("WS2P: Fail to get ep.node_full_id() !"), + ) { + Some(_) => {} + None => { + if let Some(_api) = + ws2p_db::string_to_api(&ep.api().0.clone()) + { + endpoints_to_update_status.insert( + ep.node_full_id().expect( + "WS2P: Fail to get ep.node_full_id() !", + ), + SystemTime::now(), + ); + } + if cfg!(feature = "ssl") || ep.port() != 443 { ws2p_module.connect_to(&ep); } - }; - } + } + }; } } WS2PSignal::Heads(ws2p_full_id, heads) => { @@ -669,13 +633,6 @@ impl DuniterModule<DuniterMessage> for WS2PModule { )), )); } - /*if let Some(block) = BlockV10::from_json_value(&response) { - ws2p_module - .connections_meta_datas - .get_mut(&recipient_full_id) - .unwrap() - .current_blockstamp = Some((block.id, block.hash)); - }*/ } NetworkRequest::GetBlocks(ref _req_id, _receiver, _count, from) => { info!("WS2PSignal::ReceiveChunk({}, {:?})", req_id.0, req); @@ -906,831 +863,6 @@ impl DuniterModule<DuniterMessage> for WS2PModule { } } -impl WS2PModuleDatas { - fn open_db(db_path: &PathBuf) -> Result<sqlite::Connection, sqlite::Error> { - let conn: sqlite::Connection; - if !db_path.as_path().exists() { - conn = sqlite::open(db_path.as_path())?; - conn.execute( - "CREATE TABLE endpoints (hash_full_id TEXT, status INTEGER, node_id INTEGER, pubkey TEXT, - api INTEGER, version INTEGER, endpoint TEXT, last_check INTEGER);", - )?; - } else { - conn = sqlite::open(db_path.as_path())?; - } - Ok(conn) - } - pub fn parse_ws2p_conf( - duniter_conf: &DuniterConf, - ws2p_json_conf: &serde_json::Value, - ) -> WS2PConf { - let mut sync_endpoints = Vec::new(); - match ws2p_json_conf.get("sync_peers") { - Some(peers) => { - let array_peers = peers.as_array().expect("Conf: Fail to parse conf file !"); - for peer in array_peers { - let pubkey = match peer.get("pubkey") { - Some(pubkey) => PubKey::Ed25519( - ed25519::PublicKey::from_base58( - pubkey - .as_str() - .expect("WS2PConf Error : fail to parse sync endpoint pubkey"), - ).expect("WS2PConf Error : fail to parse sync endpoint pubkey"), - ), - None => panic!( - "Fail to load ws2p conf : \ - WrongFormat : not found pubkey field !" - ), - }; - match peer.get("ws2p_endpoints") { - Some(endpoints) => { - let array_endpoints = endpoints - .as_array() - .expect("Conf: Fail to parse conf file !"); - for endpoint in array_endpoints { - sync_endpoints.push( - NetworkEndpoint::parse_from_raw( - endpoint.as_str().expect("WS2P: Fail to get ep.as_str() !"), - pubkey, - 0, - 0, - ).expect(&format!( - "WS2PConf Error : fail to parse sync Endpoint = {:?}", - endpoint.as_str().expect("WS2P: Fail to get ep.as_str() !") - )), - ); - } - } - None => panic!( - "Fail to load conf : \ - WrongFormat : not found ws2p_endpoints field !" - ), - }; - } - } - None => panic!( - "Configuration Error : \ - You must declare at least one node on which to synchronize !" - ), - }; - WS2PConf { - outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA, - node_id: NodeUUID(duniter_conf.my_node_id()), - sync_endpoints, - } - } - pub fn send_dal_request(&self, req: &DALRequest) { - for follower in &self.followers { - if follower - .send(DuniterMessage::DALRequest(req.clone())) - .is_err() - { - // handle error - } - } - } - pub fn send_network_event(&self, event: &NetworkEvent) { - for follower in &self.followers { - match follower.send(DuniterMessage::NetworkEvent(event.clone())) { - Ok(_) => { - debug!("Send NetworkEvent to one follower."); - } - Err(_) => { - warn!("Fail to send NetworkEvent to one follower !"); - } - } - } - } - pub fn generate_my_head( - network_keypair: &KeyPairEnum, - conf: &WS2PConf, - soft_name: &str, - soft_version: &str, - my_current_blockstamp: &Blockstamp, - my_uid: Option<String>, - ) -> NetworkHead { - let message = NetworkHeadMessage::V2(NetworkHeadMessageV2 { - api: String::from("WS2POCA"), - version: 1, - pubkey: network_keypair.public_key(), - blockstamp: *my_current_blockstamp, - node_uuid: conf.node_id, - software: String::from(soft_name), - soft_version: String::from(soft_version), - prefix: 1, - free_member_room: None, - free_mirror_room: None, - }); - let message_v2 = NetworkHeadMessage::V2(NetworkHeadMessageV2 { - api: String::from("WS2POCA"), - version: 2, - pubkey: network_keypair.public_key(), - blockstamp: *my_current_blockstamp, - node_uuid: conf.node_id, - software: String::from(soft_name), - soft_version: String::from(soft_version), - prefix: 1, - free_member_room: Some(0), - free_mirror_room: Some(0), - }); - NetworkHead::V2(Box::new(NetworkHeadV2 { - message: message.clone(), - sig: network_keypair - .private_key() - .sign(message.to_string().as_bytes()), - message_v2: message_v2.clone(), - sig_v2: network_keypair - .private_key() - .sign(message_v2.to_string().as_bytes()), - step: 0, - uid: my_uid, - })) - } - pub fn get_network_consensus(&self) -> Result<Blockstamp, NetworkConsensusError> { - let mut count_known_blockstamps = 0; - let mut farthest_blockstamp = Blockstamp::default(); - let mut blockstamps_occurences: HashMap<Blockstamp, usize> = - HashMap::with_capacity(*WS2P_DEFAULT_OUTCOMING_QUOTA); - let mut dominant_blockstamp = Blockstamp::default(); - let mut dominant_blockstamp_occurences = 0; - for (_ws2p_full_id, head) in self.heads_cache.clone() { - count_known_blockstamps += 1; - let blockstamps_occurences_copy = blockstamps_occurences.clone(); - match blockstamps_occurences_copy.get(&head.blockstamp()) { - Some(occurences) => { - let mut occurences_mut = blockstamps_occurences - .get_mut(&head.blockstamp()) - .expect("WS2P: Fail to get_mut blockstamps_occurences !"); - *occurences_mut += 1; - if *occurences > dominant_blockstamp_occurences { - dominant_blockstamp_occurences = *occurences; - dominant_blockstamp = head.blockstamp(); - } - } - None => { - blockstamps_occurences.insert(head.blockstamp(), 0); - } - } - if head.blockstamp().id.0 > farthest_blockstamp.id.0 { - farthest_blockstamp = head.blockstamp(); - } - } - if count_known_blockstamps < 5 { - return Err(NetworkConsensusError::InsufficientData( - count_known_blockstamps, - )); - } else if farthest_blockstamp == dominant_blockstamp { - return Ok(dominant_blockstamp); - } - Err(NetworkConsensusError::Fork) - } - fn count_established_connections(&self) -> usize { - let mut count_established_connections = 0; - for (_ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() { - if let WS2PConnectionState::Established = state { - count_established_connections += 1; - } - } - count_established_connections - } - pub fn connect_to_know_endpoints(&mut self) -> () { - let mut count_established_connections = 0; - let mut reachable_endpoints = Vec::new(); - let mut unreachable_endpoints = Vec::new(); - for (_ws2p_full_id, (ep, state)) in self.ws2p_endpoints.clone() { - match state { - WS2PConnectionState::Established => count_established_connections += 1, - WS2PConnectionState::NeverTry - | WS2PConnectionState::Close - | WS2PConnectionState::Denial => reachable_endpoints.push(ep), - _ => unreachable_endpoints.push(ep), - } - } - let mut free_outcoming_rooms = self - .conf - .clone() - .expect("WS2P: Fail to get conf !") - .outcoming_quota - count_established_connections; - while free_outcoming_rooms > 0 { - let ep = if !reachable_endpoints.is_empty() { - reachable_endpoints - .pop() - .expect("WS2P: Fail to pop() reachable_endpoints !") - } else if !unreachable_endpoints.is_empty() { - unreachable_endpoints - .pop() - .expect("WS2P: Fail to pop() unreachable_endpoints !") - } else { - break; - }; - self.connect_to_without_checking_quotas(&ep); - free_outcoming_rooms -= 1; - } - } - pub fn connect_to(&mut self, endpoint: &NetworkEndpoint) -> () { - // Add endpoint to endpoints list (if there isn't already) - match self.ws2p_endpoints.get( - &endpoint - .node_full_id() - .expect("WS2P: Fail to get ep.node_full_id() !"), - ) { - Some(_) => { - self.ws2p_endpoints - .get_mut( - &endpoint - .node_full_id() - .expect("WS2P: Fail to get ep.node_full_id() !"), - ) - .expect("WS2P: Fail to get_mut() a ws2p_endpoint !") - .1 = WS2PConnectionState::NeverTry; - } - None => { - self.ws2p_endpoints.insert( - endpoint - .node_full_id() - .expect("WS2P: Fail to get ep.node_full_id() !"), - (endpoint.clone(), WS2PConnectionState::NeverTry), - ); - } - }; - if self - .conf - .clone() - .expect("WS2P: Fail to get conf !") - .outcoming_quota > self.count_established_connections() - { - self.connect_to_without_checking_quotas(&endpoint); - } - } - fn close_connection(&mut self, ws2p_full_id: &NodeFullId, reason: WS2PCloseConnectionReason) { - match reason { - WS2PCloseConnectionReason::NegociationTimeout => {} - WS2PCloseConnectionReason::AuthMessInvalidSig - | WS2PCloseConnectionReason::Timeout - | WS2PCloseConnectionReason::Unknow => { - self.ws2p_endpoints - .get_mut(ws2p_full_id) - .expect("Failure : attempt to delete a non-existent connection !") - .1 = WS2PConnectionState::Close - } - } - self.connections_meta_datas.remove(ws2p_full_id); - self.websockets.remove(ws2p_full_id).expect(&format!( - "Fatal error : no websocket for {} !", - ws2p_full_id - )); - self.threads_senders_channels.remove(ws2p_full_id); - } - pub fn ws2p_conn_message_pretreatment(&mut self, message: WS2PConnectionMessage) -> WS2PSignal { - let connections_count = self.connections_meta_datas.len(); - if connections_count == 0 { - return WS2PSignal::NoConnection; - } - let ws2p_full_id = message.0; - match message.1 { - WS2PConnectionMessagePayload::WrongUrl - | WS2PConnectionMessagePayload::FailOpenWS - | WS2PConnectionMessagePayload::FailToSplitWS => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = WS2PConnectionState::WSError; - return WS2PSignal::WSError(ws2p_full_id); - } - WS2PConnectionMessagePayload::TryToSendConnectMess => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = WS2PConnectionState::TryToSendConnectMess; - } - WS2PConnectionMessagePayload::FailSendConnectMess => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to mut ep !") - .1 = WS2PConnectionState::Unreachable; - } - WS2PConnectionMessagePayload::WebsocketOk(sender) => { - self.websockets.insert(ws2p_full_id, sender); - } - WS2PConnectionMessagePayload::ValidConnectMessage(response, new_con_state) => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = new_con_state; - if let WS2PConnectionState::ConnectMessOk = self.ws2p_endpoints[&ws2p_full_id].1 { - trace!("Send: {:#?}", response); - self.websockets - .get_mut(&ws2p_full_id) - .expect(&format!( - "Fatal error : no websocket for {} !", - ws2p_full_id - )) - .0 - .send_message(&Message::text(response)) - .expect("WS2P: Fail to send OK Message !"); - } - } - WS2PConnectionMessagePayload::ValidAckMessage(r, new_con_state) => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = new_con_state; - if let WS2PConnectionState::AckMessOk = self.ws2p_endpoints[&ws2p_full_id].1 { - trace!("DEBUG : Send: {:#?}", r); - self.websockets - .get_mut(&ws2p_full_id) - .expect(&format!( - "Fatal error : no websocket for {} !", - ws2p_full_id - )) - .0 - .send_message(&Message::text(r)) - .expect("WS2P: Fail to send Message in websocket !"); - } - } - WS2PConnectionMessagePayload::ValidOk(new_con_state) => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = new_con_state; - match self.ws2p_endpoints[&ws2p_full_id].1 { - WS2PConnectionState::OkMessOkWaitingAckMess => {} - WS2PConnectionState::Established => { - return WS2PSignal::ConnectionEstablished(ws2p_full_id) - } - _ => { - self.threads_senders_channels[&ws2p_full_id] - .send(WS2POrderForListeningThread::Close) - .expect("WS2P: Fail to send Close signel to connections threads !"); - self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::Unknow); - return WS2PSignal::Empty; - } - } - } - WS2PConnectionMessagePayload::DalRequest(req_id, req_body) => { - return WS2PSignal::DalRequest(ws2p_full_id, req_id, req_body); - } - WS2PConnectionMessagePayload::PeerCard(body, ws2p_endpoints) => { - return WS2PSignal::PeerCard(ws2p_full_id, body, ws2p_endpoints); - } - WS2PConnectionMessagePayload::Heads(heads) => { - let mut applied_heads = Vec::with_capacity(heads.len()); - for head in heads { - if let Some(head) = NetworkHead::from_json_value(&head) { - if head.verify() - && (self.my_head.is_none() - || head.node_full_id() - != self - .my_head - .clone() - .expect("WS2P: Fail to clone my_head") - .node_full_id()) - && head.apply(&mut self.heads_cache) - { - applied_heads.push(head); - } - } - } - return WS2PSignal::Heads(ws2p_full_id, applied_heads); - } - WS2PConnectionMessagePayload::Document(network_doc) => { - return WS2PSignal::Document(ws2p_full_id, network_doc); - } - WS2PConnectionMessagePayload::ReqResponse(req_id, response) => { - if self.requests_awaiting_response.len() > req_id.0 as usize { - if let Some((ref ws2p_request, ref recipient_fulld_id, ref _timestamp)) = - self.requests_awaiting_response.remove(&req_id) - { - return WS2PSignal::ReqResponse( - req_id, - *ws2p_request, - *recipient_fulld_id, - response, - ); - } - } - } - WS2PConnectionMessagePayload::NegociationTimeout => { - match self.ws2p_endpoints[&ws2p_full_id].1 { - WS2PConnectionState::AckMessOk | WS2PConnectionState::ConnectMessOk => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = WS2PConnectionState::Denial - } - WS2PConnectionState::WaitingConnectMess => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = WS2PConnectionState::NoResponse - } - _ => { - self.ws2p_endpoints - .get_mut(&ws2p_full_id) - .expect("WS2P: Fail to get mut ep !") - .1 = WS2PConnectionState::Unreachable - } - } - self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::NegociationTimeout); - return WS2PSignal::NegociationTimeout(ws2p_full_id); - } - WS2PConnectionMessagePayload::Timeout => { - self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::Timeout); - return WS2PSignal::Timeout(ws2p_full_id); - } - WS2PConnectionMessagePayload::UnknowMessage => warn!( - "WS2P : Receive Unknow Message from {}.", - &self.connections_meta_datas[&ws2p_full_id] - .remote_pubkey - .expect("WS2P: UnknowMessage : Fail to get remote_pubkey !") - ), - WS2PConnectionMessagePayload::WrongFormatMessage => warn!( - "WS2P : Receive Wrong Format Message from {}.", - &self.connections_meta_datas[&ws2p_full_id] - .remote_pubkey - .expect("WS2P: WrongFormatMessage : Fail to get remote_pubkey !") - ), - WS2PConnectionMessagePayload::InvalidMessage => return WS2PSignal::Empty, - WS2PConnectionMessagePayload::Close => { - self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::AuthMessInvalidSig) - } - } - // Detect timeout requests - let mut requests_timeout = Vec::new(); - for &(ref req, ref _ws2p_full_id, ref timestamp) in - self.requests_awaiting_response.clone().values() - { - if SystemTime::now().duration_since(*timestamp).unwrap() > Duration::new(20, 0) { - requests_timeout.push(req.get_req_full_id()); - warn!("request timeout : {:?}", req); - } - } - // Delete (and resend) timeout requests - for req_id in requests_timeout { - //let ws2p_endpoints = self.ws2p_endpoints.clone(); - let _request_option = self.requests_awaiting_response.remove(&req_id.1); - /*if let Some((request, _, _)) = request_option { - let _request_result = self.send_request_to_specific_node( - &get_random_connection(&ws2p_endpoints), - &request, - ); - }*/ - } - WS2PSignal::Empty - } - - pub fn send_request_to_all_connections( - &mut self, - ws2p_request: &NetworkRequest, - ) -> Result<(), SendRequestError> { - let mut count_successful_sending: usize = 0; - let mut errors: Vec<websocket::WebSocketError> = Vec::new(); - match *ws2p_request { - NetworkRequest::GetCurrent(req_full_id, _receiver) => { - for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() { - if let WS2PConnectionState::Established = state { - let ws2p_request = NetworkRequest::GetCurrent( - ModuleReqFullId( - req_full_id.0, - ModuleReqId( - (self.requests_awaiting_response.len() - + count_successful_sending) - as u32, - ), - ), - ws2p_full_id, - ); - match self.send_request_to_specific_node(&ws2p_full_id, &ws2p_request) { - Ok(_) => count_successful_sending += 1, - Err(e) => errors.push(e), - }; - } - } - } - /* NetworkRequest::GetBlock(req_full_id, number) => {} */ - NetworkRequest::GetBlocks(_req_full_id, _receiver, _count, _from_number) => {} - NetworkRequest::GetRequirementsPending(req_full_id, _receiver, min_cert) => { - for (ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() { - if let WS2PConnectionState::Established = state { - let ws2p_request = NetworkRequest::GetRequirementsPending( - ModuleReqFullId( - req_full_id.0, - ModuleReqId(self.requests_awaiting_response.len() as u32), - ), - ws2p_full_id, - min_cert, - ); - match self.send_request_to_specific_node(&ws2p_full_id, &ws2p_request) { - Ok(_) => count_successful_sending += 1, - Err(e) => errors.push(e), - }; - } - } - } - _ => { - return Err(SendRequestError::RequestTypeMustNotBeTransmitted()); - } - } - debug!("count_successful_sending = {}", count_successful_sending); - if !errors.is_empty() { - return Err(SendRequestError::WSError(count_successful_sending, errors)); - } - Ok(()) - } - - pub fn send_request_to_specific_node( - &mut self, - receiver_ws2p_full_id: &NodeFullId, - ws2p_request: &NetworkRequest, - ) -> Result<(), websocket::WebSocketError> { - self.websockets - .get_mut(receiver_ws2p_full_id) - .expect("WS2P: Fail to get mut websocket !") - .0 - .send_message(&Message::text( - network_request_to_json(ws2p_request).to_string(), - ))?; - self.requests_awaiting_response.insert( - ws2p_request.get_req_id(), - (*ws2p_request, *receiver_ws2p_full_id, SystemTime::now()), - ); - debug!( - "send request {} to {}", - network_request_to_json(ws2p_request).to_string(), - receiver_ws2p_full_id - ); - Ok(()) - } - - fn connect_to_without_checking_quotas(&mut self, endpoint: &NetworkEndpoint) -> () { - // update connection state - self.ws2p_endpoints - .get_mut( - &endpoint - .node_full_id() - .expect("WS2P: Fail to get ep.node_full_id() !"), - ) - .expect("Fatal error: try to connect to unlisted endpoint ! ") - .1 = WS2PConnectionState::TryToOpenWS; - - // get endpoint url - let ws_url = endpoint.get_url(true); - - // Create WS2PConnection - let mut conn_meta_datas = WS2PConnectionMetaData::new( - "b60a14fd-0826-4ae0-83eb-1a92cd59fd5308535fd3-78f2-4678-9315-cd6e3b7871b1".to_string(), - ); - conn_meta_datas.remote_pubkey = Some(endpoint.pubkey()); - conn_meta_datas.remote_uuid = Some( - endpoint - .node_uuid() - .expect("WS2P: Fail to get ep.node_uuid() !"), - ); - - // Prepare datas for listening thread - let mut datas_for_listening_thread = WS2PDatasForListeningThread { - conn_meta_datas: conn_meta_datas.clone(), - currency: self.currency.clone().expect("WS2P: Fail to get currency !"), - key_pair: self.key_pair.expect("WS2P: Fail to get key_pair!"), - }; - - // Create CONNECT Message - let mut connect_message = WS2PConnectMessageV1 { - currency: self.currency.clone().expect("WS2P: Fail to getcurrency !"), - pubkey: self - .key_pair - .expect("WS2P: Fail to get key_pair!") - .public_key(), - challenge: conn_meta_datas.challenge.clone(), - signature: None, - }; - connect_message.signature = - Some(connect_message.sign(self.key_pair.expect("WS2P: Fail to get key_pair !"))); - let json_connect_message = - serde_json::to_string(&connect_message).expect("Fail to serialize CONNECT message !"); - - // Log - trace!("Try connection to {} ...", ws_url); - - // Listen incoming messages into a thread - let sender_to_main_thread: mpsc::Sender<WS2PThreadSignal> = - mpsc::Sender::clone(&self.main_thread_channel.0); - let (tx2, rx2) = mpsc::channel(); - self.connections_meta_datas - .insert(conn_meta_datas.node_full_id(), conn_meta_datas.clone()); - self.threads_senders_channels - .insert(conn_meta_datas.node_full_id(), tx2); - thread::spawn(move || { - // Open websocket - let open_ws_time = SystemTime::now(); - let client = match ClientBuilder::new(&ws_url) { - Ok(mut client_builder) => match client_builder.connect_insecure() { - Ok(c) => c, - Err(_) => { - debug!("WS2PConnectResult::FailOpenWS"); - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::FailOpenWS, - ), - )) - .unwrap_or(()); - return (); - } - }, - Err(_) => { - warn!("WS2PConnectResult::WrongUrl : {}", ws_url); - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::WrongUrl, - ), - )) - .unwrap_or(()); - - return (); - } - }; - let (mut receiver, mut sender) = match client.split() { - Ok((mut r, mut s)) => (r, s), - Err(_) => { - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::FailToSplitWS, - ), - )) - .unwrap_or(()); - return (); - } - }; - - // Send CONNECT Message - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::TryToSendConnectMess, - ), - )) - .unwrap_or(()); - match sender.send_message(&Message::text(json_connect_message)) { - Ok(_) => { - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::WebsocketOk(WebsocketSender(sender)), - ), - )) - .unwrap_or(()); - } - Err(_) => { - receiver.shutdown_all().unwrap_or(()); - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::FailSendConnectMess, - ), - )) - .unwrap_or(()); - return (); - } - } - - let mut last_mess_time = SystemTime::now(); - let mut spam_interval = false; - let mut spam_counter = 0; - for incoming_message in receiver.incoming_messages() { - // Spam ? - if SystemTime::now().duration_since(last_mess_time).unwrap() - > Duration::new(*WS2P_SPAM_INTERVAL_IN_MILLI_SECS, 0) - { - if spam_interval { - spam_counter += 1; - } else { - spam_interval = true; - spam_counter = 2; - } - } else { - spam_interval = false; - spam_counter = 0; - } - // Spam ? - if spam_counter >= *WS2P_SPAM_LIMIT { - thread::sleep(Duration::from_millis(*WS2P_SPAM_SLEEP_TIME_IN_SEC)); - last_mess_time = SystemTime::now(); - } else { - // Negociation timeout ? - if datas_for_listening_thread.conn_meta_datas.state - != WS2PConnectionState::Established - && SystemTime::now().duration_since(open_ws_time).unwrap() - > Duration::new(*WS2P_NEGOTIATION_TIMEOUT, 0) - { - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::NegociationTimeout, - ), - )) - .unwrap_or(()); - break; - } - // Connection timeout ? - else if SystemTime::now().duration_since(last_mess_time).unwrap() - > Duration::new(*WS2P_CONNECTION_TIMEOUT, 0) - { - sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread.conn_meta_datas.node_full_id(), - WS2PConnectionMessagePayload::Timeout, - ), - )) - .unwrap_or(()); - break; - } - last_mess_time = SystemTime::now(); - match rx2.recv_timeout(Duration::from_millis(40)) { - Ok(s) => match s { - WS2POrderForListeningThread::Close => break, - }, - Err(e) => { - match e { - mpsc::RecvTimeoutError::Timeout => { - match incoming_message { - Ok(message) => { - if message.is_close() { - if sender_to_main_thread - .send(WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread - .conn_meta_datas - .node_full_id(), - WS2PConnectionMessagePayload::Close, - ), - )) - .is_ok() - { - break; - } - } else if message.is_data() { - // Parse message - let m = Message::from(message); - let s: String = from_utf8(&m.payload) - .expect("WS2P: Fail to convert message payload to String !") - .to_string(); - let message: serde_json::Value = - serde_json::from_str(&s) - .expect("WS2P: Fail to convert string message ton json value !"); - let result = sender_to_main_thread.send( - WS2PThreadSignal::WS2PConnectionMessage( - WS2PConnectionMessage( - datas_for_listening_thread - .conn_meta_datas - .node_full_id(), - datas_for_listening_thread - .conn_meta_datas - .parse_and_check_incoming_message( - &datas_for_listening_thread - .currency, - datas_for_listening_thread - .key_pair, - &message, - ), - ), - ), - ); - if result.is_err() { - debug!("Close ws2p connection because ws2p main thread is unrechable !"); - break; - } - } - } - Err(e) => { - warn!("WebSocketError : {} ! Close ", e); - //receiver.shutdown_all().unwrap_or(()); - break; - } - }; - } - mpsc::RecvTimeoutError::Disconnected => { - break; - } - } - } - }; - } - } - }); - } -} - #[cfg(test)] mod tests { extern crate duniter_conf; diff --git a/ws2p/ws2p_connection.rs b/ws2p/ws2p_connection.rs index 84578ca8a48def9bb3084b73900b9fc828ea0a96..214ef3290051b81a56f39d3cc5cb787fc6ead58e 100644 --- a/ws2p/ws2p_connection.rs +++ b/ws2p/ws2p_connection.rs @@ -1,15 +1,194 @@ -extern crate serde_json; -extern crate websocket; - +use constants::*; use duniter_crypto::keys::*; use duniter_module::ModuleReqId; use duniter_network::network_endpoint::{NetworkEndpoint, NetworkEndpointApi}; use duniter_network::{NetworkDocument, NodeUUID}; use parsers::blocks::parse_json_block; -use std::fmt::Debug; -use std::net::TcpStream; +use rand::Rng; +use std::sync::mpsc; +#[allow(deprecated)] +use ws::util::{Timeout, Token}; +use ws::{connect, CloseCode, Frame, Handler, Handshake, Message, Sender}; +use *; + +const CONNECT: Token = Token(1); +const EXPIRE: Token = Token(2); + +/// Store a websocket sender +pub struct WsSender(pub Sender); + +impl ::std::fmt::Debug for WsSender { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "WsSender {{ }}") + } +} -use super::{NodeFullId, WS2PAckMessageV1, WS2PConnectMessageV1, WS2PMessage, WS2POkMessageV1}; +// Our Handler struct. +// Here we explicity indicate that the Client needs a Sender, +// whereas a closure captures the Sender for us automatically. +#[allow(deprecated)] +struct Client { + ws: Sender, + conductor_sender: mpsc::Sender<WS2PThreadSignal>, + currency: String, + key_pair: KeyPairEnum, + connect_message: Message, + conn_meta_datas: WS2PConnectionMetaDatas, + last_mess_time: SystemTime, + spam_interval: bool, + spam_counter: usize, + timeout: Option<Timeout>, +} + +// We implement the Handler trait for Client so that we can get more +// fine-grained control of the connection. +impl Handler for Client { + // `on_open` will be called only after the WebSocket handshake is successful + // so at this point we know that the connection is ready to send/receive messages. + // We ignore the `Handshake` for now, but you could also use this method to setup + // Handler state or reject the connection based on the details of the Request + // or Response, such as by checking cookies or Auth headers. + fn on_open(&mut self, _: Handshake) -> ws::Result<()> { + // Define timeouts + self.ws.timeout(WS2P_NEGOTIATION_TIMEOUT * 1_000, CONNECT)?; + self.ws.timeout(WS2P_EXPIRE_TIMEOUT * 1_000, EXPIRE)?; + // Send ws::Sender to WS2PConductor + let result = self + .conductor_sender + .send(WS2PThreadSignal::WS2PConnectionMessage( + WS2PConnectionMessage( + self.conn_meta_datas.node_full_id(), + WS2PConnectionMessagePayload::WebsocketOk(WsSender(self.ws.clone())), + ), + )); + // If WS2PConductor is unrechable, close connection. + if result.is_err() { + debug!("Close ws2p connection because ws2p main thread is unrechable !"); + self.ws.close(CloseCode::Normal) + } else { + // Send CONNECT Message + self.ws.send(self.connect_message.clone()) + } + } + + // `on_message` is roughly equivalent to the Handler closure. It takes a `Message` + // and returns a `Result<()>`. + fn on_message(&mut self, msg: Message) -> ws::Result<()> { + // Spam ? + if SystemTime::now() + .duration_since(self.last_mess_time) + .unwrap() > Duration::new(*WS2P_SPAM_INTERVAL_IN_MILLI_SECS, 0) + { + if self.spam_interval { + self.spam_counter += 1; + } else { + self.spam_interval = true; + self.spam_counter = 2; + } + } else { + self.spam_interval = false; + self.spam_counter = 0; + } + // Spam ? + if self.spam_counter >= *WS2P_SPAM_LIMIT { + thread::sleep(Duration::from_millis(*WS2P_SPAM_SLEEP_TIME_IN_SEC)); + self.last_mess_time = SystemTime::now(); + return Ok(()); + } + self.last_mess_time = SystemTime::now(); + + // Parse and check incoming message + if msg.is_text() { + let s: String = msg + .into_text() + .expect("WS2P: Fail to convert message payload to String !"); + trace!("WS2P: receive mess: {}", s); + let json_message: serde_json::Value = serde_json::from_str(&s) + .expect("WS2P: Fail to convert string message ton json value !"); + let result = self + .conductor_sender + .send(WS2PThreadSignal::WS2PConnectionMessage( + WS2PConnectionMessage( + self.conn_meta_datas.node_full_id(), + self.conn_meta_datas.parse_and_check_incoming_message( + &self.currency, + self.key_pair, + &json_message, + ), + ), + )); + if result.is_err() { + info!("Close ws2p connection because ws2p main thread is unrechable !"); + self.ws.close(CloseCode::Normal)?; + } + } + Ok(()) + } + fn on_timeout(&mut self, event: Token) -> ws::Result<()> { + match event { + CONNECT => { + if self.conn_meta_datas.state != WS2PConnectionState::Established { + let _result = self.conductor_sender.send( + WS2PThreadSignal::WS2PConnectionMessage(WS2PConnectionMessage( + self.conn_meta_datas.node_full_id(), + WS2PConnectionMessagePayload::NegociationTimeout, + )), + ); + self.ws.close(CloseCode::Away) + } else { + Ok(()) + } + } + EXPIRE => { + let _result = self + .conductor_sender + .send(WS2PThreadSignal::WS2PConnectionMessage( + WS2PConnectionMessage( + self.conn_meta_datas.node_full_id(), + WS2PConnectionMessagePayload::Timeout, + ), + )); + self.ws.close(CloseCode::Away) + } + _ => Ok(()), + } + } + #[allow(deprecated)] + fn on_new_timeout(&mut self, event: Token, timeout: Timeout) -> ws::Result<()> { + if event == EXPIRE { + if let Some(t) = self.timeout.take() { + self.ws.cancel(t)?; + } + self.timeout = Some(timeout) + } + Ok(()) + } + fn on_frame(&mut self, frame: Frame) -> ws::Result<Option<Frame>> { + // some activity has occurred, let's reset the expiration timeout + self.ws.timeout(WS2P_EXPIRE_TIMEOUT * 1_000, EXPIRE)?; + Ok(Some(frame)) + } + fn on_close(&mut self, code: CloseCode, reason: &str) { + // The WebSocket protocol allows for a utf8 reason for the closing state after the + // close code. WS-RS will attempt to interpret this data as a utf8 description of the + // reason for closing the connection. I many cases, `reason` will be an empty string. + // So, you may not normally want to display `reason` to the user, + // but let's assume that we know that `reason` is human-readable. + match code { + CloseCode::Normal => info!("The remote server close the connection."), + CloseCode::Away => info!("The remote server is leaving."), + _ => warn!("The remote server encountered an error: {}", reason), + } + let _result = self + .conductor_sender + .send(WS2PThreadSignal::WS2PConnectionMessage( + WS2PConnectionMessage( + self.conn_meta_datas.node_full_id(), + WS2PConnectionMessagePayload::Close, + ), + )); + } +} #[derive(Debug, Copy, Clone)] pub enum WS2POrderForListeningThread { @@ -74,14 +253,6 @@ impl WS2PConnectionState { } } -pub struct WebsocketSender(pub websocket::sender::Writer<TcpStream>); - -impl Debug for WebsocketSender { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "WebsocketSender {{ }}") - } -} - #[derive(Debug)] pub enum WS2PConnectionMessagePayload { FailOpenWS, @@ -89,7 +260,7 @@ pub enum WS2PConnectionMessagePayload { FailToSplitWS, TryToSendConnectMess, FailSendConnectMess, - WebsocketOk(WebsocketSender), + WebsocketOk(WsSender), NegociationTimeout, ValidConnectMessage(String, WS2PConnectionState), ValidAckMessage(String, WS2PConnectionState), @@ -118,7 +289,7 @@ pub enum WS2PCloseConnectionReason { } #[derive(Debug, Clone)] -pub struct WS2PConnectionMetaData { +pub struct WS2PConnectionMetaDatas { pub state: WS2PConnectionState, pub remote_uuid: Option<NodeUUID>, pub remote_pubkey: Option<PubKey>, @@ -129,14 +300,14 @@ pub struct WS2PConnectionMetaData { #[derive(Debug, Clone)] pub struct WS2PDatasForListeningThread { - pub conn_meta_datas: WS2PConnectionMetaData, + pub conn_meta_datas: WS2PConnectionMetaDatas, pub currency: String, pub key_pair: KeyPairEnum, } -impl WS2PConnectionMetaData { +impl WS2PConnectionMetaDatas { pub fn new(challenge: String) -> Self { - WS2PConnectionMetaData { + WS2PConnectionMetaDatas { state: WS2PConnectionState::WaitingConnectMess, remote_uuid: None, remote_pubkey: None, @@ -170,7 +341,7 @@ impl WS2PConnectionMetaData { if message.verify() && message.pubkey == self.remote_pubkey.unwrap() { match self.state { WS2PConnectionState::WaitingConnectMess => { - trace!("CONNECT sig is valid."); + debug!("CONNECT sig is valid."); self.state = WS2PConnectionState::ConnectMessOk; self.remote_challenge = message.challenge.clone(); let mut response = WS2PAckMessageV1 { @@ -397,3 +568,83 @@ impl WS2PConnectionMetaData { } } } + +pub fn get_random_connection<S: ::std::hash::BuildHasher>( + connections: &HashMap<NodeFullId, (NetworkEndpoint, WS2PConnectionState), S>, +) -> NodeFullId { + let mut rng = rand::thread_rng(); + let mut loop_count = 0; + loop { + for (ws2p_full_id, (_ep, state)) in &(*connections) { + if loop_count > 10 { + return *ws2p_full_id; + } + if let WS2PConnectionState::Established = state { + if rng.gen::<bool>() { + return *ws2p_full_id; + } + } + } + loop_count += 1; + } +} + +pub fn connect_to_ws2p_endpoint( + endpoint: &NetworkEndpoint, + conductor_sender: &mpsc::Sender<WS2PThreadSignal>, + currency: &str, + key_pair: KeyPairEnum, +) -> ws::Result<()> { + // Get endpoint url + let ws_url = endpoint.get_url(true); + + // Create WS2PConnectionMetaDatass + let mut conn_meta_datas = WS2PConnectionMetaDatas::new( + "b60a14fd-0826-4ae0-83eb-1a92cd59fd5308535fd3-78f2-4678-9315-cd6e3b7871b1".to_string(), + ); + conn_meta_datas.remote_pubkey = Some(endpoint.pubkey()); + conn_meta_datas.remote_uuid = Some( + endpoint + .node_uuid() + .expect("WS2P: Fail to get ep.node_uuid() !"), + ); + + // Generate connect message + let connect_message = + generate_connect_message(currency, key_pair, conn_meta_datas.challenge.clone()); + + // Log + info!("Try connection to {} ...", ws_url); + + // Connect to websocket + connect(ws_url, |ws| Client { + ws, + conductor_sender: conductor_sender.clone(), + currency: String::from(currency), + key_pair, + connect_message: connect_message.clone(), + conn_meta_datas: conn_meta_datas.clone(), + last_mess_time: SystemTime::now(), + spam_interval: false, + spam_counter: 0, + timeout: None, + }) +} + +pub fn generate_connect_message( + currency: &str, + key_pair: KeyPairEnum, + challenge: String, +) -> Message { + // Create CONNECT Message + let mut connect_message = WS2PConnectMessageV1 { + currency: String::from(currency), + pubkey: key_pair.public_key(), + challenge, + signature: None, + }; + connect_message.signature = Some(connect_message.sign(key_pair)); + Message::text( + serde_json::to_string(&connect_message).expect("Fail to serialize CONNECT message !"), + ) +} diff --git a/ws2p/ws2p_db.rs b/ws2p/ws2p_db.rs index 5ffad9a7d8627903ef91d41e5c503b987a38cdc8..5d34ff28aeb62a6c6bf5f08f3df319972295497b 100644 --- a/ws2p/ws2p_db.rs +++ b/ws2p/ws2p_db.rs @@ -5,7 +5,6 @@ extern crate duniter_module; extern crate duniter_network; extern crate serde_json; extern crate sqlite; -extern crate websocket; use duniter_crypto::keys::*; use duniter_network::network_endpoint::{NetworkEndpoint, NetworkEndpointApi};