From f864fd9a7366ba4339a6d8dcd50a8bf305330c9b Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Wed, 24 Apr 2019 20:47:46 +0200
Subject: [PATCH 1/5] [ref] ws2pv1: move crate code in folder src

---
 lib/modules/ws2p-v1-legacy/Cargo.toml                        | 2 +-
 lib/modules/ws2p-v1-legacy/{ => src}/ack_message.rs          | 0
 lib/modules/ws2p-v1-legacy/{ => src}/connect_message.rs      | 0
 lib/modules/ws2p-v1-legacy/{ => src}/constants.rs            | 0
 lib/modules/ws2p-v1-legacy/{ => src}/datas.rs                | 0
 lib/modules/ws2p-v1-legacy/{ => src}/heads.rs                | 0
 lib/modules/ws2p-v1-legacy/{ => src}/lib.rs                  | 0
 lib/modules/ws2p-v1-legacy/{ => src}/ok_message.rs           | 0
 lib/modules/ws2p-v1-legacy/{ => src}/parsers/blocks.rs       | 0
 lib/modules/ws2p-v1-legacy/{ => src}/parsers/excluded.rs     | 0
 lib/modules/ws2p-v1-legacy/{ => src}/parsers/identities.rs   | 0
 lib/modules/ws2p-v1-legacy/{ => src}/parsers/memberships.rs  | 0
 lib/modules/ws2p-v1-legacy/{ => src}/parsers/mod.rs          | 0
 lib/modules/ws2p-v1-legacy/{ => src}/parsers/transactions.rs | 0
 lib/modules/ws2p-v1-legacy/{ => src}/serializer.rs           | 0
 lib/modules/ws2p-v1-legacy/{ => src}/ws2p_connection.rs      | 0
 lib/modules/ws2p-v1-legacy/{ => src}/ws2p_db.rs              | 0
 lib/modules/ws2p-v1-legacy/{ => src}/ws2p_requests.rs        | 0
 18 files changed, 1 insertion(+), 1 deletion(-)
 rename lib/modules/ws2p-v1-legacy/{ => src}/ack_message.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/connect_message.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/constants.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/datas.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/heads.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/lib.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/ok_message.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/parsers/blocks.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/parsers/excluded.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/parsers/identities.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/parsers/memberships.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/parsers/mod.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/parsers/transactions.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/serializer.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/ws2p_connection.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/ws2p_db.rs (100%)
 rename lib/modules/ws2p-v1-legacy/{ => src}/ws2p_requests.rs (100%)

diff --git a/lib/modules/ws2p-v1-legacy/Cargo.toml b/lib/modules/ws2p-v1-legacy/Cargo.toml
index 30909adc..e4aba182 100644
--- a/lib/modules/ws2p-v1-legacy/Cargo.toml
+++ b/lib/modules/ws2p-v1-legacy/Cargo.toml
@@ -7,7 +7,7 @@ license = "AGPL-3.0"
 edition = "2018"
 
 [lib]
-path = "lib.rs"
+path = "src/lib.rs"
 
 [dependencies]
 byteorder = "1.2.3"
diff --git a/lib/modules/ws2p-v1-legacy/ack_message.rs b/lib/modules/ws2p-v1-legacy/src/ack_message.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/ack_message.rs
rename to lib/modules/ws2p-v1-legacy/src/ack_message.rs
diff --git a/lib/modules/ws2p-v1-legacy/connect_message.rs b/lib/modules/ws2p-v1-legacy/src/connect_message.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/connect_message.rs
rename to lib/modules/ws2p-v1-legacy/src/connect_message.rs
diff --git a/lib/modules/ws2p-v1-legacy/constants.rs b/lib/modules/ws2p-v1-legacy/src/constants.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/constants.rs
rename to lib/modules/ws2p-v1-legacy/src/constants.rs
diff --git a/lib/modules/ws2p-v1-legacy/datas.rs b/lib/modules/ws2p-v1-legacy/src/datas.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/datas.rs
rename to lib/modules/ws2p-v1-legacy/src/datas.rs
diff --git a/lib/modules/ws2p-v1-legacy/heads.rs b/lib/modules/ws2p-v1-legacy/src/heads.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/heads.rs
rename to lib/modules/ws2p-v1-legacy/src/heads.rs
diff --git a/lib/modules/ws2p-v1-legacy/lib.rs b/lib/modules/ws2p-v1-legacy/src/lib.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/lib.rs
rename to lib/modules/ws2p-v1-legacy/src/lib.rs
diff --git a/lib/modules/ws2p-v1-legacy/ok_message.rs b/lib/modules/ws2p-v1-legacy/src/ok_message.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/ok_message.rs
rename to lib/modules/ws2p-v1-legacy/src/ok_message.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/blocks.rs b/lib/modules/ws2p-v1-legacy/src/parsers/blocks.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/blocks.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/blocks.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/excluded.rs b/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/excluded.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/identities.rs b/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/identities.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/memberships.rs b/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/memberships.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/mod.rs b/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/mod.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/transactions.rs b/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/transactions.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
diff --git a/lib/modules/ws2p-v1-legacy/serializer.rs b/lib/modules/ws2p-v1-legacy/src/serializer.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/serializer.rs
rename to lib/modules/ws2p-v1-legacy/src/serializer.rs
diff --git a/lib/modules/ws2p-v1-legacy/ws2p_connection.rs b/lib/modules/ws2p-v1-legacy/src/ws2p_connection.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/ws2p_connection.rs
rename to lib/modules/ws2p-v1-legacy/src/ws2p_connection.rs
diff --git a/lib/modules/ws2p-v1-legacy/ws2p_db.rs b/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/ws2p_db.rs
rename to lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
diff --git a/lib/modules/ws2p-v1-legacy/ws2p_requests.rs b/lib/modules/ws2p-v1-legacy/src/ws2p_requests.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/ws2p_requests.rs
rename to lib/modules/ws2p-v1-legacy/src/ws2p_requests.rs
-- 
GitLab


From cea0216b5701a0418ae10850bde37980a8041588 Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Thu, 25 Apr 2019 00:53:11 +0200
Subject: [PATCH 2/5] [feat] common-tools: add fn read & write binary file

---
 lib/tools/common-tools/src/lib.rs | 44 +++++++++++++++++++++++++------
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/lib/tools/common-tools/src/lib.rs b/lib/tools/common-tools/src/lib.rs
index f726482e..be0eee5c 100644
--- a/lib/tools/common-tools/src/lib.rs
+++ b/lib/tools/common-tools/src/lib.rs
@@ -26,6 +26,13 @@
     unused_import_braces
 )]
 
+use std::fs::File;
+use std::io::Read;
+use std::io::Write;
+use std::path::Path;
+use std::time::SystemTime;
+use std::time::UNIX_EPOCH;
+
 /// Interrupts the program and log error message
 /// WARNING: this macro must not be called before the logger is initialized !
 #[macro_export]
@@ -44,14 +51,35 @@ macro_rules! fatal_error {
     });
 }
 
-/*macro_rules! error {
-    (target: $target:expr, $($arg:tt)+) => (
-        log!(target: $target, $crate::Level::Error, $($arg)+);
-    );
-    ($($arg:tt)+) => (
-        log!($crate::Level::Error, $($arg)+);
-    )
-}*/
+#[inline]
+/// Get current timestamp in seconds
+pub fn current_timestamp() -> u64 {
+    SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .expect("SystemTime::duration_since failed")
+        .as_secs()
+}
+
+/// Read bin file
+pub fn read_bin_file(file_path: &Path) -> Result<Vec<u8>, std::io::Error> {
+    let mut file = File::open(file_path)?;
+    if file.metadata()?.len() == 0 {
+        Ok(vec![])
+    } else {
+        let mut bin_datas = Vec::new();
+        file.read_to_end(&mut bin_datas)?;
+
+        Ok(bin_datas)
+    }
+}
+
+/// Write bin file
+pub fn write_bin_file(file_path: &Path, datas: &[u8]) -> Result<(), std::io::Error> {
+    let mut file = File::create(file_path)?;
+    file.write_all(&datas[..])?;
+
+    Ok(())
+}
 
 /// Unescape backslash
 pub fn unescape_str(source: &str) -> String {
-- 
GitLab


From c0ad94390555672cb038bdccce17b113f319daef Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Thu, 25 Apr 2019 00:54:34 +0200
Subject: [PATCH 3/5] [ref] network-documents: use new serde derive way

---
 lib/tools/network-documents/Cargo.toml             | 3 +--
 lib/tools/network-documents/src/lib.rs             | 5 ++---
 lib/tools/network-documents/src/network_head.rs    | 1 +
 lib/tools/network-documents/src/network_head_v2.rs | 1 +
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/tools/network-documents/Cargo.toml b/lib/tools/network-documents/Cargo.toml
index d53595f8..f218c133 100644
--- a/lib/tools/network-documents/Cargo.toml
+++ b/lib/tools/network-documents/Cargo.toml
@@ -18,8 +18,7 @@ dubp-documents= { path = "../documents" }
 hex = "0.3.*"
 pest = "2.1.0"
 pest_derive = "2.1.0"
-serde = "1.0.*"
-serde_derive = "1.0.*"
+serde = { version = "1.0.*", features = ["derive"] }
 serde_json = "1.0.*"
 
 [dev-dependencies]
diff --git a/lib/tools/network-documents/src/lib.rs b/lib/tools/network-documents/src/lib.rs
index dd95a0f3..a5eeec12 100644
--- a/lib/tools/network-documents/src/lib.rs
+++ b/lib/tools/network-documents/src/lib.rs
@@ -30,8 +30,6 @@ extern crate pest_derive;
 #[cfg(test)]
 #[macro_use]
 extern crate pretty_assertions;
-#[macro_use]
-extern crate serde_derive;
 
 pub mod network_endpoint;
 pub mod network_head;
@@ -48,6 +46,7 @@ use dup_crypto::hashs::*;
 use dup_crypto::keys::*;
 use pest::iterators::Pair;
 use pest::Parser;
+use serde::{Deserialize, Serialize};
 use std::fmt::{Display, Error, Formatter};
 
 #[derive(Parser)]
@@ -116,7 +115,7 @@ impl<'a> From<&'a str> for NodeId {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 /// Complete identifier of a duniter node.
 pub struct NodeFullId(pub NodeId, pub PubKey);
 
diff --git a/lib/tools/network-documents/src/network_head.rs b/lib/tools/network-documents/src/network_head.rs
index b3d50090..fddce933 100644
--- a/lib/tools/network-documents/src/network_head.rs
+++ b/lib/tools/network-documents/src/network_head.rs
@@ -21,6 +21,7 @@ use crate::{NodeFullId, NodeId};
 use dubp_documents::blockstamp::*;
 use dup_crypto::bases::BaseConvertionError;
 use dup_crypto::keys::*;
+use serde::{Deserialize, Serialize};
 use serde_json;
 use std::collections::HashMap;
 use std::num::ParseIntError;
diff --git a/lib/tools/network-documents/src/network_head_v2.rs b/lib/tools/network-documents/src/network_head_v2.rs
index f8e8b596..cd113c9f 100644
--- a/lib/tools/network-documents/src/network_head_v2.rs
+++ b/lib/tools/network-documents/src/network_head_v2.rs
@@ -19,6 +19,7 @@ use crate::NodeId;
 use dubp_documents::blockstamp::*;
 use dup_crypto::bases::BaseConvertionError;
 use dup_crypto::keys::*;
+use serde::{Deserialize, Serialize};
 use std::cmp::Ordering;
 use std::num::ParseIntError;
 use std::ops::Deref;
-- 
GitLab


From c544ba13f02e9e408def849a789bbc7f1aea22ed Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Thu, 25 Apr 2019 00:55:46 +0200
Subject: [PATCH 4/5] [ref+feat] ws2p1: deep ref whole crate + migrate sqlite
 -> bin file

---
 lib/modules/ws2p-v1-legacy/Cargo.toml         |  15 +-
 lib/modules/ws2p-v1-legacy/clippy.toml        |   2 +-
 lib/modules/ws2p-v1-legacy/src/ack_message.rs |  28 +-
 .../ws2p-v1-legacy/src/connect_message.rs     |  31 +-
 lib/modules/ws2p-v1-legacy/src/constants.rs   |  47 +-
 lib/modules/ws2p-v1-legacy/src/datas.rs       | 491 ---------
 lib/modules/ws2p-v1-legacy/src/events/mod.rs  |  19 +
 .../ws2p-v1-legacy/src/events/received.rs     |  72 ++
 lib/modules/ws2p-v1-legacy/src/events/sent.rs |  59 ++
 lib/modules/ws2p-v1-legacy/src/lib.rs         | 956 ++++++++----------
 lib/modules/ws2p-v1-legacy/src/ok_message.rs  |  34 +-
 .../ws2p-v1-legacy/src/parsers/excluded.rs    |  15 +-
 .../ws2p-v1-legacy/src/parsers/identities.rs  |  19 +-
 .../ws2p-v1-legacy/src/parsers/memberships.rs |  22 +-
 lib/modules/ws2p-v1-legacy/src/parsers/mod.rs |  58 +-
 .../src/parsers/transactions.rs               |  25 +-
 .../ws2p-v1-legacy/src/requests/mod.rs        |  19 +
 .../ws2p-v1-legacy/src/requests/received.rs   |  66 ++
 .../ws2p-v1-legacy/src/requests/sent.rs       |  37 +
 .../ws2p-v1-legacy/src/responses/mod.rs       |  19 +
 .../ws2p-v1-legacy/src/responses/received.rs  |  16 +
 .../ws2p-v1-legacy/src/responses/sent.rs      |  36 +
 lib/modules/ws2p-v1-legacy/src/ws2p_db.rs     | 157 ++-
 .../ws2p-v1-legacy/src/ws2p_requests.rs       |  37 -
 .../src/ws_connections/handler.rs             | 241 +++++
 .../src/ws_connections/messages.rs            | 291 ++++++
 .../meta_datas.rs}                            | 406 +-------
 .../ws2p-v1-legacy/src/ws_connections/mod.rs  | 184 ++++
 .../src/ws_connections/requests/mod.rs        |  19 +
 .../src/ws_connections/requests/received.rs   |   1 +
 .../src/ws_connections/requests/sent.rs       |  77 ++
 .../src/ws_connections/states.rs              |  76 ++
 32 files changed, 1929 insertions(+), 1646 deletions(-)
 delete mode 100644 lib/modules/ws2p-v1-legacy/src/datas.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/events/mod.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/events/received.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/events/sent.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/requests/mod.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/requests/received.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/requests/sent.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/responses/mod.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/responses/received.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/responses/sent.rs
 delete mode 100644 lib/modules/ws2p-v1-legacy/src/ws2p_requests.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs
 rename lib/modules/ws2p-v1-legacy/src/{ws2p_connection.rs => ws_connections/meta_datas.rs} (52%)
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/requests/mod.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/requests/received.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/requests/sent.rs
 create mode 100644 lib/modules/ws2p-v1-legacy/src/ws_connections/states.rs

diff --git a/lib/modules/ws2p-v1-legacy/Cargo.toml b/lib/modules/ws2p-v1-legacy/Cargo.toml
index e4aba182..6b2f9788 100644
--- a/lib/modules/ws2p-v1-legacy/Cargo.toml
+++ b/lib/modules/ws2p-v1-legacy/Cargo.toml
@@ -10,23 +10,24 @@ edition = "2018"
 path = "src/lib.rs"
 
 [dependencies]
+bincode = "1.0.1"
 byteorder = "1.2.3"
+dubp-documents= { path = "../../tools/documents" }
 duniter-conf = { path = "../../core/conf" }
+duniter-module = { path = "../../core/module" }
+duniter-network = { path = "../../core/network" }
 dup-crypto = { path = "../../tools/crypto" }
-dubp-documents= { path = "../../tools/documents" }
 durs-network-documents = { path = "../../tools/network-documents" }
 durs-message =  { path = "../../core/message" }
-duniter-module = { path = "../../core/module" }
-duniter-network = { path = "../../core/network" }
+durs-common-tools = { path = "../../tools/common-tools" }
 durs-wot = { path = "../../tools/wot" }
 log = "0.4.*"
 rand = "0.4.*"
-sqlite = "0.23.*"
-serde = "1.0.*"
-serde_derive = "1.0.*"
+serde = { version = "1.0.*", features = ["derive"] }
 serde_json = "1.0.*"
 structopt= "0.2.*"
-ws = { version = "0.7.*", features = ["permessage-deflate"] }
+unwrap = "1.2.1"
+ws = "0.7.*"
 
 [features]
 ssl = ["ws/ssl"]
\ No newline at end of file
diff --git a/lib/modules/ws2p-v1-legacy/clippy.toml b/lib/modules/ws2p-v1-legacy/clippy.toml
index 05bd01e1..fbfe7d8a 100644
--- a/lib/modules/ws2p-v1-legacy/clippy.toml
+++ b/lib/modules/ws2p-v1-legacy/clippy.toml
@@ -1 +1 @@
-cyclomatic-complexity-threshold = 77
\ No newline at end of file
+cyclomatic-complexity-threshold = 51
\ No newline at end of file
diff --git a/lib/modules/ws2p-v1-legacy/src/ack_message.rs b/lib/modules/ws2p-v1-legacy/src/ack_message.rs
index e1fcdeed..f18bf55e 100644
--- a/lib/modules/ws2p-v1-legacy/src/ack_message.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ack_message.rs
@@ -1,4 +1,4 @@
-use super::WS2PMessage;
+use crate::*;
 use dup_crypto::keys::*;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
@@ -11,20 +11,19 @@ pub struct WS2PAckMessageV1 {
 }
 
 impl WS2PMessage for WS2PAckMessageV1 {
-    fn parse(v: &serde_json::Value, currency: String) -> Option<Self> {
+    fn parse(v: &serde_json::Value, currency: String) -> Result<Self, WS2PMsgParseErr> {
         let pubkey = match v.get("pub") {
-            Some(pubkey) => pubkey.as_str().unwrap().to_string(),
-            None => return None,
+            Some(pubkey) => pubkey.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+            None => return Err(WS2PMsgParseErr {}),
         };
         let signature = match v.get("sig") {
-            Some(signature) => signature.as_str().unwrap().to_string(),
-            None => return None,
+            Some(signature) => signature.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+            None => return Err(WS2PMsgParseErr {}),
         };
-        let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey).unwrap());
-        let signature: Option<Sig> = Some(Sig::Ed25519(
-            ed25519::Signature::from_base64(&signature).unwrap(),
-        ));
-        Some(WS2PAckMessageV1 {
+        let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey)?);
+        let signature: Option<Sig> =
+            Some(Sig::Ed25519(ed25519::Signature::from_base64(&signature)?));
+        Ok(WS2PAckMessageV1 {
             currency,
             pubkey,
             challenge: "".to_string(),
@@ -38,8 +37,11 @@ impl WS2PMessage for WS2PAckMessageV1 {
         )
     }
     fn verify(&self) -> bool {
-        self.pubkey
-            .verify(self.to_raw().as_bytes(), &self.signature.unwrap())
+        if let Some(sig) = self.signature {
+            self.pubkey.verify(self.to_raw().as_bytes(), &sig)
+        } else {
+            false
+        }
     }
 }
 
diff --git a/lib/modules/ws2p-v1-legacy/src/connect_message.rs b/lib/modules/ws2p-v1-legacy/src/connect_message.rs
index 1f917ade..e229cc1d 100644
--- a/lib/modules/ws2p-v1-legacy/src/connect_message.rs
+++ b/lib/modules/ws2p-v1-legacy/src/connect_message.rs
@@ -1,4 +1,4 @@
-use super::WS2PMessage;
+use crate::*;
 use dup_crypto::keys::*;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
@@ -11,24 +11,22 @@ pub struct WS2PConnectMessageV1 {
 }
 
 impl WS2PMessage for WS2PConnectMessageV1 {
-    fn parse(v: &serde_json::Value, currency: String) -> Option<Self> {
+    fn parse(v: &serde_json::Value, currency: String) -> Result<Self, WS2PMsgParseErr> {
         let pubkey = match v.get("pub") {
-            Some(pubkey) => pubkey.as_str().unwrap().to_string(),
-            None => return None,
+            Some(pubkey) => pubkey.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+            None => return Err(WS2PMsgParseErr {}),
         };
         let challenge = match v.get("challenge") {
-            Some(challenge) => challenge.as_str().unwrap().to_string(),
-            None => return None,
+            Some(challenge) => challenge.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+            None => return Err(WS2PMsgParseErr {}),
         };
         let signature = match v.get("sig") {
-            Some(signature) => signature.as_str().unwrap().to_string(),
-            None => return None,
+            Some(signature) => signature.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+            None => return Err(WS2PMsgParseErr {}),
         };
-        let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey).unwrap());
-        let signature = Some(Sig::Ed25519(
-            ed25519::Signature::from_base64(&signature).unwrap(),
-        ));
-        Some(WS2PConnectMessageV1 {
+        let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey)?);
+        let signature = Some(Sig::Ed25519(ed25519::Signature::from_base64(&signature)?));
+        Ok(WS2PConnectMessageV1 {
             currency,
             pubkey,
             challenge,
@@ -42,8 +40,11 @@ impl WS2PMessage for WS2PConnectMessageV1 {
         )
     }
     fn verify(&self) -> bool {
-        self.pubkey
-            .verify(self.to_raw().as_bytes(), &self.signature.unwrap())
+        if let Some(sig) = self.signature {
+            self.pubkey.verify(self.to_raw().as_bytes(), &sig)
+        } else {
+            false
+        }
     }
 }
 
diff --git a/lib/modules/ws2p-v1-legacy/src/constants.rs b/lib/modules/ws2p-v1-legacy/src/constants.rs
index aaada76d..cdc14af7 100644
--- a/lib/modules/ws2p-v1-legacy/src/constants.rs
+++ b/lib/modules/ws2p-v1-legacy/src/constants.rs
@@ -1,12 +1,55 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! WS2Pv1 constants
+
+/// API Name
+pub static WS2P_API: &'static str = "WS2P";
+
+/// Interval between to sequence of general actions
+pub static WS2P_GENERAL_STATE_INTERVAL: &'static u64 = &15;
+
+/// Connection wave interval at startup
 pub static WS2P_OUTCOMING_INTERVAL_AT_STARTUP: &'static u64 = &75;
+
+/// Interval of connection waves after the start-up phase
 pub static WS2P_OUTCOMING_INTERVAL: &'static u64 = &300;
+
+/// Default outgoing connection quota
 pub static WS2P_DEFAULT_OUTCOMING_QUOTA: &'static usize = &10;
+
+/// Maximum duration of a connection negotiation
 pub static WS2P_NEGOTIATION_TIMEOUT: &'static u64 = &15;
+
+/// Maximum waiting time for a response to a request
 //pub static WS2P_REQUEST_TIMEOUT : &'static u64 = &30;
+
+/// Maximum duration of inactivity of a connection (the connection will be closed after this delay)
 pub static WS2P_EXPIRE_TIMEOUT: &'static u64 = &120;
+
+/// Interval between 2 messages from which it''s perhaps a spam (in milliseconds)
 pub static WS2P_SPAM_INTERVAL_IN_MILLI_SECS: &'static u64 = &80;
+
+/// Number of consecutive closed messages from which messages will be considered as spam.
 pub static WS2P_SPAM_LIMIT: &'static usize = &6;
+
+/// Rest time in a situation of proven spam
 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;
+
+/// Duration between 2 endpoints saving
+pub static DURATION_BETWEEN_2_ENDPOINTS_SAVING: &'static u64 = &180;
+
+/// Duration between 2 requests from the pool of the wot data
 pub static PENDING_IDENTITIES_REQUEST_INTERVAL: &'static u64 = &40;
diff --git a/lib/modules/ws2p-v1-legacy/src/datas.rs b/lib/modules/ws2p-v1-legacy/src/datas.rs
deleted file mode 100644
index 89968a51..00000000
--- a/lib/modules/ws2p-v1-legacy/src/datas.rs
+++ /dev/null
@@ -1,491 +0,0 @@
-//  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 crate::*;
-use dup_crypto::keys::*;
-use durs_message::requests::BlockchainRequest;
-use durs_message::*;
-use durs_network_documents::network_endpoint::*;
-use durs_network_documents::network_head::*;
-use durs_network_documents::*;
-use std::collections::HashSet;
-use std::sync::mpsc;
-
-#[derive(Debug)]
-pub struct WS2PModuleDatas {
-    pub router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
-    pub currency: Option<String>,
-    pub key_pair: Option<KeyPairEnum>,
-    pub conf: WS2PConf,
-    pub ssl: bool,
-    pub node_id: NodeId,
-    pub main_thread_channel: (
-        mpsc::Sender<WS2PThreadSignal>,
-        mpsc::Receiver<WS2PThreadSignal>,
-    ),
-    pub ws2p_endpoints: HashMap<NodeFullId, (EndpointV1, WS2PConnectionState)>,
-    pub websockets: HashMap<NodeFullId, WsSender>,
-    pub requests_awaiting_response:
-        HashMap<ModuleReqId, (OldNetworkRequest, NodeFullId, SystemTime)>,
-    pub heads_cache: HashMap<NodeFullId, NetworkHead>,
-    pub my_head: Option<NetworkHead>,
-    pub uids_cache: HashMap<PubKey, String>,
-    pub count_dal_requests: u32,
-}
-
-#[inline]
-#[cfg(not(feature = "ssl"))]
-fn ssl() -> bool {
-    false
-}
-#[cfg(feature = "ssl")]
-fn ssl() -> bool {
-    true
-}
-
-impl WS2PModuleDatas {
-    pub fn new(
-        router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
-        conf: WS2PConf,
-        node_id: NodeId,
-    ) -> WS2PModuleDatas {
-        WS2PModuleDatas {
-            router_sender,
-            key_pair: None,
-            currency: None,
-            conf,
-            ssl: ssl(),
-            node_id,
-            main_thread_channel: mpsc::channel(),
-            ws2p_endpoints: HashMap::new(),
-            websockets: HashMap::new(),
-            requests_awaiting_response: HashMap::new(),
-            heads_cache: HashMap::new(),
-            my_head: None,
-            uids_cache: HashMap::new(),
-            count_dal_requests: 0,
-        }
-    }
-    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 send_dal_request(&mut self, req: &BlockchainRequest) {
-        self.count_dal_requests += 1;
-        if self.count_dal_requests == std::u32::MAX {
-            self.count_dal_requests = 0;
-        }
-        self.router_sender
-            .send(RouterThreadMessage::ModuleMessage(DursMsg::Request {
-                req_from: WS2PModule::name(),
-                req_to: ModuleRole::BlockchainDatas,
-                req_id: ModuleReqId(self.count_dal_requests),
-                req_content: DursReqContent::BlockchainRequest(req.clone()),
-            }))
-            .expect("Fail to send message to router !");
-    }
-    pub fn send_network_req_response(
-        &self,
-        requester: ModuleStaticName,
-        req_id: ModuleReqId,
-        response: NetworkResponse,
-    ) {
-        self.router_sender
-            .send(RouterThreadMessage::ModuleMessage(DursMsg::Response {
-                res_from: WS2PModule::name(),
-                res_to: requester,
-                req_id,
-                res_content: DursResContent::NetworkResponse(response),
-            }))
-            .expect("Fail to send message to router !");
-    }
-    pub fn send_network_event(&self, event: &NetworkEvent) {
-        let module_event = match event {
-            NetworkEvent::ConnectionStateChange(_, _, _, _) => {
-                ModuleEvent::ConnectionsChangeNodeNetwork
-            }
-            NetworkEvent::ReceiveBlocks(_) => ModuleEvent::NewBlockFromNetwork,
-            NetworkEvent::ReceiveDocuments(network_docs) => {
-                if !network_docs.is_empty() {
-                    match network_docs[0] {
-                        BlockchainDocument::Block(_) => ModuleEvent::NewBlockFromNetwork,
-                        BlockchainDocument::Transaction(_) => ModuleEvent::NewTxFromNetwork,
-                        _ => ModuleEvent::NewWotDocFromNetwork,
-                    }
-                } else {
-                    return;
-                }
-            }
-            NetworkEvent::ReceiveHeads(_) => ModuleEvent::NewValidHeadFromNetwork,
-            NetworkEvent::ReceivePeers(_) => ModuleEvent::NewValidPeerFromNodeNetwork,
-            NetworkEvent::NewSelfPeer(_) => ModuleEvent::NewSelfPeer,
-        };
-        self.router_sender
-            .send(RouterThreadMessage::ModuleMessage(DursMsg::Event {
-                event_type: module_event,
-                event_content: DursEvent::NetworkEvent(event.clone()),
-            }))
-            .expect("Fail to send network event to router !");
-    }
-    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 pubkeys = HashSet::new();
-        let mut reachable_endpoints = Vec::new();
-        let mut unreachable_endpoints = Vec::new();
-        for (_ws2p_full_id, (ep, state)) in self.ws2p_endpoints.clone() {
-            if ep.issuer == self.key_pair.unwrap().public_key() || !pubkeys.contains(&ep.issuer) {
-                match state {
-                    WS2PConnectionState::Established => count_established_connections += 1,
-                    WS2PConnectionState::NeverTry
-                    | WS2PConnectionState::Close
-                    | WS2PConnectionState::Denial => {
-                        pubkeys.insert(ep.issuer);
-                        reachable_endpoints.push(ep);
-                    }
-                    _ => {
-                        pubkeys.insert(ep.issuer);
-                        unreachable_endpoints.push(ep);
-                    }
-                }
-            }
-        }
-        let mut free_outcoming_rooms =
-            self.conf.clone().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 !self.ssl && ep.port == 443 {
-                continue;
-            }
-            self.connect_to_without_checking_quotas(&ep);
-            free_outcoming_rooms -= 1;
-        }
-    }
-    pub fn connect_to(&mut self, endpoint: &EndpointV1) {
-        // 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().outcoming_quota > self.count_established_connections() {
-            self.connect_to_without_checking_quotas(&endpoint);
-        }
-    }
-    pub fn close_connection(
-        &mut self,
-        ws2p_full_id: &NodeFullId,
-        reason: WS2PCloseConnectionReason,
-    ) {
-        match reason {
-            WS2PCloseConnectionReason::NegociationTimeout => {}
-            WS2PCloseConnectionReason::AuthMessInvalidSig
-            | WS2PCloseConnectionReason::Timeout
-            | WS2PCloseConnectionReason::WsError
-            | WS2PCloseConnectionReason::Unknow => {
-                self.ws2p_endpoints
-                    .get_mut(ws2p_full_id)
-                    .expect("Failure : attempt to delete a non-existent connection !")
-                    .1 = WS2PConnectionState::Close
-            }
-        }
-        if let Some(websocket) = self.websockets.get(&ws2p_full_id) {
-            let _result = websocket.0.close(ws::CloseCode::Normal);
-        }
-        let _result = self.websockets.remove(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);
-                if let Some(websocket) = self.websockets.get_mut(&ws2p_full_id) {
-                    if websocket.0.send(Message::text(response)).is_err() {
-                        return WS2PSignal::WSError(ws2p_full_id);
-                    }
-                } else {
-                    // Connection closed by remote peer
-                    self.ws2p_endpoints
-                        .get_mut(&ws2p_full_id)
-                        .expect("Endpoint don't exist !")
-                        .1 = WS2PConnectionState::Close;
-                }
-            }
-            WS2PConnectionMessagePayload::ValidAckMessage(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::AckMessOk = self.ws2p_endpoints[&ws2p_full_id].1 {
-                    debug!("Send: {:#?}", response);
-                    if let Some(websocket) = self.websockets.get_mut(&ws2p_full_id) {
-                        if websocket.0.send(Message::text(response)).is_err() {
-                            return WS2PSignal::WSError(ws2p_full_id);
-                        }
-                    } else {
-                        panic!("Fatal error : no websocket for {} !", ws2p_full_id);
-                    }
-                }
-            }
-            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 Ok(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 : {:?} (sent to {:?})", req, ws2p_full_id);
-            }
-        }
-        // 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_specific_node(
-        &mut self,
-        receiver_ws2p_full_id: &NodeFullId,
-        ws2p_request: &OldNetworkRequest,
-    ) -> 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: &EndpointV1) {
-        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,
-                &currency_copy.expect("WS2PError : No currency !"),
-                key_pair_copy.expect("WS2PError : No key_pair !"),
-            );
-        });
-    }
-}
diff --git a/lib/modules/ws2p-v1-legacy/src/events/mod.rs b/lib/modules/ws2p-v1-legacy/src/events/mod.rs
new file mode 100644
index 00000000..0e373125
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/events/mod.rs
@@ -0,0 +1,19 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the events received and sent.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/events/received.rs b/lib/modules/ws2p-v1-legacy/src/events/received.rs
new file mode 100644
index 00000000..a8bb4f27
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/events/received.rs
@@ -0,0 +1,72 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing events received from other durs modules
+
+use crate::*;
+use dubp_documents::Document;
+use duniter_module::*;
+use durs_message::events::DursEvent;
+use std::ops::Deref;
+
+pub fn receive_event(
+    ws2p_module: &mut WS2PModule,
+    _event_type: ModuleEvent,
+    event_content: &DursEvent,
+) {
+    if let DursEvent::BlockchainEvent(ref bc_event) = *event_content {
+        match *bc_event.deref() {
+            BlockchainEvent::StackUpValidBlock(ref block) => {
+                ws2p_module.current_blockstamp = block.deref().blockstamp();
+                debug!(
+                    "WS2PModule : current_blockstamp = {}",
+                    ws2p_module.current_blockstamp
+                );
+                ws2p_module.my_head = Some(heads::generate_my_head(
+                    &ws2p_module.key_pair,
+                    ws2p_module.node_id,
+                    ws2p_module.soft_name,
+                    ws2p_module.soft_version,
+                    &ws2p_module.current_blockstamp,
+                    None,
+                ));
+                super::sent::send_network_event(
+                    ws2p_module,
+                    NetworkEvent::ReceiveHeads(vec![unwrap!(ws2p_module.my_head.clone())]),
+                );
+                // Send my head to all connections
+                let my_json_head = serializer::serialize_head(unwrap!(ws2p_module.my_head.clone()));
+                trace!("Send my HEAD: {:#?}", my_json_head);
+                let _results: Result<(), ws::Error> = ws2p_module
+                    .websockets
+                    .iter_mut()
+                    .map(|ws| {
+                        (ws.1).0.send(Message::text(
+                            json!({
+                                "name": "HEAD",
+                                "body": {
+                                    "heads": [my_json_head]
+                                }
+                            })
+                            .to_string(),
+                        ))
+                    })
+                    .collect();
+            }
+            BlockchainEvent::RevertBlocks(ref _blocks) => {}
+            _ => {}
+        }
+    }
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/events/sent.rs b/lib/modules/ws2p-v1-legacy/src/events/sent.rs
new file mode 100644
index 00000000..bb5a49b6
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/events/sent.rs
@@ -0,0 +1,59 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the events emitted by the blockchain module.
+
+use crate::WS2PModule;
+use duniter_module::{ModuleEvent, RouterThreadMessage};
+use duniter_network::documents::BlockchainDocument;
+use duniter_network::events::NetworkEvent;
+use durs_message::events::DursEvent;
+use durs_message::*;
+
+pub fn send_network_events(ws2p_module: &mut WS2PModule, events: Vec<NetworkEvent>) {
+    for event in events {
+        send_network_event(ws2p_module, event);
+    }
+}
+
+pub fn send_network_event(ws2p_module: &mut WS2PModule, event: NetworkEvent) {
+    let module_event = match event {
+        NetworkEvent::ConnectionStateChange(_, _, _, _) => {
+            ModuleEvent::ConnectionsChangeNodeNetwork
+        }
+        NetworkEvent::ReceiveBlocks(_) => ModuleEvent::NewBlockFromNetwork,
+        NetworkEvent::ReceiveDocuments(ref network_docs) => {
+            if !network_docs.is_empty() {
+                match network_docs[0] {
+                    BlockchainDocument::Block(_) => ModuleEvent::NewBlockFromNetwork,
+                    BlockchainDocument::Transaction(_) => ModuleEvent::NewTxFromNetwork,
+                    _ => ModuleEvent::NewWotDocFromNetwork,
+                }
+            } else {
+                return;
+            }
+        }
+        NetworkEvent::ReceiveHeads(_) => ModuleEvent::NewValidHeadFromNetwork,
+        NetworkEvent::ReceivePeers(_) => ModuleEvent::NewValidPeerFromNodeNetwork,
+        NetworkEvent::NewSelfPeer(_) => ModuleEvent::NewSelfPeer,
+    };
+    ws2p_module
+        .router_sender
+        .send(RouterThreadMessage::ModuleMessage(DursMsg::Event {
+            event_type: module_event,
+            event_content: DursEvent::NetworkEvent(event),
+        }))
+        .expect("Fail to send network event to router !");
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/lib.rs b/lib/modules/ws2p-v1-legacy/src/lib.rs
index a3e7663e..c19854b3 100644
--- a/lib/modules/ws2p-v1-legacy/src/lib.rs
+++ b/lib/modules/ws2p-v1-legacy/src/lib.rs
@@ -1,4 +1,4 @@
-//  Copyright (C) 2018  The Duniter Project Developers.
+//  Copyright (C) 2018  The Durs 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
@@ -13,7 +13,7 @@
 // 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/>.
 
-//! WebSocketToPeer API for the Duniter project.
+//! WebSocketToPeer API for the Durs project.
 
 #![deny(
     missing_debug_implementations,
@@ -29,8 +29,6 @@
 #[macro_use]
 extern crate log;
 #[macro_use]
-extern crate serde_derive;
-#[macro_use]
 extern crate serde_json;
 #[macro_use]
 extern crate structopt;
@@ -38,24 +36,27 @@ extern crate structopt;
 mod ack_message;
 mod connect_message;
 pub mod constants;
-mod datas;
+mod events;
 mod heads;
 mod ok_message;
 pub mod parsers;
+mod requests;
+mod responses;
 pub mod serializer;
-pub mod ws2p_connection;
 pub mod ws2p_db;
-pub mod ws2p_requests;
+pub mod ws_connections;
 
 use crate::ack_message::WS2PAckMessageV1;
 use crate::connect_message::WS2PConnectMessageV1;
 use crate::constants::*;
-use crate::datas::*;
 use crate::ok_message::WS2POkMessageV1;
 use crate::parsers::blocks::parse_json_block;
-use crate::ws2p_connection::*;
-use crate::ws2p_requests::network_request_to_json;
-use dubp_documents::{Blockstamp, Document};
+use crate::requests::sent::send_dal_request;
+use crate::ws2p_db::DbEndpoint;
+use crate::ws_connections::messages::WS2PConnectionMessage;
+use crate::ws_connections::states::WS2PConnectionState;
+use crate::ws_connections::*;
+use dubp_documents::Blockstamp;
 use duniter_conf::DuRsConf;
 use duniter_module::*;
 use duniter_network::cli::sync::SyncOpt;
@@ -64,6 +65,7 @@ use duniter_network::events::*;
 use duniter_network::requests::*;
 use duniter_network::*;
 use dup_crypto::keys::*;
+use durs_common_tools::fatal_error;
 use durs_message::events::*;
 use durs_message::requests::*;
 use durs_message::responses::*;
@@ -71,14 +73,28 @@ use durs_message::*;
 use durs_network_documents::network_endpoint::*;
 use durs_network_documents::network_head::*;
 use durs_network_documents::*;
+use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
+use std::fs;
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::mpsc;
 use std::thread;
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
+use unwrap::unwrap;
 use ws::Message;
 
+#[inline]
+#[cfg(not(feature = "ssl"))]
+pub fn ssl() -> bool {
+    false
+}
+#[inline]
+#[cfg(feature = "ssl")]
+pub fn ssl() -> bool {
+    true
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
 /// WS2P Configuration
 pub struct WS2PConf {
@@ -93,54 +109,38 @@ impl Default for WS2PConf {
         WS2PConf {
             outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA,
             sync_endpoints: vec![
-                EndpointV1::parse_from_raw(
+                unwrap!(EndpointV1::parse_from_raw(
                     "WS2P c1c39a0a ts.g1.librelois.fr 443 /ws2p",
-                    PubKey::Ed25519(
-                        ed25519::PublicKey::from_base58(
-                            "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
-                        )
-                        .unwrap(),
-                    ),
+                    PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                        "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
+                    )),),
                     0,
                     0,
-                )
-                .unwrap(),
-                EndpointV1::parse_from_raw(
+                )),
+                unwrap!(EndpointV1::parse_from_raw(
                     "WS2P fb17fcd4 g1.duniter.fr 443 /ws2p",
-                    PubKey::Ed25519(
-                        ed25519::PublicKey::from_base58(
-                            "38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE",
-                        )
-                        .unwrap(),
-                    ),
+                    PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                        "38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE",
+                    ))),
                     0,
                     0,
-                )
-                .unwrap(),
-                EndpointV1::parse_from_raw(
+                )),
+                unwrap!(EndpointV1::parse_from_raw(
                     "WS2P 7b33becd g1.nordstrom.duniter.org 443 /ws2p",
-                    PubKey::Ed25519(
-                        ed25519::PublicKey::from_base58(
-                            "DWoSCRLQyQ48dLxUGr1MDKg4NFcbPbC56LN2hJjCCPpZ",
-                        )
-                        .unwrap(),
-                    ),
+                    PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                        "DWoSCRLQyQ48dLxUGr1MDKg4NFcbPbC56LN2hJjCCPpZ",
+                    ))),
                     0,
                     0,
-                )
-                .unwrap(),
-                EndpointV1::parse_from_raw(
+                )),
+                unwrap!(EndpointV1::parse_from_raw(
                     "WS2P dff60418 duniter.normandie-libre.fr 443 /ws2p",
-                    PubKey::Ed25519(
-                        ed25519::PublicKey::from_base58(
-                            "8t6Di3pLxxoTEfjXHjF49pNpjSTXuGEQ6BpkT75CkNb2",
-                        )
-                        .unwrap(),
-                    ),
+                    PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                        "8t6Di3pLxxoTEfjXHjF49pNpjSTXuGEQ6BpkT75CkNb2",
+                    ))),
                     0,
                     0,
-                )
-                .unwrap(),
+                )),
             ],
         }
     }
@@ -181,8 +181,64 @@ pub enum SendRequestError {
     WSError(usize, Vec<ws::Error>),
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct WS2PModule {}
+#[derive(Debug)]
+pub struct WS2PModule {
+    pub conf: WS2PConf,
+    pub count_dal_requests: u32,
+    pub currency: Option<String>,
+    pub current_blockstamp: Blockstamp,
+    pub ep_file_path: PathBuf,
+    pub heads_cache: HashMap<NodeFullId, NetworkHead>,
+    pub key_pair: KeyPairEnum,
+    pub main_thread_channel: (
+        mpsc::Sender<WS2PThreadSignal>,
+        mpsc::Receiver<WS2PThreadSignal>,
+    ),
+    pub my_head: Option<NetworkHead>,
+    pub next_receiver: usize,
+    pub node_id: NodeId,
+    pub requests_awaiting_response:
+        HashMap<ModuleReqId, (OldNetworkRequest, NodeFullId, SystemTime)>,
+    pub router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
+    pub soft_name: &'static str,
+    pub soft_version: &'static str,
+    pub ssl: bool,
+    pub websockets: HashMap<NodeFullId, WsSender>,
+    pub ws2p_endpoints: HashMap<NodeFullId, DbEndpoint>,
+    pub uids_cache: HashMap<PubKey, String>,
+}
+
+impl WS2PModule {
+    pub fn new(
+        soft_meta_datas: &SoftwareMetaDatas<DuRsConf>,
+        conf: WS2PConf,
+        ep_file_path: PathBuf,
+        key_pair: KeyPairEnum,
+        router_sender: mpsc::Sender<RouterThreadMessage<DursMsg>>,
+    ) -> WS2PModule {
+        WS2PModule {
+            router_sender,
+            key_pair,
+            currency: None,
+            current_blockstamp: Blockstamp::default(),
+            conf,
+            ep_file_path,
+            soft_name: soft_meta_datas.soft_name,
+            soft_version: soft_meta_datas.soft_version,
+            ssl: ssl(),
+            node_id: NodeId(soft_meta_datas.conf.my_node_id()),
+            main_thread_channel: mpsc::channel(),
+            next_receiver: 0,
+            ws2p_endpoints: HashMap::new(),
+            websockets: HashMap::new(),
+            requests_awaiting_response: HashMap::new(),
+            heads_cache: HashMap::new(),
+            my_head: None,
+            uids_cache: HashMap::new(),
+            count_dal_requests: 0,
+        }
+    }
+}
 
 #[derive(Debug)]
 pub enum WS2PThreadSignal {
@@ -190,8 +246,18 @@ pub enum WS2PThreadSignal {
     WS2PConnectionMessage(WS2PConnectionMessage),
 }
 
+#[derive(Copy, Clone, Debug)]
+/// Error when parsing WS2P message
+pub struct WS2PMsgParseErr {}
+
+impl From<dup_crypto::bases::BaseConvertionError> for WS2PMsgParseErr {
+    fn from(_: dup_crypto::bases::BaseConvertionError) -> Self {
+        WS2PMsgParseErr {}
+    }
+}
+
 pub trait WS2PMessage: Sized {
-    fn parse(v: &serde_json::Value, currency: String) -> Option<Self>;
+    fn parse(v: &serde_json::Value, currency: String) -> Result<Self, WS2PMsgParseErr>;
     fn to_raw(&self) -> String;
     fn sign(&self, key_pair: KeyPairEnum) -> Sig {
         key_pair.sign(self.to_raw().as_bytes())
@@ -200,12 +266,6 @@ pub trait WS2PMessage: Sized {
     //fn parse_and_verify(v: serde_json::Value, currency: String) -> bool;
 }
 
-impl Default for WS2PModule {
-    fn default() -> WS2PModule {
-        WS2PModule {}
-    }
-}
-
 #[derive(Debug)]
 /// WS2PFeaturesParseError
 pub enum WS2PFeaturesParseError {
@@ -291,34 +351,76 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
         // Get start time
         let start_time = SystemTime::now();
 
-        // Define WS2PModuleDatas
-        let mut ws2p_module = WS2PModuleDatas::new(
-            router_sender.clone(),
-            conf,
-            NodeId(soft_meta_datas.conf.my_node_id()),
-        );
+        // Get key_pair
+        let key_pair = if let RequiredKeysContent::NetworkKeyPair(key_pair) = keys {
+            key_pair
+        } else {
+            return Err(ModuleInitError::FailToLoadConf(
+                "WS2PModule fatal error at load_conf() : keys != NetworkKeyPair",
+            ));
+        };
 
         // load conf
-        let key_pair = match keys {
-            RequiredKeysContent::NetworkKeyPair(key_pair) => key_pair,
-            _ => panic!("WS2PModule fatal error at load_conf() : keys != NetworkKeyPair"),
-        };
         let mut ws2p_endpoints = HashMap::new();
-        for ep in &ws2p_module.conf.sync_endpoints {
+        for ep in &conf.sync_endpoints {
+            info!("Load sync endpoint {}", ep.raw_endpoint);
+            let node_full_id = ep
+                .node_full_id()
+                .expect("Fail to get endpoint node_full_id");
             ws2p_endpoints.insert(
-                ep.node_full_id()
-                    .expect("Fail to get endpoint node_full_id"),
-                (ep.clone(), WS2PConnectionState::Close),
+                node_full_id,
+                DbEndpoint {
+                    ep: ep.clone(),
+                    state: WS2PConnectionState::Close,
+                    last_check: 0,
+                },
             );
-            info!("Load sync endpoint {}", ep.raw_endpoint);
         }
-        ws2p_module.key_pair = Some(key_pair);
+
+        // Get endpoints file path
+        let mut ep_file_path =
+            duniter_conf::datas_path(&soft_meta_datas.profile, &soft_meta_datas.conf.currency());
+        ep_file_path.push("ws2pv1");
+        if !ep_file_path.exists() {
+            fs::create_dir(ep_file_path.as_path()).expect("Impossible to create ws2pv1 dir !");
+        }
+        ep_file_path.push("endpoints.bin");
+
+        // Define WS2PModule
+        let mut ws2p_module = WS2PModule::new(
+            soft_meta_datas,
+            conf,
+            ep_file_path.clone(),
+            key_pair,
+            router_sender.clone(),
+        );
         ws2p_module.currency = Some(soft_meta_datas.conf.currency().to_string());
         ws2p_module.ws2p_endpoints = ws2p_endpoints;
 
         // Create ws2p main thread channel
         let ws2p_sender_clone = ws2p_module.main_thread_channel.0.clone();
 
+        // Get ws2p endpoints in file
+        info!("TMP: WS2P SSL={}", ssl());
+        let count;
+        match ws2p_db::get_endpoints(&ep_file_path) {
+            Ok(ws2p_enpoints) => {
+                let ws2p_enpoints = ws2p_enpoints
+                    .into_iter()
+                    .filter(|(_, dal_ep)| cfg!(feature = "ssl") || dal_ep.ep.port != 443)
+                    .collect::<Vec<(NodeFullId, DbEndpoint)>>();
+                count = ws2p_enpoints.len();
+                ws2p_module.ws2p_endpoints.extend(ws2p_enpoints);
+            }
+            Err(err) => fatal_error!("WS2Pv1: fail to load endpoints from DB: {:?}", err),
+        }
+        info!("Load {} endpoints from DB !", count);
+
+        // Stop here in load_conf_only mode
+        if load_conf_only {
+            return Ok(());
+        }
+
         // Create proxy channel
         let (proxy_sender, proxy_receiver): (mpsc::Sender<DursMsg>, mpsc::Receiver<DursMsg>) =
             mpsc::channel();
@@ -364,50 +466,29 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
             }
         });
 
-        // open ws2p bdd
-        let mut db_path =
-            duniter_conf::datas_path(&soft_meta_datas.profile, &soft_meta_datas.conf.currency());
-        db_path.push("ws2p.db");
-        let db = WS2PModuleDatas::open_db(&db_path).expect("Fatal error : fail to open WS2P DB !");
+        // Request current blockstamp
+        send_dal_request(&mut ws2p_module, &BlockchainRequest::CurrentBlockstamp());
 
-        // Get ws2p endpoints in BDD
-        let mut count = 0;
-        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"))
-                && (cfg!(feature = "ssl") || ep.port != 443)
-            {
-                count += 1;
-                ws2p_module.ws2p_endpoints.insert(
-                    ep.node_full_id()
-                        .expect("WS2P: Fail to get ep.node_full_id() !"),
-                    (ep.clone(), WS2PConnectionState::from(ep.status)),
-                );
-            }
-        }
-        info!("Load {} endpoints from bdd !", count);
+        // Start
+        connect_to_know_endpoints(&mut ws2p_module);
+        ws2p_module.main_loop(start_time, soft_meta_datas);
 
-        // Stop here in load_conf_only mode
-        if load_conf_only {
-            return Ok(());
-        }
+        Ok(())
+    }
+}
 
+impl WS2PModule {
+    fn main_loop(mut self, start_time: SystemTime, soft_meta_datas: &SoftwareMetaDatas<DuRsConf>) {
         // Initialize variables
+        let key_pair = self.key_pair;
         let mut last_ws2p_connecting_wave = SystemTime::now();
-        let mut last_ws2p_connections_print = SystemTime::now();
+        let mut last_ws2p_state_print = SystemTime::now();
+        let mut last_ws2p_endpoints_write = SystemTime::now();
         let mut endpoints_to_update_status: HashMap<NodeFullId, SystemTime> = HashMap::new();
         let mut last_identities_request = UNIX_EPOCH;
-        let mut current_blockstamp = Blockstamp::default();
-        let mut next_receiver = 0;
 
-        // Request current blockstamp
-        ws2p_module.send_dal_request(&BlockchainRequest::CurrentBlockstamp());
-
-        // Start
-        ws2p_module.connect_to_know_endpoints();
         loop {
-            match ws2p_module
+            match self
                 .main_thread_channel
                 .1
                 .recv_timeout(Duration::from_millis(200))
@@ -418,112 +499,16 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
                             DursMsg::Stop => break,
                             DursMsg::Request {
                                 ref req_content, ..
-                            } => {
-                                if let DursReqContent::OldNetworkRequest(ref old_net_request) =
-                                    *req_content
-                                {
-                                    match *old_net_request {
-                                        OldNetworkRequest::GetBlocks(
-                                            ref req_id,
-                                            ref count,
-                                            ref from,
-                                        ) => {
-                                            let mut receiver_index = 0;
-                                            let mut real_receiver = None;
-                                            for (ws2p_full_id, (_ep, state)) in
-                                                ws2p_module.ws2p_endpoints.clone()
-                                            {
-                                                if let WS2PConnectionState::Established = state {
-                                                    if receiver_index == next_receiver {
-                                                        real_receiver = Some(ws2p_full_id);
-                                                        break;
-                                                    }
-                                                    receiver_index += 1;
-                                                }
-                                            }
-                                            if real_receiver.is_none() {
-                                                next_receiver = 0;
-                                                for (ws2p_full_id, (_ep, state)) in
-                                                    &ws2p_module.ws2p_endpoints
-                                                {
-                                                    if let WS2PConnectionState::Established = *state
-                                                    {
-                                                        real_receiver = Some(*ws2p_full_id);
-                                                        break;
-                                                    }
-                                                }
-                                            } else {
-                                                next_receiver += 1;
-                                            }
-                                            if let Some(real_receiver) = real_receiver {
-                                                debug!("WS2P: send req to: ({:?})", real_receiver);
-                                                let _blocks_request_result = ws2p_module
-                                                    .send_request_to_specific_node(
-                                                        &real_receiver,
-                                                        &OldNetworkRequest::GetBlocks(
-                                                            *req_id, *count, *from,
-                                                        ),
-                                                    );
-                                            } else {
-                                                warn!("WS2P: not found peer to send request !");
-                                            }
-                                        }
-                                        OldNetworkRequest::GetEndpoints(ref _request) => {}
-                                        _ => {}
-                                    }
-                                }
-                            }
+                            } => requests::received::receive_req(&mut self, req_content),
                             DursMsg::Event {
-                                ref event_content, ..
-                            } => {
-                                if let DursEvent::BlockchainEvent(ref bc_event) = *event_content {
-                                    match *bc_event.deref() {
-                                        BlockchainEvent::StackUpValidBlock(ref block) => {
-                                            current_blockstamp = block.deref().blockstamp();
-                                            debug!(
-                                                "WS2PModule : current_blockstamp = {}",
-                                                current_blockstamp
-                                            );
-                                            ws2p_module.my_head = Some(heads::generate_my_head(
-                                                &key_pair,
-                                                NodeId(soft_meta_datas.conf.my_node_id()),
-                                                soft_meta_datas.soft_name,
-                                                soft_meta_datas.soft_version,
-                                                &current_blockstamp,
-                                                None,
-                                            ));
-                                            ws2p_module.send_network_event(
-                                                &NetworkEvent::ReceiveHeads(vec![ws2p_module
-                                                    .my_head
-                                                    .clone()
-                                                    .unwrap()]),
-                                            );
-                                            // Send my head to all connections
-                                            let my_json_head = serializer::serialize_head(
-                                                ws2p_module.my_head.clone().unwrap(),
-                                            );
-                                            trace!("Send my HEAD: {:#?}", my_json_head);
-                                            let _results: Result<(), ws::Error> = ws2p_module
-                                                .websockets
-                                                .iter_mut()
-                                                .map(|ws| {
-                                                    (ws.1).0.send(Message::text(
-                                                        json!({
-                                                            "name": "HEAD",
-                                                            "body": {
-                                                                "heads": [my_json_head]
-                                                            }
-                                                        })
-                                                        .to_string(),
-                                                    ))
-                                                })
-                                                .collect();
-                                        }
-                                        BlockchainEvent::RevertBlocks(ref _blocks) => {}
-                                        _ => {}
-                                    }
-                                }
-                            }
+                                ref event_type,
+                                ref event_content,
+                                ..
+                            } => events::received::receive_event(
+                                &mut self,
+                                *event_type,
+                                event_content,
+                            ),
                             DursMsg::Response {
                                 ref res_content, ..
                             } => {
@@ -536,70 +521,61 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
                                         ) => {
                                             debug!(
                                                 "WS2PModule : receive DALResBc::CurrentBlockstamp({})",
-                                                current_blockstamp
+                                                self.current_blockstamp
                                             );
-                                            current_blockstamp = *current_blockstamp_;
-                                            if ws2p_module.my_head.is_none() {
-                                                ws2p_module.my_head =
-                                                    Some(heads::generate_my_head(
-                                                        &key_pair,
-                                                        NodeId(soft_meta_datas.conf.my_node_id()),
-                                                        soft_meta_datas.soft_name,
-                                                        soft_meta_datas.soft_version,
-                                                        &current_blockstamp,
-                                                        None,
-                                                    ));
+                                            self.current_blockstamp = *current_blockstamp_;
+                                            if self.my_head.is_none() {
+                                                self.my_head = Some(heads::generate_my_head(
+                                                    &key_pair,
+                                                    NodeId(soft_meta_datas.conf.my_node_id()),
+                                                    soft_meta_datas.soft_name,
+                                                    soft_meta_datas.soft_version,
+                                                    &self.current_blockstamp,
+                                                    None,
+                                                ));
                                             }
-                                            ws2p_module.send_network_event(
-                                                &NetworkEvent::ReceiveHeads(vec![ws2p_module
+                                            let event =
+                                                NetworkEvent::ReceiveHeads(vec![unwrap!(self
                                                     .my_head
-                                                    .clone()
-                                                    .unwrap()]),
-                                            );
+                                                    .clone())]);
+                                            events::sent::send_network_event(&mut self, event);
                                         }
                                         BlockchainResponse::UIDs(ref _req_id, ref uids) => {
                                             // Add uids to heads
-                                            for head in ws2p_module.heads_cache.values_mut() {
+                                            for head in self.heads_cache.values_mut() {
                                                 if let Some(uid_option) = uids.get(&head.pubkey()) {
                                                     if let Some(ref uid) = *uid_option {
                                                         head.set_uid(uid);
-                                                        ws2p_module
-                                                            .uids_cache
+                                                        self.uids_cache
                                                             .insert(head.pubkey(), uid.to_string());
                                                     } else {
-                                                        ws2p_module
-                                                            .uids_cache
-                                                            .remove(&head.pubkey());
+                                                        self.uids_cache.remove(&head.pubkey());
                                                     }
                                                 }
                                             }
                                             // Resent heads to other modules
-                                            ws2p_module.send_network_event(
-                                                &NetworkEvent::ReceiveHeads(
-                                                    ws2p_module
-                                                        .heads_cache
-                                                        .values()
-                                                        .cloned()
-                                                        .collect(),
-                                                ),
+                                            let event = NetworkEvent::ReceiveHeads(
+                                                self.heads_cache.values().cloned().collect(),
                                             );
+                                            events::sent::send_network_event(&mut self, event);
                                             // Resent to other modules connections that match receive uids
-                                            for (node_full_id, (ep, conn_state)) in
-                                                &ws2p_module.ws2p_endpoints
-                                            {
-                                                if let Some(uid_option) = uids.get(&node_full_id.1)
-                                                {
-                                                    ws2p_module.send_network_event(
-                                                        &NetworkEvent::ConnectionStateChange(
+                                            let events = self.ws2p_endpoints
+                                                .iter()
+                                                .filter_map(|(node_full_id, DbEndpoint { ep, state, .. })| {
+                                                    if let Some(uid_option) = uids.get(&node_full_id.1) {
+                                                        Some(NetworkEvent::ConnectionStateChange(
                                                             *node_full_id,
-                                                            *conn_state as u32,
+                                                            *state as u32,
                                                             uid_option.clone(),
                                                             ep.get_url(false, false)
                                                                 .expect("Endpoint unreachable !"),
-                                                        ),
-                                                    );
-                                                }
-                                            }
+                                                        ))
+                                                    } else {
+                                                        None
+                                                    }
+                                                })
+                                                .collect();
+                                            events::sent::send_network_events(&mut self, events);
                                         }
                                         _ => {} // Others BlockchainResponse variants
                                     }
@@ -608,187 +584,208 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
                             _ => {} // Others DursMsg variants
                         }
                     }
-                    WS2PThreadSignal::WS2PConnectionMessage(ws2p_conn_message) => match ws2p_module
-                        .ws2p_conn_message_pretreatment(ws2p_conn_message)
-                    {
-                        WS2PSignal::NoConnection => {
-                            warn!("WS2PSignal::NoConnection");
-                        }
-                        WS2PSignal::ConnectionEstablished(ws2p_full_id) => {
-                            let req_id =
-                                ModuleReqId(ws2p_module.requests_awaiting_response.len() as u32);
-                            let module_id = WS2PModule::name();
-                            debug!("WS2P: send req to: ({:?})", ws2p_full_id);
-                            let _current_request_result = ws2p_module
-                                .send_request_to_specific_node(
+                    WS2PThreadSignal::WS2PConnectionMessage(ws2p_conn_message) => {
+                        match crate::ws_connections::messages::ws2p_conn_message_pretreatment(
+                            &mut self,
+                            ws2p_conn_message,
+                        ) {
+                            WS2PSignal::NoConnection => {
+                                warn!("WS2PSignal::NoConnection");
+                            }
+                            WS2PSignal::ConnectionEstablished(ws2p_full_id) => {
+                                let req_id =
+                                    ModuleReqId(self.requests_awaiting_response.len() as u32);
+                                let module_id = WS2PModule::name();
+                                debug!("WS2P: send req to: ({:?})", ws2p_full_id);
+                                let _current_request_result =
+                                    ws_connections::requests::sent::send_request_to_specific_node(
+                                        &mut self,
+                                        &ws2p_full_id,
+                                        &OldNetworkRequest::GetCurrent(ModuleReqFullId(
+                                            module_id, req_id,
+                                        )),
+                                    );
+                                if self.uids_cache.get(&ws2p_full_id.1).is_none() {
+                                    send_dal_request(
+                                        &mut self,
+                                        &BlockchainRequest::UIDs(vec![ws2p_full_id.1]),
+                                    );
+                                }
+                                let event = NetworkEvent::ConnectionStateChange(
+                                    ws2p_full_id,
+                                    WS2PConnectionState::Established as u32,
+                                    self.uids_cache.get(&ws2p_full_id.1).cloned(),
+                                    self.ws2p_endpoints[&ws2p_full_id]
+                                        .ep
+                                        .get_url(false, false)
+                                        .expect("Endpoint unreachable !"),
+                                );
+                                events::sent::send_network_event(&mut self, event);
+                            }
+                            WS2PSignal::WSError(ws2p_full_id) => {
+                                endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
+                                close_connection(
+                                    &mut self,
                                     &ws2p_full_id,
-                                    &OldNetworkRequest::GetCurrent(ModuleReqFullId(
-                                        module_id, req_id,
-                                    )),
+                                    WS2PCloseConnectionReason::WsError,
                                 );
-                            if ws2p_module.uids_cache.get(&ws2p_full_id.1).is_none() {
-                                ws2p_module.send_dal_request(&BlockchainRequest::UIDs(vec![
-                                    ws2p_full_id.1,
-                                ]));
+                                let event = NetworkEvent::ConnectionStateChange(
+                                    ws2p_full_id,
+                                    WS2PConnectionState::WSError as u32,
+                                    self.uids_cache.get(&ws2p_full_id.1).cloned(),
+                                    self.ws2p_endpoints[&ws2p_full_id]
+                                        .ep
+                                        .get_url(false, false)
+                                        .expect("Endpoint unreachable !"),
+                                );
+                                events::sent::send_network_event(&mut self, event);
                             }
-                            ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
-                                ws2p_full_id,
-                                WS2PConnectionState::Established as u32,
-                                ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
-                                ws2p_module.ws2p_endpoints[&ws2p_full_id]
-                                    .0
-                                    .get_url(false, false)
-                                    .expect("Endpoint unreachable !"),
-                            ));
-                        }
-                        WS2PSignal::WSError(ws2p_full_id) => {
-                            endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
-                            ws2p_module.close_connection(
-                                &ws2p_full_id,
-                                WS2PCloseConnectionReason::WsError,
-                            );
-                            ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
-                                ws2p_full_id,
-                                WS2PConnectionState::WSError as u32,
-                                ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
-                                ws2p_module.ws2p_endpoints[&ws2p_full_id]
-                                    .0
-                                    .get_url(false, false)
-                                    .expect("Endpoint unreachable !"),
-                            ));
-                        }
-                        WS2PSignal::NegociationTimeout(ws2p_full_id) => {
-                            endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
-                            ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
-                                ws2p_full_id,
-                                WS2PConnectionState::Denial as u32,
-                                ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
-                                ws2p_module.ws2p_endpoints[&ws2p_full_id]
-                                    .0
-                                    .get_url(false, false)
-                                    .expect("Endpoint unreachable !"),
-                            ));
-                        }
-                        WS2PSignal::Timeout(ws2p_full_id) => {
-                            endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
-                            ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
-                                ws2p_full_id,
-                                WS2PConnectionState::Close as u32,
-                                ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
-                                ws2p_module.ws2p_endpoints[&ws2p_full_id]
-                                    .0
-                                    .get_url(false, false)
-                                    .expect("Endpoint unreachable !"),
-                            ));
-                        }
-                        WS2PSignal::PeerCard(_ws2p_full_id, _peer_card, ws2p_endpoints) => {
-                            //trace!("WS2PSignal::PeerCard({})", ws2p_full_id);
-                            //ws2p_module.send_network_event(NetworkEvent::ReceivePeers(_));
-                            for ep in ws2p_endpoints {
-                                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() !",
+                            WS2PSignal::NegociationTimeout(ws2p_full_id) => {
+                                endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
+                                let event = NetworkEvent::ConnectionStateChange(
+                                    ws2p_full_id,
+                                    WS2PConnectionState::Denial as u32,
+                                    self.uids_cache.get(&ws2p_full_id.1).cloned(),
+                                    self.ws2p_endpoints[&ws2p_full_id]
+                                        .ep
+                                        .get_url(false, false)
+                                        .expect("Endpoint unreachable !"),
+                                );
+                                events::sent::send_network_event(&mut self, event);
+                            }
+                            WS2PSignal::Timeout(ws2p_full_id) => {
+                                endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
+                                let event = NetworkEvent::ConnectionStateChange(
+                                    ws2p_full_id,
+                                    WS2PConnectionState::Close as u32,
+                                    self.uids_cache.get(&ws2p_full_id.1).cloned(),
+                                    self.ws2p_endpoints[&ws2p_full_id]
+                                        .ep
+                                        .get_url(false, false)
+                                        .expect("Endpoint unreachable !"),
+                                );
+                                events::sent::send_network_event(&mut self, event);
+                            }
+                            WS2PSignal::PeerCard(_ws2p_full_id, _peer_card, ws2p_endpoints) => {
+                                //trace!("WS2PSignal::PeerCard({})", ws2p_full_id);
+                                //self.send_network_event(NetworkEvent::ReceivePeers(_));
+                                for ep in ws2p_endpoints {
+                                    match self.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 {
+                                                connect_to(&mut self, &ep);
+                                            }
+                                        }
+                                    };
+                                }
+                            }
+                            WS2PSignal::Heads(ws2p_full_id, heads) => {
+                                trace!("WS2PSignal::Heads({}, {:?})", ws2p_full_id, heads.len());
+                                send_dal_request(
+                                    &mut self,
+                                    &BlockchainRequest::UIDs(
+                                        heads.iter().map(NetworkHead::pubkey).collect(),
+                                    ),
+                                );
+                                let event = NetworkEvent::ReceiveHeads(
+                                    heads
+                                        .iter()
+                                        .map(|head| {
+                                            let mut new_head = head.clone();
+                                            if let Some(uid) = self.uids_cache.get(&head.pubkey()) {
+                                                new_head.set_uid(uid);
+                                            }
+                                            new_head
+                                        })
+                                        .collect(),
+                                );
+                                events::sent::send_network_event(&mut self, event);
+                            }
+                            WS2PSignal::Document(ws2p_full_id, network_doc) => {
+                                trace!("WS2PSignal::Document({})", ws2p_full_id);
+                                events::sent::send_network_event(
+                                    &mut self,
+                                    NetworkEvent::ReceiveDocuments(vec![network_doc]),
+                                );
+                            }
+                            WS2PSignal::ReqResponse(req_id, req, recipient_full_id, response) => {
+                                match req {
+                                    OldNetworkRequest::GetCurrent(ref _req_id) => {
+                                        info!(
+                                            "WS2PSignal::ReceiveCurrent({}, {:?})",
+                                            req_id.0, req
+                                        );
+                                        if let Some(block) = parse_json_block(&response) {
+                                            crate::responses::sent::send_network_req_response(
+                                                &self,
+                                                req.get_req_full_id().0,
+                                                req.get_req_full_id().1,
+                                                NetworkResponse::CurrentBlock(
+                                                    ModuleReqFullId(WS2PModule::name(), req_id),
+                                                    recipient_full_id,
+                                                    Box::new(block),
                                                 ),
-                                                SystemTime::now(),
                                             );
                                         }
-                                        if cfg!(feature = "ssl") || ep.port != 443 {
-                                            ws2p_module.connect_to(&ep);
-                                        }
                                     }
-                                };
-                            }
-                        }
-                        WS2PSignal::Heads(ws2p_full_id, heads) => {
-                            trace!("WS2PSignal::Heads({}, {:?})", ws2p_full_id, heads.len());
-                            ws2p_module.send_dal_request(&BlockchainRequest::UIDs(
-                                heads.iter().map(NetworkHead::pubkey).collect(),
-                            ));
-                            ws2p_module.send_network_event(&NetworkEvent::ReceiveHeads(
-                                heads
-                                    .iter()
-                                    .map(|head| {
-                                        let mut new_head = head.clone();
-                                        if let Some(uid) =
-                                            ws2p_module.uids_cache.get(&head.pubkey())
-                                        {
-                                            new_head.set_uid(uid);
-                                        }
-                                        new_head
-                                    })
-                                    .collect(),
-                            ));
-                        }
-                        WS2PSignal::Document(ws2p_full_id, network_doc) => {
-                            trace!("WS2PSignal::Document({})", ws2p_full_id);
-                            ws2p_module.send_network_event(&NetworkEvent::ReceiveDocuments(vec![
-                                network_doc,
-                            ]));
-                        }
-                        WS2PSignal::ReqResponse(req_id, req, recipient_full_id, response) => {
-                            match req {
-                                OldNetworkRequest::GetCurrent(ref _req_id) => {
-                                    info!("WS2PSignal::ReceiveCurrent({}, {:?})", req_id.0, req);
-                                    if let Some(block) = parse_json_block(&response) {
-                                        ws2p_module.send_network_req_response(
-                                            req.get_req_full_id().0,
-                                            req.get_req_full_id().1,
-                                            NetworkResponse::CurrentBlock(
-                                                ModuleReqFullId(WS2PModule::name(), req_id),
-                                                recipient_full_id,
-                                                Box::new(block),
-                                            ),
+                                    OldNetworkRequest::GetBlocks(ref _req_id, count, from) => {
+                                        info!(
+                                            "WS2PSignal::ReceiveChunk({}, {} blocks from {})",
+                                            req_id.0, count, from
                                         );
-                                    }
-                                }
-                                OldNetworkRequest::GetBlocks(ref _req_id, count, from) => {
-                                    info!(
-                                        "WS2PSignal::ReceiveChunk({}, {} blocks from {})",
-                                        req_id.0, count, from
-                                    );
-                                    if response.is_array() {
-                                        let mut chunk = Vec::new();
-                                        for json_block in response.as_array().unwrap() {
-                                            if let Some(block) = parse_json_block(json_block) {
-                                                chunk.push(block);
-                                            } else {
-                                                warn!("WS2PModule: Error : fail to parse one json block !");
+                                        if response.is_array() {
+                                            let mut chunk = Vec::new();
+                                            for json_block in unwrap!(response.as_array()) {
+                                                if let Some(block) = parse_json_block(json_block) {
+                                                    chunk.push(block);
+                                                } else {
+                                                    warn!("WS2PModule: Error : fail to parse one json block !");
+                                                }
                                             }
+                                            debug!("Send chunk to followers : {}", from);
+                                            events::sent::send_network_event(
+                                                &mut self,
+                                                NetworkEvent::ReceiveBlocks(chunk),
+                                            );
                                         }
-                                        debug!("Send chunk to followers : {}", from);
-                                        ws2p_module.send_network_event(
-                                            &NetworkEvent::ReceiveBlocks(chunk),
+                                    }
+                                    OldNetworkRequest::GetRequirementsPending(
+                                        _req_id,
+                                        min_cert,
+                                    ) => {
+                                        info!(
+                                            "WS2PSignal::ReceiveRequirementsPending({}, {})",
+                                            req_id.0, min_cert
                                         );
+                                        debug!("----------------------------------------");
+                                        debug!("-      BEGIN IDENTITIES PENDING        -");
+                                        debug!("----------------------------------------");
+                                        debug!("{:#?}", response);
+                                        debug!("----------------------------------------");
+                                        debug!("-       END IDENTITIES PENDING         -");
+                                        debug!("----------------------------------------");
                                     }
+                                    _ => {}
                                 }
-                                OldNetworkRequest::GetRequirementsPending(_req_id, min_cert) => {
-                                    info!(
-                                        "WS2PSignal::ReceiveRequirementsPending({}, {})",
-                                        req_id.0, min_cert
-                                    );
-                                    debug!("----------------------------------------");
-                                    debug!("-      BEGIN IDENTITIES PENDING        -");
-                                    debug!("----------------------------------------");
-                                    debug!("{:#?}", response);
-                                    debug!("----------------------------------------");
-                                    debug!("-       END IDENTITIES PENDING         -");
-                                    debug!("----------------------------------------");
-                                }
-                                _ => {}
                             }
+                            WS2PSignal::Empty => {}
+                            _ => {}
                         }
-                        WS2PSignal::Empty => {}
-                        _ => {}
-                    },
+                    }
                 },
                 Err(e) => match e {
                     mpsc::RecvTimeoutError::Disconnected => {
@@ -797,14 +794,21 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
                     mpsc::RecvTimeoutError::Timeout => {}
                 },
             }
-            if SystemTime::now()
-                .duration_since(last_ws2p_connections_print)
-                .unwrap()
-                > Duration::new(5, 0)
+            if unwrap!(SystemTime::now().duration_since(last_ws2p_endpoints_write))
+                > Duration::new(*DURATION_BETWEEN_2_ENDPOINTS_SAVING, 0)
+            {
+                last_ws2p_endpoints_write = SystemTime::now();
+                if let Err(err) = ws2p_db::write_endpoints(&self.ep_file_path, &self.ws2p_endpoints)
+                {
+                    fatal_error!("WS2P1: Fail to write endpoints in DB : {:?}", err);
+                }
+            }
+            if unwrap!(SystemTime::now().duration_since(last_ws2p_state_print))
+                > Duration::new(*WS2P_GENERAL_STATE_INTERVAL, 0)
             {
-                last_ws2p_connections_print = SystemTime::now();
+                last_ws2p_state_print = SystemTime::now();
                 let mut connected_nodes = Vec::new();
-                for (k, (_ep, state)) in ws2p_module.ws2p_endpoints.clone() {
+                for (k, DbEndpoint { state, .. }) in self.ws2p_endpoints.clone() {
                     if let WS2PConnectionState::Established = state {
                         connected_nodes.push(k);
                     }
@@ -812,75 +816,37 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
                 // Print current_blockstamp
                 info!(
                     "WS2PModule : current_blockstamp() = {:?}",
-                    current_blockstamp
+                    self.current_blockstamp
                 );
                 // New WS2P connection wave
-                if connected_nodes.len() < ws2p_module.conf.clone().outcoming_quota
-                    && (SystemTime::now()
-                        .duration_since(last_ws2p_connecting_wave)
-                        .unwrap()
+                if connected_nodes.len() < self.conf.clone().outcoming_quota
+                    && (unwrap!(SystemTime::now().duration_since(last_ws2p_connecting_wave))
                         > Duration::new(*WS2P_OUTCOMING_INTERVAL, 0)
-                        || (SystemTime::now()
-                            .duration_since(last_ws2p_connecting_wave)
-                            .unwrap()
+                        || (unwrap!(SystemTime::now().duration_since(last_ws2p_connecting_wave))
                             > Duration::new(*WS2P_OUTCOMING_INTERVAL_AT_STARTUP, 0)
-                            && SystemTime::now().duration_since(start_time).unwrap()
+                            && unwrap!(SystemTime::now().duration_since(start_time))
                                 < Duration::new(*WS2P_OUTCOMING_INTERVAL, 0)))
                 {
                     last_ws2p_connecting_wave = SystemTime::now();
                     info!("Connected to know endpoints...");
-                    ws2p_module.connect_to_know_endpoints();
+                    connect_to_know_endpoints(&mut self);
                 }
                 // Request pending_identities from network
-                if SystemTime::now()
-                    .duration_since(last_identities_request)
-                    .unwrap()
+                if unwrap!(SystemTime::now().duration_since(last_identities_request))
                     > Duration::new(*PENDING_IDENTITIES_REQUEST_INTERVAL, 0)
-                    && SystemTime::now().duration_since(start_time).unwrap() > Duration::new(10, 0)
+                    && unwrap!(SystemTime::now().duration_since(start_time)) > Duration::new(10, 0)
                 {
                     /*info!("get pending_identities from all connections...");
-                    let _blocks_request_result = ws2p_module.send_request_to_all_connections(
+                    let _blocks_request_result = self.send_request_to_all_connections(
                         &OldNetworkRequest::GetRequirementsPending(ModuleReqId(0 as u32), 5),
                     );*/
                     last_identities_request = SystemTime::now();
                 }
-                // Write pending endpoints
-                for (ep_full_id, received_time) in endpoints_to_update_status.clone() {
-                    if SystemTime::now().duration_since(received_time).unwrap()
-                        > Duration::new(*DURATION_BEFORE_RECORDING_ENDPOINT, 0)
-                    {
-                        if let Some(&(ref ep, ref state)) =
-                            ws2p_module.ws2p_endpoints.get(&ep_full_id)
-                        {
-                            ws2p_db::write_endpoint(
-                                &db,
-                                &ep,
-                                state.to_u32(),
-                                SystemTime::now()
-                                    .duration_since(UNIX_EPOCH)
-                                    .unwrap()
-                                    .as_secs(),
-                            );
-                        }
-                        endpoints_to_update_status.remove(&ep_full_id);
-                    } else {
-                        info!(
-                            "Write {} endpoint in {} secs.",
-                            ep_full_id,
-                            *DURATION_BEFORE_RECORDING_ENDPOINT
-                                - SystemTime::now()
-                                    .duration_since(received_time)
-                                    .unwrap()
-                                    .as_secs()
-                        );
-                    }
-                }
                 // ..
                 // Request current blockstamp
-                ws2p_module.send_dal_request(&BlockchainRequest::CurrentBlockstamp());
+                send_dal_request(&mut self, &BlockchainRequest::CurrentBlockstamp());
             }
         }
-        Ok(())
     }
 }
 
@@ -888,13 +854,9 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule {
 mod tests {
     use super::parsers::blocks::parse_json_block;
     use super::*;
+    use crate::ws_connections::requests::sent::network_request_to_json;
     use dubp_documents::documents::block::BlockDocument;
     use duniter_module::DursModule;
-    use dup_crypto::keys::PublicKey;
-    use durs_network_documents::network_endpoint::NetworkEndpointApi;
-    use std::fs;
-    use std::path::PathBuf;
-    use std::time::{SystemTime, UNIX_EPOCH};
 
     #[test]
     fn test_parse_json_block() {
@@ -1062,40 +1024,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn endpoint_db_tests() {
-        let test_db_path = PathBuf::from("test.db");
-        if test_db_path.as_path().exists() {
-            fs::remove_file(&test_db_path).unwrap();
-        }
-        let db = WS2PModuleDatas::open_db(&test_db_path).unwrap();
-
-        let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
-
-        let mut endpoint = EndpointV1::parse_from_raw(
-            "WS2P cb06a19b g1.imirhil.fr 53012 /",
-            PubKey::Ed25519(
-                ed25519::PublicKey::from_base58("5gJYnQp8v7bWwk7EWRoL8vCLof1r3y9c6VDdnGSM1GLv")
-                    .unwrap(),
-            ),
-            1,
-            current_time.as_secs(),
-        )
-        .expect("Failt to parse test endpoint !");
-
-        ws2p_db::write_endpoint(&db, &endpoint, 1, current_time.as_secs());
-        let mut written_endpoints =
-            ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P")));
-        assert_eq!(endpoint, written_endpoints.pop().unwrap());
-
-        // Test status update
-        endpoint.status = 3;
-        ws2p_db::write_endpoint(&db, &endpoint, 3, current_time.as_secs());
-        let mut written_endpoints =
-            ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P")));
-        assert_eq!(endpoint, written_endpoints.pop().unwrap());
-    }
-
     #[test]
     fn ws2p_requests() {
         let module_id = WS2PModule::name();
diff --git a/lib/modules/ws2p-v1-legacy/src/ok_message.rs b/lib/modules/ws2p-v1-legacy/src/ok_message.rs
index 95a63c9d..5d566034 100644
--- a/lib/modules/ws2p-v1-legacy/src/ok_message.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ok_message.rs
@@ -1,4 +1,4 @@
-use super::WS2PMessage;
+use crate::*;
 use dup_crypto::keys::*;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
@@ -11,23 +11,18 @@ pub struct WS2POkMessageV1 {
 }
 
 impl WS2PMessage for WS2POkMessageV1 {
-    fn parse(v: &serde_json::Value, currency: String) -> Option<Self> {
+    fn parse(v: &serde_json::Value, currency: String) -> Result<Self, WS2PMsgParseErr> {
         let signature = match v.get("sig") {
-            Some(signature) => signature
-                .as_str()
-                .expect("Parsing of OK message : fail to convert sig to str")
-                .to_string(),
-            None => return None,
+            Some(signature) => signature.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+            None => return Err(WS2PMsgParseErr {}),
         };
-        let pubkey: PubKey = PubKey::Ed25519(
-            ed25519::PublicKey::from_base58("969qRJs8KhsnkyzqarpL4RKZGMdVKNbZgu8fhsigM7Lj")
-                .expect("fail to create default pubkey !"),
-        );
-        let signature: Option<Sig> = Some(Sig::Ed25519(
-            dup_crypto::keys::Signature::from_base64(&signature)
-                .expect("fail to parse signature of OK message !"),
-        ));
-        Some(WS2POkMessageV1 {
+        let pubkey: PubKey = PubKey::Ed25519(ed25519::PublicKey::from_base58(
+            "969qRJs8KhsnkyzqarpL4RKZGMdVKNbZgu8fhsigM7Lj",
+        )?);
+        let signature: Option<Sig> = Some(Sig::Ed25519(dup_crypto::keys::Signature::from_base64(
+            &signature,
+        )?));
+        Ok(WS2POkMessageV1 {
             currency,
             pubkey,
             challenge: "".to_string(),
@@ -41,8 +36,11 @@ impl WS2PMessage for WS2POkMessageV1 {
         )
     }
     fn verify(&self) -> bool {
-        self.pubkey
-            .verify(self.to_raw().as_bytes(), &self.signature.unwrap())
+        if let Some(sig) = self.signature {
+            self.pubkey.verify(self.to_raw().as_bytes(), &sig)
+        } else {
+            false
+        }
     }
 }
 
diff --git a/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs b/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
index 8e7dd84b..aff225c3 100644
--- a/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
@@ -1,13 +1,14 @@
 use dup_crypto::keys::ed25519;
 use dup_crypto::keys::*;
+use unwrap::unwrap;
 
 pub fn parse_exclusions(json_datas: &str) -> Option<Vec<PubKey>> {
-    let raw_exclusions: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+    let raw_exclusions: serde_json::Value = unwrap!(serde_json::from_str(json_datas));
 
     if raw_exclusions.is_array() {
-        Some(parse_exclusions_from_json_value(
-            raw_exclusions.as_array().unwrap(),
-        ))
+        Some(parse_exclusions_from_json_value(unwrap!(
+            raw_exclusions.as_array()
+        )))
     } else {
         None
     }
@@ -16,9 +17,9 @@ pub fn parse_exclusions(json_datas: &str) -> Option<Vec<PubKey>> {
 pub fn parse_exclusions_from_json_value(array_exclusions: &[serde_json::Value]) -> Vec<PubKey> {
     let mut exclusions: Vec<PubKey> = Vec::new();
     for exclusion in array_exclusions.iter() {
-        exclusions.push(PubKey::Ed25519(
-            ed25519::PublicKey::from_base58(exclusion.as_str().unwrap()).unwrap(),
-        ));
+        exclusions.push(PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+            unwrap!(exclusion.as_str())
+        ))));
     }
     exclusions
 }
diff --git a/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs b/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
index 02aab9a9..254214a3 100644
--- a/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
@@ -2,6 +2,7 @@ use dubp_documents::documents::identity::*;
 use dubp_documents::Blockstamp;
 use dubp_documents::DocumentBuilder;
 use dup_crypto::keys::*;
+use unwrap::unwrap;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum IdentityParseError {
@@ -9,10 +10,10 @@ pub enum IdentityParseError {
 }
 
 pub fn parse_identities(currency: &str, json_datas: &str) -> Option<Vec<IdentityDocument>> {
-    let raw_idties: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+    let raw_idties: serde_json::Value = unwrap!(serde_json::from_str(json_datas));
     if raw_idties.is_array() {
         return Some(
-            parse_identities_from_json_value(currency, raw_idties.as_array().unwrap())
+            parse_identities_from_json_value(currency, unwrap!(raw_idties.as_array()))
                 .iter()
                 .map(|i| {
                     i.clone()
@@ -31,18 +32,18 @@ pub fn parse_identities_from_json_value(
     array_identities
         .iter()
         .map(|idty| {
-            let idty_datas: Vec<&str> = idty.as_str().unwrap().split(':').collect();
+            let idty_datas: Vec<&str> = unwrap!(idty.as_str()).split(':').collect();
             if idty_datas.len() == 4 {
                 let idty_doc_builder = IdentityDocumentBuilder {
                     currency,
-                    issuer: &PubKey::Ed25519(
-                        ed25519::PublicKey::from_base58(idty_datas[0]).unwrap(),
-                    ),
-                    blockstamp: &Blockstamp::from_string(idty_datas[2]).unwrap(),
+                    issuer: &PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                        idty_datas[0]
+                    ))),
+                    blockstamp: &unwrap!(Blockstamp::from_string(idty_datas[2])),
                     username: idty_datas[3],
                 };
                 let idty_sig =
-                    Sig::Ed25519(ed25519::Signature::from_base64(idty_datas[1]).unwrap());
+                    Sig::Ed25519(unwrap!(ed25519::Signature::from_base64(idty_datas[1])));
                 //memberships.push(membership_doc_builder.build_with_signature(vec![membership_sig]));
                 Ok(idty_doc_builder.build_with_signature(vec![idty_sig]))
             } else {
@@ -57,7 +58,7 @@ pub fn parse_compact_identity(
     source: &serde_json::Value,
 ) -> Option<IdentityDocument> {
     if source.is_string() {
-        let idty_elements: Vec<&str> = source.as_str().unwrap().split(':').collect();
+        let idty_elements: Vec<&str> = unwrap!(source.as_str()).split(':').collect();
         let issuer = match ed25519::PublicKey::from_base58(idty_elements[0]) {
             Ok(pubkey) => PubKey::Ed25519(pubkey),
             Err(_) => return None,
diff --git a/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs b/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
index a04d2d99..3fb2cf2a 100644
--- a/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
@@ -2,6 +2,7 @@ use dubp_documents::documents::membership::*;
 use dubp_documents::Blockstamp;
 use dubp_documents::DocumentBuilder;
 use dup_crypto::keys::*;
+use unwrap::unwrap;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum MembershipParseError {
@@ -13,13 +14,13 @@ pub fn parse_memberships(
     membership_type: MembershipType,
     json_datas: &str,
 ) -> Option<Vec<MembershipDocument>> {
-    let raw_memberships: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+    let raw_memberships: serde_json::Value = unwrap!(serde_json::from_str(json_datas));
     if raw_memberships.is_array() {
         return Some(
             parse_memberships_from_json_value(
                 currency,
                 membership_type,
-                raw_memberships.as_array().unwrap(),
+                unwrap!(raw_memberships.as_array()),
             )
             .iter()
             .map(|m| {
@@ -41,20 +42,21 @@ pub fn parse_memberships_from_json_value(
     array_memberships
         .iter()
         .map(|membership| {
-            let membership_datas: Vec<&str> = membership.as_str().unwrap().split(':').collect();
+            let membership_datas: Vec<&str> = unwrap!(membership.as_str()).split(':').collect();
             if membership_datas.len() == 5 {
                 let membership_doc_builder = MembershipDocumentBuilder {
                     currency,
-                    issuer: &PubKey::Ed25519(
-                        ed25519::PublicKey::from_base58(membership_datas[0]).unwrap(),
-                    ),
-                    blockstamp: &Blockstamp::from_string(membership_datas[2]).unwrap(),
+                    issuer: &PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                        membership_datas[0]
+                    ))),
+                    blockstamp: &unwrap!(Blockstamp::from_string(membership_datas[2])),
                     membership: membership_type,
                     identity_username: membership_datas[4],
-                    identity_blockstamp: &Blockstamp::from_string(membership_datas[3]).unwrap(),
+                    identity_blockstamp: &unwrap!(Blockstamp::from_string(membership_datas[3])),
                 };
-                let membership_sig =
-                    Sig::Ed25519(ed25519::Signature::from_base64(membership_datas[1]).unwrap());
+                let membership_sig = Sig::Ed25519(unwrap!(ed25519::Signature::from_base64(
+                    membership_datas[1]
+                )));
                 Ok(membership_doc_builder.build_with_signature(vec![membership_sig]))
             } else {
                 Err(MembershipParseError::WrongFormat())
diff --git a/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs b/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
index ca9a42a8..7c9c1edc 100644
--- a/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
@@ -27,6 +27,7 @@ mod tests {
     use dubp_documents::DocumentBuilder;
     use dup_crypto::keys::*;
     use std::str::FromStr;
+    use unwrap::unwrap;
 
     #[test]
     fn parse_json_tx() {
@@ -57,28 +58,24 @@ mod tests {
 
         let tx_builder = TransactionDocumentBuilder {
             currency: "g1",
-            blockstamp: &Blockstamp::from_string(
+            blockstamp: &unwrap!(Blockstamp::from_string(
                 "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
-            )
-            .unwrap(),
+            )),
             locktime: &0,
-            issuers: &vec![PubKey::Ed25519(
-                ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
-                    .unwrap(),
-            )],
-            inputs: &vec![TransactionInput::from_str(
+            issuers: &vec![PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                "51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2"
+            )))],
+            inputs: &vec![unwrap!(TransactionInput::from_str(
                 "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
-            )
-            .unwrap()],
-            outputs: &vec![TransactionOutput::from_str(
+            ))],
+            outputs: &vec![unwrap!(TransactionOutput::from_str(
                 "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
-            )
-            .unwrap()],
-            unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
+            ))],
+            unlocks: &vec![unwrap!(TransactionInputUnlocks::from_str("0:SIG(0)"))],
             comment: "Merci pour la calligraphie ;) de Liam",
             hash: None,
         };
-        let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(ed25519::Signature::from_base64("5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==").unwrap())]);
+        let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(unwrap!(ed25519::Signature::from_base64("5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==")))]);
         tx_doc.compute_hash();
         assert_eq!(
             parse_transaction("g1", &tx_json).expect("Fail to parse transaction !"),
@@ -116,32 +113,29 @@ mod tests {
 
         let tx_builder = TransactionDocumentBuilder {
             currency: "g1",
-            blockstamp: &Blockstamp::from_string(
+            blockstamp: &unwrap!(Blockstamp::from_string(
                 "58-00005B9167EBA1E32C6EAD42AE7F72D8F14B765D3C9E47D233B553D47C5AEE0C",
-            )
-            .unwrap(),
+            )),
             locktime: &0,
-            issuers: &vec![PubKey::Ed25519(
-                ed25519::PublicKey::from_base58("FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD")
-                    .unwrap(),
-            )],
-            inputs: &vec![TransactionInput::from_str(
+            issuers: &vec![PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                "FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD"
+            )))],
+            inputs: &vec![unwrap!(TransactionInput::from_str(
                 "1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1",
-            )
-            .unwrap()],
+            ))],
             outputs: &vec![
-                TransactionOutput::from_str("3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)")
-                    .unwrap(),
-                TransactionOutput::from_str(
+                unwrap!(TransactionOutput::from_str(
+                    "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)"
+                )),
+                unwrap!(TransactionOutput::from_str(
                     "997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)",
-                )
-                .unwrap(),
+                )),
             ],
-            unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
+            unlocks: &vec![unwrap!(TransactionInputUnlocks::from_str("0:SIG(0)"))],
             comment: "Un petit cafe ;-)",
             hash: None,
         };
-        let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(ed25519::Signature::from_base64("VWbvsiybM4L2X5+o+6lIiuKNw5KrD1yGZqmV+lHtA28XoRUFzochSIgfoUqBsTAaYEHY45vSX917LDXudTEzBg==").unwrap())]);
+        let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(unwrap!(ed25519::Signature::from_base64("VWbvsiybM4L2X5+o+6lIiuKNw5KrD1yGZqmV+lHtA28XoRUFzochSIgfoUqBsTAaYEHY45vSX917LDXudTEzBg==")))]);
         tx_doc.compute_hash();
         assert_eq!(
             parse_transaction("g1", &tx_json).expect("Fail to parse transaction !"),
diff --git a/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs b/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
index f979aa73..5beacc27 100644
--- a/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
@@ -96,6 +96,7 @@ pub fn parse_transaction(
 #[cfg(test)]
 mod tests {
     use super::*;
+    use unwrap::unwrap;
 
     #[test]
     fn parse_compact_tx() {
@@ -110,24 +111,20 @@ Merci pour la calligraphie ;) de Liam$\
 
         let _tx_builder = TransactionDocumentBuilder {
             currency: "g1",
-            blockstamp: &Blockstamp::from_string(
+            blockstamp: &unwrap!(Blockstamp::from_string(
                 "112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
-            )
-            .unwrap(),
+            )),
             locktime: &0,
-            issuers: &vec![PubKey::Ed25519(
-                ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
-                    .unwrap(),
-            )],
-            inputs: &vec![TransactionInput::from_str(
+            issuers: &vec![PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+                "51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2"
+            )))],
+            inputs: &vec![unwrap!(TransactionInput::from_str(
                 "1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
-            )
-            .unwrap()],
-            outputs: &vec![TransactionOutput::from_str(
+            ))],
+            outputs: &vec![unwrap!(TransactionOutput::from_str(
                 "1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
-            )
-            .unwrap()],
-            unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
+            ))],
+            unlocks: &vec![unwrap!(TransactionInputUnlocks::from_str("0:SIG(0)"))],
             comment: "Merci pour la calligraphie ;) de Liam",
             hash: None,
         };
diff --git a/lib/modules/ws2p-v1-legacy/src/requests/mod.rs b/lib/modules/ws2p-v1-legacy/src/requests/mod.rs
new file mode 100644
index 00000000..f2456178
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/requests/mod.rs
@@ -0,0 +1,19 @@
+//  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/>.
+
+//! Sub-module managing the inter-modules requests sent and received.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/requests/received.rs b/lib/modules/ws2p-v1-legacy/src/requests/received.rs
new file mode 100644
index 00000000..ab9c2d0e
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/requests/received.rs
@@ -0,0 +1,66 @@
+//  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/>.
+
+//! Sub-module managing the inter-modules requests received.
+
+use crate::ws2p_db::DbEndpoint;
+use crate::ws_connections::states::WS2PConnectionState;
+use crate::WS2PModule;
+use duniter_network::requests::OldNetworkRequest;
+use durs_message::requests::DursReqContent;
+
+pub fn receive_req(ws2p_module: &mut WS2PModule, req_content: &DursReqContent) {
+    if let DursReqContent::OldNetworkRequest(ref old_net_request) = *req_content {
+        match *old_net_request {
+            OldNetworkRequest::GetBlocks(ref req_id, ref count, ref from) => {
+                let mut receiver_index = 0;
+                let mut real_receiver = None;
+                for (ws2p_full_id, DbEndpoint { state, .. }) in ws2p_module.ws2p_endpoints.clone() {
+                    if let WS2PConnectionState::Established = state {
+                        if receiver_index == ws2p_module.next_receiver {
+                            real_receiver = Some(ws2p_full_id);
+                            break;
+                        }
+                        receiver_index += 1;
+                    }
+                }
+                if real_receiver.is_none() {
+                    ws2p_module.next_receiver = 0;
+                    for (ws2p_full_id, DbEndpoint { state, .. }) in &ws2p_module.ws2p_endpoints {
+                        if let WS2PConnectionState::Established = *state {
+                            real_receiver = Some(*ws2p_full_id);
+                            break;
+                        }
+                    }
+                } else {
+                    ws2p_module.next_receiver += 1;
+                }
+                if let Some(real_receiver) = real_receiver {
+                    debug!("WS2P: send req to: ({:?})", real_receiver);
+                    let _blocks_request_result =
+                        crate::ws_connections::requests::sent::send_request_to_specific_node(
+                            ws2p_module,
+                            &real_receiver,
+                            &OldNetworkRequest::GetBlocks(*req_id, *count, *from),
+                        );
+                } else {
+                    warn!("WS2P: not found peer to send request !");
+                }
+            }
+            OldNetworkRequest::GetEndpoints(ref _request) => {}
+            _ => {}
+        }
+    }
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/requests/sent.rs b/lib/modules/ws2p-v1-legacy/src/requests/sent.rs
new file mode 100644
index 00000000..e07093a9
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/requests/sent.rs
@@ -0,0 +1,37 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the inter-modules requests sent.
+
+use crate::WS2PModule;
+use duniter_module::{DursModule, ModuleReqId, ModuleRole, RouterThreadMessage};
+use durs_message::requests::{BlockchainRequest, DursReqContent};
+use durs_message::*;
+
+pub fn send_dal_request(ws2p_module: &mut WS2PModule, req: &BlockchainRequest) {
+    ws2p_module.count_dal_requests += 1;
+    if ws2p_module.count_dal_requests == std::u32::MAX {
+        ws2p_module.count_dal_requests = 0;
+    }
+    ws2p_module
+        .router_sender
+        .send(RouterThreadMessage::ModuleMessage(DursMsg::Request {
+            req_from: WS2PModule::name(),
+            req_to: ModuleRole::BlockchainDatas,
+            req_id: ModuleReqId(ws2p_module.count_dal_requests),
+            req_content: DursReqContent::BlockchainRequest(req.clone()),
+        }))
+        .expect("Fail to send message to router !");
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/mod.rs b/lib/modules/ws2p-v1-legacy/src/responses/mod.rs
new file mode 100644
index 00000000..516f7af7
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/responses/mod.rs
@@ -0,0 +1,19 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the inter-modules responses sent and received.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/received.rs b/lib/modules/ws2p-v1-legacy/src/responses/received.rs
new file mode 100644
index 00000000..64e0f487
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/responses/received.rs
@@ -0,0 +1,16 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the inter-modules responses received.
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/sent.rs b/lib/modules/ws2p-v1-legacy/src/responses/sent.rs
new file mode 100644
index 00000000..f102489c
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/responses/sent.rs
@@ -0,0 +1,36 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the inter-modules responses sent.
+
+use crate::*;
+use durs_message::*;
+
+pub fn send_network_req_response(
+    ws2p_module: &WS2PModule,
+    requester: ModuleStaticName,
+    req_id: ModuleReqId,
+    response: NetworkResponse,
+) {
+    ws2p_module
+        .router_sender
+        .send(RouterThreadMessage::ModuleMessage(DursMsg::Response {
+            res_from: WS2PModule::name(),
+            res_to: requester,
+            req_id,
+            res_content: DursResContent::NetworkResponse(response),
+        }))
+        .expect("Fail to send message to router !");
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs b/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
index c23229dc..0b09fb1f 100644
--- a/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
@@ -1,6 +1,27 @@
-use dup_crypto::keys::*;
-use durs_network_documents::network_endpoint::{EndpointV1, NetworkEndpointApi};
-use sqlite::*;
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Manage WS2Pv1 storage.
+
+use crate::ws_connections::states::WS2PConnectionState;
+use durs_network_documents::network_endpoint::EndpointV1;
+use durs_network_documents::NodeFullId;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::fs::File;
+use std::path::Path;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum EndpointApi {
@@ -12,14 +33,6 @@ pub enum EndpointApi {
     //BMAS,
 }
 
-impl From<u32> for EndpointApi {
-    fn from(integer: u32) -> Self {
-        match integer {
-            _ => EndpointApi::WS2P,
-        }
-    }
-}
-
 pub fn string_to_api(api: &str) -> Option<EndpointApi> {
     match api {
         "WS2P" => Some(EndpointApi::WS2P),
@@ -32,97 +45,53 @@ pub fn string_to_api(api: &str) -> Option<EndpointApi> {
     }
 }
 
-pub fn api_to_integer(api: &NetworkEndpointApi) -> i64 {
-    match api.0.as_str() {
-        "WS2P" => 1,
-        //EndpointApi::WS2PS => 2,
-        //EndpointApi::WS2PTOR => 3,
-        //EndpointApi::DASA => 4,
-        //EndpointApi::BMA => 5,
-        //EndpointApi::BMAS => 6,
-        _ => 0,
-    }
+#[derive(Debug)]
+pub enum Ws2pPeersDbError {
+    IoErr(std::io::Error),
+    SerdeErr(bincode::Error),
 }
 
-pub fn get_endpoints_for_api(db: &Connection, api: &NetworkEndpointApi) -> Vec<EndpointV1> {
-    let mut cursor: Cursor = db
-        .prepare("SELECT hash_full_id, status, node_id, pubkey, api, version, endpoint, last_check FROM endpoints WHERE api=? ORDER BY status DESC;")
-        .expect("get_endpoints_for_api() : Error in SQL request !")
-        .cursor();
-
-    cursor
-        .bind(&[Value::Integer(api_to_integer(&api))])
-        .expect("get_endpoints_for_api() : Error in cursor binding !");
-    let mut endpoints = Vec::new();
-    while let Some(row) = cursor
-        .next()
-        .expect("get_endpoints_for_api() : Error in cursor.next()")
-    {
-        let raw_ep = row[6].as_string().unwrap().to_string();
-        let ep_issuer =
-            PubKey::Ed25519(ed25519::PublicKey::from_base58(row[3].as_string().unwrap()).unwrap());
-        let mut ep = match EndpointV1::parse_from_raw(
-            &raw_ep,
-            ep_issuer,
-            row[1].as_integer().unwrap() as u32,
-            row[7].as_integer().unwrap() as u64,
-        ) {
-            Ok(ep) => ep,
-            Err(e) => panic!(format!(
-                "Fail to parse endpoint : {} (Error: {:?})",
-                raw_ep, e
-            )),
-        };
-        ep.status = row[1].as_integer().unwrap() as u32;
-        ep.last_check = row[7].as_integer().unwrap() as u64;
+impl From<std::io::Error> for Ws2pPeersDbError {
+    fn from(e: std::io::Error) -> Self {
+        Ws2pPeersDbError::IoErr(e)
+    }
+}
 
-        endpoints.push(ep);
+impl From<bincode::Error> for Ws2pPeersDbError {
+    fn from(e: bincode::Error) -> Self {
+        Ws2pPeersDbError::SerdeErr(e)
     }
-    endpoints
 }
 
-pub fn write_endpoint(
-    db: &Connection,
-    endpoint: &EndpointV1,
-    new_status: u32,
-    new_last_check: u64,
-) {
-    let hash_full_id = endpoint
-        .node_full_id()
-        .expect("Fail to write endpoint : node_full_id() return None !")
-        .sha256();
-    // Check if endpoint it's already written
-    let mut cursor: Cursor = db
-        .prepare("SELECT status FROM endpoints WHERE hash_full_id=? ORDER BY status DESC;")
-        .expect("write_endpoint() : Error in SQL request !")
-        .cursor();
-    cursor
-        .bind(&[Value::String(hash_full_id.to_string())])
-        .expect("write_endpoint() : Error in cursor binding !");
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct DbEndpoint {
+    pub ep: EndpointV1,
+    pub state: WS2PConnectionState,
+    pub last_check: u64,
+}
 
-    // If endpoint it's already written, update status
-    if let Some(row) = cursor
-        .next()
-        .expect("write_endpoint() : Error in cursor.next()")
-    {
-        if row[0].as_integer().expect("fail to read ep status !") as u32 != endpoint.status {
-            db.execute(format!(
-                "UPDATE endpoints SET status={} WHERE hash_full_id='{}'",
-                endpoint.status, hash_full_id
-            ))
-            .expect("Fail to parse SQL request update endpoint  status !");
+pub fn get_endpoints(
+    file_path: &Path,
+) -> Result<HashMap<NodeFullId, DbEndpoint>, Ws2pPeersDbError> {
+    if file_path.exists() {
+        let bin_endpoints = durs_common_tools::read_bin_file(file_path)?;
+        if bin_endpoints.is_empty() {
+            Ok(HashMap::new())
+        } else {
+            Ok(bincode::deserialize(&bin_endpoints[..])?)
         }
     } else {
-        let ep_v10 = endpoint;
-        db
-                    .execute(
-                        format!(
-                            "INSERT INTO endpoints (hash_full_id, status, node_id, pubkey, api, version, endpoint, last_check) VALUES ('{}', {}, {}, '{}', {}, {}, '{}', {});",
-                            ep_v10.hash_full_id.expect("ep_v10.hash_full_id = None"), new_status, ep_v10.node_id.expect("ep_v10.node_id = None").0,
-                            ep_v10.issuer.to_string(), api_to_integer(&ep_v10.api),
-                            1, ep_v10.raw_endpoint, new_last_check
-                        )
-                    )
-                    .expect("Fail to parse SQL request INSERT endpoint !");
+        File::create(file_path)?;
+        Ok(HashMap::new())
     }
 }
+
+pub fn write_endpoints<S: std::hash::BuildHasher>(
+    file_path: &Path,
+    endpoints: &HashMap<NodeFullId, DbEndpoint, S>,
+) -> Result<(), Ws2pPeersDbError> {
+    let bin_endpoints = bincode::serialize(&endpoints)?;
+    durs_common_tools::write_bin_file(file_path, &bin_endpoints)?;
+
+    Ok(())
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws2p_requests.rs b/lib/modules/ws2p-v1-legacy/src/ws2p_requests.rs
deleted file mode 100644
index 7ba0058b..00000000
--- a/lib/modules/ws2p-v1-legacy/src/ws2p_requests.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use duniter_network::requests::OldNetworkRequest;
-
-pub fn network_request_to_json(request: &OldNetworkRequest) -> serde_json::Value {
-    let (request_id, request_type, request_params) = match *request {
-        OldNetworkRequest::GetCurrent(ref req_full_id) => (req_full_id.1, "CURRENT", json!({})),
-        OldNetworkRequest::GetBlocks(ref req_full_id, count, from_mumber) => (
-            req_full_id.1,
-            "BLOCKS_CHUNK",
-            json!({
-                "count": count,
-                "fromNumber": from_mumber
-            }),
-        ),
-        OldNetworkRequest::GetRequirementsPending(ref req_full_id, min_cert) => (
-            req_full_id.1,
-            "WOT_REQUIREMENTS_OF_PENDING",
-            json!({ "minCert": min_cert }),
-        ),
-        OldNetworkRequest::GetConsensus(_) => {
-            panic!("GetConsensus() request must be not convert to json !");
-        }
-        OldNetworkRequest::GetHeadsCache(_) => {
-            panic!("GetHeadsCache() request must be not convert to json !");
-        }
-        OldNetworkRequest::GetEndpoints(_) => {
-            panic!("GetEndpoints() request must be not convert to json !");
-        }
-    };
-
-    json!({
-        "reqId": request_id,
-        "body" : {
-            "name": request_type,
-            "params": request_params
-        }
-    })
-}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
new file mode 100644
index 00000000..d53b59ea
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
@@ -0,0 +1,241 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! WS2P connections handler.
+
+use super::messages::*;
+use super::meta_datas::WS2PConnectionMetaDatas;
+use super::states::WS2PConnectionState;
+use crate::constants::*;
+use crate::*;
+use dup_crypto::keys::*;
+use std::sync::mpsc;
+#[allow(deprecated)]
+use ws::util::{Timeout, Token};
+use ws::{CloseCode, Frame, Handler, Handshake, Message, Sender};
+
+const CONNECT: Token = Token(1);
+const EXPIRE: Token = Token(2);
+
+// Our Handler struct.
+// Here we explicity indicate that the Client needs a Sender,
+// whereas a closure captures the Sender for us automatically.
+#[allow(deprecated)]
+#[derive(Debug)]
+pub 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>,
+}
+
+pub fn connect_to_ws2p_endpoint(
+    endpoint: &EndpointV1,
+    conductor_sender: &mpsc::Sender<WS2PThreadSignal>,
+    currency: &str,
+    key_pair: KeyPairEnum,
+) -> ws::Result<()> {
+    // Get endpoint url
+    let ws_url = endpoint.get_url(true, false).expect("Endpoint unreachable");
+
+    // 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.issuer);
+    conn_meta_datas.remote_uuid = Some(
+        endpoint
+            .node_id
+            .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!("WS2P: Try connection to {} ...", ws_url);
+
+    // Connect to websocket
+    ws::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,
+    })
+}
+
+// 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 unwrap!(SystemTime::now().duration_since(self.last_mess_time))
+            > 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,
+                ),
+            ));
+    }
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs
new file mode 100644
index 00000000..d6465184
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/messages.rs
@@ -0,0 +1,291 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Define ws2p connections messages.
+
+use super::*;
+use durs_network_documents::NodeFullId;
+use ws::Message;
+
+#[derive(Debug)]
+/// WS2Pv1 connection Message
+pub struct WS2PConnectionMessage(pub NodeFullId, pub WS2PConnectionMessagePayload);
+
+#[derive(Debug)]
+/// WS2Pv1 connection Message payload
+pub enum WS2PConnectionMessagePayload {
+    FailOpenWS,
+    WrongUrl,
+    FailToSplitWS,
+    TryToSendConnectMess,
+    FailSendConnectMess,
+    WebsocketOk(WsSender),
+    NegociationTimeout,
+    ValidConnectMessage(String, WS2PConnectionState),
+    ValidAckMessage(String, WS2PConnectionState),
+    ValidOk(WS2PConnectionState),
+    DalRequest(ModuleReqId, serde_json::Value),
+    PeerCard(serde_json::Value, Vec<EndpointV1>),
+    Heads(Vec<serde_json::Value>),
+    Document(BlockchainDocument),
+    ReqResponse(ModuleReqId, serde_json::Value),
+    InvalidMessage,
+    WrongFormatMessage,
+    UnknowMessage,
+    Timeout,
+    Close,
+}
+
+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 !"),
+    )
+}
+
+pub fn ws2p_conn_message_pretreatment(
+    ws2p_module: &mut WS2PModule,
+    message: WS2PConnectionMessage,
+) -> WS2PSignal {
+    let ws2p_full_id = message.0;
+    match message.1 {
+        WS2PConnectionMessagePayload::WrongUrl
+        | WS2PConnectionMessagePayload::FailOpenWS
+        | WS2PConnectionMessagePayload::FailToSplitWS => {
+            let dal_ep = ws2p_module
+                .ws2p_endpoints
+                .get_mut(&ws2p_full_id)
+                .expect("WS2P: Fail to get mut ep !");
+            dal_ep.state = WS2PConnectionState::WSError;
+            dal_ep.last_check = durs_common_tools::current_timestamp();
+            return WS2PSignal::WSError(ws2p_full_id);
+        }
+        WS2PConnectionMessagePayload::TryToSendConnectMess => {
+            ws2p_module
+                .ws2p_endpoints
+                .get_mut(&ws2p_full_id)
+                .expect("WS2P: Fail to get mut ep !")
+                .state = WS2PConnectionState::TryToSendConnectMess;
+        }
+        WS2PConnectionMessagePayload::FailSendConnectMess => {
+            let dal_ep = ws2p_module
+                .ws2p_endpoints
+                .get_mut(&ws2p_full_id)
+                .expect("WS2P: Fail to get mut ep !");
+            dal_ep.state = WS2PConnectionState::Unreachable;
+            dal_ep.last_check = durs_common_tools::current_timestamp();
+        }
+        WS2PConnectionMessagePayload::WebsocketOk(sender) => {
+            ws2p_module.websockets.insert(ws2p_full_id, sender);
+        }
+        WS2PConnectionMessagePayload::ValidConnectMessage(response, new_con_state) => {
+            ws2p_module
+                .ws2p_endpoints
+                .get_mut(&ws2p_full_id)
+                .expect("WS2P: Fail to get mut ep !")
+                .state = new_con_state;
+            debug!("Send: {:#?}", response);
+            if let Some(websocket) = ws2p_module.websockets.get_mut(&ws2p_full_id) {
+                if websocket.0.send(Message::text(response)).is_err() {
+                    return WS2PSignal::WSError(ws2p_full_id);
+                }
+            } else {
+                // Connection closed by remote peer
+                let dal_ep = ws2p_module
+                    .ws2p_endpoints
+                    .get_mut(&ws2p_full_id)
+                    .expect("WS2P: Fail to get mut ep !");
+                dal_ep.state = WS2PConnectionState::Close;
+                dal_ep.last_check = durs_common_tools::current_timestamp();
+            }
+        }
+        WS2PConnectionMessagePayload::ValidAckMessage(response, new_con_state) => {
+            ws2p_module
+                .ws2p_endpoints
+                .get_mut(&ws2p_full_id)
+                .expect("WS2P: Fail to get mut ep !")
+                .state = new_con_state;
+            if let WS2PConnectionState::AckMessOk = ws2p_module.ws2p_endpoints[&ws2p_full_id].state
+            {
+                debug!("Send: {:#?}", response);
+                if let Some(websocket) = ws2p_module.websockets.get_mut(&ws2p_full_id) {
+                    if websocket.0.send(Message::text(response)).is_err() {
+                        return WS2PSignal::WSError(ws2p_full_id);
+                    }
+                } else {
+                    fatal_error!("Fatal error : no websocket for {} !", ws2p_full_id);
+                }
+            }
+        }
+        WS2PConnectionMessagePayload::ValidOk(new_con_state) => {
+            ws2p_module
+                .ws2p_endpoints
+                .get_mut(&ws2p_full_id)
+                .expect("WS2P: Fail to get mut ep !")
+                .state = new_con_state;
+            let mut close_conn = false;
+            let signal = match ws2p_module.ws2p_endpoints[&ws2p_full_id].state {
+                WS2PConnectionState::OkMessOkWaitingAckMess => WS2PSignal::Empty,
+                WS2PConnectionState::Established => WS2PSignal::ConnectionEstablished(ws2p_full_id),
+                _ => {
+                    close_conn = true;
+                    WS2PSignal::Empty
+                }
+            };
+            if close_conn {
+                close_connection(
+                    ws2p_module,
+                    &ws2p_full_id,
+                    WS2PCloseConnectionReason::Unknow,
+                );
+            }
+
+            return signal;
+        }
+        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 Ok(head) = NetworkHead::from_json_value(&head) {
+                    if head.verify()
+                        && (ws2p_module.my_head.is_none()
+                            || head.node_full_id()
+                                != ws2p_module
+                                    .my_head
+                                    .clone()
+                                    .expect("WS2P: Fail to clone my_head")
+                                    .node_full_id())
+                        && head.apply(&mut ws2p_module.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 ws2p_module.requests_awaiting_response.len() > req_id.0 as usize {
+                if let Some((ref ws2p_request, ref recipient_fulld_id, ref _timestamp)) =
+                    ws2p_module.requests_awaiting_response.remove(&req_id)
+                {
+                    return WS2PSignal::ReqResponse(
+                        req_id,
+                        *ws2p_request,
+                        *recipient_fulld_id,
+                        response,
+                    );
+                }
+            }
+        }
+        WS2PConnectionMessagePayload::NegociationTimeout => {
+            match ws2p_module.ws2p_endpoints[&ws2p_full_id].state {
+                WS2PConnectionState::AckMessOk | WS2PConnectionState::ConnectMessOk => {
+                    ws2p_module
+                        .ws2p_endpoints
+                        .get_mut(&ws2p_full_id)
+                        .expect("WS2P: Fail to get mut ep !")
+                        .state = WS2PConnectionState::Denial
+                }
+                WS2PConnectionState::WaitingConnectMess => {
+                    ws2p_module
+                        .ws2p_endpoints
+                        .get_mut(&ws2p_full_id)
+                        .expect("WS2P: Fail to get mut ep !")
+                        .state = WS2PConnectionState::NoResponse
+                }
+                _ => {
+                    let dal_ep = ws2p_module
+                        .ws2p_endpoints
+                        .get_mut(&ws2p_full_id)
+                        .expect("WS2P: Fail to get mut ep !");
+                    dal_ep.state = WS2PConnectionState::Unreachable;
+                    dal_ep.last_check = durs_common_tools::current_timestamp();
+                }
+            }
+            close_connection(
+                ws2p_module,
+                &ws2p_full_id,
+                WS2PCloseConnectionReason::NegociationTimeout,
+            );
+            return WS2PSignal::NegociationTimeout(ws2p_full_id);
+        }
+        WS2PConnectionMessagePayload::Timeout => {
+            close_connection(
+                ws2p_module,
+                &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 => close_connection(
+            ws2p_module,
+            &ws2p_full_id,
+            WS2PCloseConnectionReason::AuthMessInvalidSig,
+        ),
+    }
+    let connections_count = ws2p_module.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
+        ws2p_module.requests_awaiting_response.clone().values()
+    {
+        if unwrap!(SystemTime::now().duration_since(*timestamp)) > Duration::new(20, 0) {
+            requests_timeout.push(req.get_req_full_id());
+            warn!("request timeout : {:?} (sent to {:?})", req, ws2p_full_id);
+        }
+    }
+    // Delete (and resend) timeout requests
+    for req_id in requests_timeout {
+        //let ws2p_endpoints = ws2p_module.ws2p_endpoints.clone();
+        let _request_option = ws2p_module.requests_awaiting_response.remove(&req_id.1);
+        /*if let Some((request, _, _)) = request_option {
+            let _request_result = ws2p_module.send_request_to_specific_node(
+                &get_random_connection(&ws2p_endpoints),
+                &request,
+            );
+        }*/
+    }
+    WS2PSignal::Empty
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws2p_connection.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs
similarity index 52%
rename from lib/modules/ws2p-v1-legacy/src/ws2p_connection.rs
rename to lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs
index c25f3f60..e5b8950d 100644
--- a/lib/modules/ws2p-v1-legacy/src/ws2p_connection.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/meta_datas.rs
@@ -1,4 +1,22 @@
-use crate::constants::*;
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! WS2P connections meta datas.
+
+use super::messages::WS2PConnectionMessagePayload;
+use super::states::WS2PConnectionState;
 use crate::parsers::blocks::parse_json_block;
 use crate::*;
 use duniter_module::ModuleReqId;
@@ -6,294 +24,7 @@ use duniter_network::documents::BlockchainDocument;
 use dup_crypto::keys::*;
 use durs_network_documents::network_endpoint::{EndpointV1, NetworkEndpointApi};
 use durs_network_documents::NodeId;
-use rand::Rng;
-use std::sync::mpsc;
-use ws::deflate::DeflateBuilder;
-#[allow(deprecated)]
-use ws::util::{Timeout, Token};
-use ws::{connect, CloseCode, Frame, Handler, Handshake, Message, Sender};
-
-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 {{ }}")
-    }
-}
-
-// 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 {
-    Close,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum WS2PConnectionState {
-    NeverTry = 0,
-    TryToOpenWS = 1,
-    WSError = 2,
-    TryToSendConnectMess = 3,
-    Unreachable = 4,
-    WaitingConnectMess = 5,
-    NoResponse = 6,
-    ConnectMessOk = 7,
-    OkMessOkWaitingAckMess = 8,
-    AckMessOk = 9,
-    Denial = 10,
-    Close = 11,
-    Established = 12,
-}
-
-impl From<u32> for WS2PConnectionState {
-    fn from(integer: u32) -> Self {
-        match integer {
-            1 | 2 => WS2PConnectionState::WSError,
-            3 | 4 => WS2PConnectionState::Unreachable,
-            5 | 6 => WS2PConnectionState::NoResponse,
-            7 | 8 | 9 | 10 => WS2PConnectionState::Denial,
-            11 | 12 => WS2PConnectionState::Close,
-            _ => WS2PConnectionState::NeverTry,
-        }
-    }
-}
-
-impl WS2PConnectionState {
-    pub fn from_u32(integer: u32, from_db: bool) -> Self {
-        if from_db {
-            WS2PConnectionState::from(integer)
-        } else {
-            match integer {
-                1 => WS2PConnectionState::TryToOpenWS,
-                2 => WS2PConnectionState::WSError,
-                3 | 4 => WS2PConnectionState::Unreachable,
-                5 | 6 => WS2PConnectionState::NoResponse,
-                7 => WS2PConnectionState::ConnectMessOk,
-                8 => WS2PConnectionState::OkMessOkWaitingAckMess,
-                9 => WS2PConnectionState::AckMessOk,
-                10 => WS2PConnectionState::Denial,
-                11 => WS2PConnectionState::Close,
-                12 => WS2PConnectionState::Established,
-                _ => WS2PConnectionState::NeverTry,
-            }
-        }
-    }
-    pub fn to_u32(self) -> u32 {
-        match self {
-            WS2PConnectionState::NeverTry => 0,
-            _ => 1,
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum WS2PConnectionMessagePayload {
-    FailOpenWS,
-    WrongUrl,
-    FailToSplitWS,
-    TryToSendConnectMess,
-    FailSendConnectMess,
-    WebsocketOk(WsSender),
-    NegociationTimeout,
-    ValidConnectMessage(String, WS2PConnectionState),
-    ValidAckMessage(String, WS2PConnectionState),
-    ValidOk(WS2PConnectionState),
-    DalRequest(ModuleReqId, serde_json::Value),
-    PeerCard(serde_json::Value, Vec<EndpointV1>),
-    Heads(Vec<serde_json::Value>),
-    Document(BlockchainDocument),
-    ReqResponse(ModuleReqId, serde_json::Value),
-    InvalidMessage,
-    WrongFormatMessage,
-    UnknowMessage,
-    Timeout,
-    Close,
-}
-
-#[derive(Debug)]
-pub struct WS2PConnectionMessage(pub NodeFullId, pub WS2PConnectionMessagePayload);
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum WS2PCloseConnectionReason {
-    AuthMessInvalidSig,
-    NegociationTimeout,
-    Timeout,
-    WsError,
-    Unknow,
-}
-
 #[derive(Debug, Clone)]
 pub struct WS2PConnectionMetaDatas {
     pub state: WS2PConnectionState,
@@ -304,13 +35,6 @@ pub struct WS2PConnectionMetaDatas {
     pub current_blockstamp: Option<(u32, String)>,
 }
 
-#[derive(Debug, Clone)]
-pub struct WS2PDatasForListeningThread {
-    pub conn_meta_datas: WS2PConnectionMetaDatas,
-    pub currency: String,
-    pub key_pair: KeyPairEnum,
-}
-
 impl WS2PConnectionMetaDatas {
     pub fn new(challenge: String) -> Self {
         WS2PConnectionMetaDatas {
@@ -340,11 +64,11 @@ impl WS2PConnectionMetaDatas {
     ) -> WS2PConnectionMessagePayload {
         if let Some(s) = m.get("auth") {
             if s.is_string() {
-                match s.as_str().unwrap() {
+                match s.as_str().unwrap_or("") {
                     "CONNECT" => {
                         let message = WS2PConnectMessageV1::parse(m, currency.to_string())
                             .expect("Failed to parsing CONNECT Message !");
-                        if message.verify() && message.pubkey == self.remote_pubkey.unwrap() {
+                        if message.verify() && message.pubkey == unwrap!(self.remote_pubkey) {
                             match self.state {
                                 WS2PConnectionState::WaitingConnectMess => {
                                     debug!("CONNECT sig is valid.");
@@ -358,7 +82,7 @@ impl WS2PConnectionMetaDatas {
                                     };
                                     response.signature = Some(response.sign(key_pair));
                                     return WS2PConnectionMessagePayload::ValidConnectMessage(
-                                        serde_json::to_string(&response).unwrap(),
+                                        unwrap!(serde_json::to_string(&response)),
                                         self.state,
                                     );
                                 }
@@ -391,7 +115,7 @@ impl WS2PConnectionMetaDatas {
                             };
                             response.signature = Some(response.sign(key_pair));
                             return WS2PConnectionMessagePayload::ValidAckMessage(
-                                serde_json::to_string(&response).unwrap(),
+                                unwrap!(serde_json::to_string(&response)),
                                 self.state,
                             );
                         } else {
@@ -483,7 +207,7 @@ impl WS2PConnectionMetaDatas {
             match body.get("name") {
                 Some(s) => {
                     if s.is_string() {
-                        match s.as_str().unwrap() {
+                        match s.as_str().unwrap_or("") {
                             "BLOCK" => match body.get("block") {
                                 Some(block) => {
                                     if let Some(block_doc) = parse_json_block(&block) {
@@ -584,85 +308,3 @@ impl WS2PConnectionMetaDatas {
         }
     }
 }
-
-pub fn get_random_connection<S: ::std::hash::BuildHasher>(
-    connections: &HashMap<NodeFullId, (EndpointV1, 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: &EndpointV1,
-    conductor_sender: &mpsc::Sender<WS2PThreadSignal>,
-    currency: &str,
-    key_pair: KeyPairEnum,
-) -> ws::Result<()> {
-    // Get endpoint url
-    let ws_url = endpoint.get_url(true, false).expect("Endpoint unreachable");
-
-    // 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.issuer);
-    conn_meta_datas.remote_uuid = Some(
-        endpoint
-            .node_id
-            .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!("WS2P: Try connection to {} ...", ws_url);
-
-    // Connect to websocket
-    connect(ws_url, |ws| {
-        DeflateBuilder::new().build(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/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs
new file mode 100644
index 00000000..f18a33b9
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/mod.rs
@@ -0,0 +1,184 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Manage websockets connections.
+
+pub mod handler;
+pub mod messages;
+mod meta_datas;
+pub mod requests;
+pub mod states;
+
+use crate::*;
+use duniter_module::ModuleReqId;
+use duniter_network::documents::BlockchainDocument;
+use dup_crypto::keys::*;
+use durs_network_documents::network_endpoint::EndpointV1;
+use rand::Rng;
+use states::WS2PConnectionState;
+use std::collections::HashSet;
+#[allow(deprecated)]
+use ws::Sender;
+
+/// 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 {{ }}")
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum WS2PCloseConnectionReason {
+    AuthMessInvalidSig,
+    NegociationTimeout,
+    Timeout,
+    WsError,
+    Unknow,
+}
+
+pub fn connect_to_know_endpoints(ws2p_module: &mut WS2PModule) {
+    info!("WS2P: connect to know endpoints...");
+    let mut count_established_connections = 0;
+    let mut pubkeys = HashSet::new();
+    let mut reachable_endpoints = Vec::new();
+    let mut unreachable_endpoints = Vec::new();
+    for (_ws2p_full_id, DbEndpoint { ep, state, .. }) in ws2p_module.ws2p_endpoints.clone() {
+        if ep.issuer == ws2p_module.key_pair.public_key() || !pubkeys.contains(&ep.issuer) {
+            match state {
+                WS2PConnectionState::Established => count_established_connections += 1,
+                WS2PConnectionState::NeverTry
+                | WS2PConnectionState::Close
+                | WS2PConnectionState::Denial => {
+                    pubkeys.insert(ep.issuer);
+                    reachable_endpoints.push(ep);
+                }
+                _ => {
+                    pubkeys.insert(ep.issuer);
+                    unreachable_endpoints.push(ep);
+                }
+            }
+        }
+    }
+    let mut free_outcoming_rooms =
+        ws2p_module.conf.clone().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 !ws2p_module.ssl && ep.port == 443 {
+            continue;
+        }
+        connect_to_without_checking_quotas(ws2p_module, unwrap!(ep.node_full_id()));
+        free_outcoming_rooms -= 1;
+    }
+}
+
+pub fn connect_to(ws2p_module: &mut WS2PModule, ep: &EndpointV1) {
+    // Add endpoint to endpoints list (if there isn't already)
+    let node_full_id = ep
+        .node_full_id()
+        .expect("WS2P: Fail to get ep.node_full_id() !");
+    ws2p_module
+        .ws2p_endpoints
+        .entry(node_full_id)
+        .or_insert(DbEndpoint {
+            ep: ep.clone(),
+            state: WS2PConnectionState::NeverTry,
+            last_check: 0,
+        });
+    let count_established_connections = count_established_connections(&ws2p_module);
+    if ws2p_module.conf.outcoming_quota > count_established_connections {
+        connect_to_without_checking_quotas(ws2p_module, node_full_id);
+    }
+}
+
+pub fn connect_to_without_checking_quotas(ws2p_module: &mut WS2PModule, node_full_id: NodeFullId) {
+    let endpoint = unwrap!(ws2p_module.ws2p_endpoints.get(&node_full_id));
+    let endpoint_copy = endpoint.ep.clone();
+    let conductor_sender_copy = ws2p_module.main_thread_channel.0.clone();
+    let currency_copy = ws2p_module.currency.clone();
+    let key_pair_copy = ws2p_module.key_pair;
+    thread::spawn(move || {
+        let _result = crate::ws_connections::handler::connect_to_ws2p_endpoint(
+            &endpoint_copy,
+            &conductor_sender_copy,
+            &currency_copy.expect("WS2PError : No currency !"),
+            key_pair_copy,
+        );
+    });
+}
+
+pub fn close_connection(
+    ws2p_module: &mut WS2PModule,
+    ws2p_full_id: &NodeFullId,
+    reason: WS2PCloseConnectionReason,
+) {
+    match reason {
+        WS2PCloseConnectionReason::NegociationTimeout => {}
+        WS2PCloseConnectionReason::AuthMessInvalidSig
+        | WS2PCloseConnectionReason::Timeout
+        | WS2PCloseConnectionReason::WsError
+        | WS2PCloseConnectionReason::Unknow => {
+            if let Some(dal_ep) = ws2p_module.ws2p_endpoints.get_mut(ws2p_full_id) {
+                dal_ep.state = WS2PConnectionState::Close;
+                dal_ep.last_check = durs_common_tools::current_timestamp();
+            }
+        }
+    }
+    if let Some(websocket) = ws2p_module.websockets.get(&ws2p_full_id) {
+        let _result = websocket.0.close(ws::CloseCode::Normal);
+    }
+    let _result = ws2p_module.websockets.remove(ws2p_full_id);
+}
+
+pub fn get_random_connection<S: ::std::hash::BuildHasher>(
+    connections: &HashMap<NodeFullId, (EndpointV1, 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 count_established_connections(ws2p_module: &WS2PModule) -> usize {
+    let mut count_established_connections = 0;
+    for DbEndpoint { state, .. } in ws2p_module.ws2p_endpoints.values() {
+        if let WS2PConnectionState::Established = state {
+            count_established_connections += 1;
+        }
+    }
+    count_established_connections
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/mod.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/mod.rs
new file mode 100644
index 00000000..3dbfe5e9
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/mod.rs
@@ -0,0 +1,19 @@
+//  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/>.
+
+//! Sub-module managing the WS2Pv1 requests sent and received.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/received.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/received.rs
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/received.rs
@@ -0,0 +1 @@
+
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/sent.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/sent.rs
new file mode 100644
index 00000000..6a3b539b
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/requests/sent.rs
@@ -0,0 +1,77 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Sub-module managing the WS2Pv1 requests sent.
+
+use crate::WS2PModule;
+use duniter_network::requests::OldNetworkRequest;
+use durs_network_documents::NodeFullId;
+use std::time::SystemTime;
+use ws::Message;
+
+pub fn send_request_to_specific_node(
+    ws2p_module: &mut WS2PModule,
+    ws2p_full_id: &NodeFullId,
+    ws2p_request: &OldNetworkRequest,
+) -> ws::Result<()> {
+    if let Some(ws) = ws2p_module.websockets.get_mut(ws2p_full_id) {
+        let json_req = network_request_to_json(ws2p_request).to_string();
+        debug!("send request {} to {}", json_req, ws2p_full_id);
+        ws.0.send(Message::text(json_req))?;
+        ws2p_module.requests_awaiting_response.insert(
+            ws2p_request.get_req_id(),
+            (*ws2p_request, *ws2p_full_id, SystemTime::now()),
+        );
+    } else {
+        warn!("WS2P: Fail to get mut websocket !");
+    }
+    Ok(())
+}
+
+pub fn network_request_to_json(request: &OldNetworkRequest) -> serde_json::Value {
+    let (request_id, request_type, request_params) = match *request {
+        OldNetworkRequest::GetCurrent(ref req_full_id) => (req_full_id.1, "CURRENT", json!({})),
+        OldNetworkRequest::GetBlocks(ref req_full_id, count, from_mumber) => (
+            req_full_id.1,
+            "BLOCKS_CHUNK",
+            json!({
+                "count": count,
+                "fromNumber": from_mumber
+            }),
+        ),
+        OldNetworkRequest::GetRequirementsPending(ref req_full_id, min_cert) => (
+            req_full_id.1,
+            "WOT_REQUIREMENTS_OF_PENDING",
+            json!({ "minCert": min_cert }),
+        ),
+        OldNetworkRequest::GetConsensus(_) => {
+            panic!("GetConsensus() request must be not convert to json !");
+        }
+        OldNetworkRequest::GetHeadsCache(_) => {
+            panic!("GetHeadsCache() request must be not convert to json !");
+        }
+        OldNetworkRequest::GetEndpoints(_) => {
+            panic!("GetEndpoints() request must be not convert to json !");
+        }
+    };
+
+    json!({
+        "reqId": request_id,
+        "body" : {
+            "name": request_type,
+            "params": request_params
+        }
+    })
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/states.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/states.rs
new file mode 100644
index 00000000..48e91425
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/states.rs
@@ -0,0 +1,76 @@
+//  Copyright (C) 2018  The Durs 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/>.
+
+//! Define ws2p connections states.
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
+pub enum WS2PConnectionState {
+    NeverTry = 0,
+    TryToOpenWS = 1,
+    WSError = 2,
+    TryToSendConnectMess = 3,
+    Unreachable = 4,
+    WaitingConnectMess = 5,
+    NoResponse = 6,
+    ConnectMessOk = 7,
+    OkMessOkWaitingAckMess = 8,
+    AckMessOk = 9,
+    Denial = 10,
+    Close = 11,
+    Established = 12,
+}
+
+impl From<u32> for WS2PConnectionState {
+    fn from(integer: u32) -> Self {
+        match integer {
+            1 | 2 => WS2PConnectionState::WSError,
+            3 | 4 => WS2PConnectionState::Unreachable,
+            5 | 6 => WS2PConnectionState::NoResponse,
+            7 | 8 | 9 | 10 => WS2PConnectionState::Denial,
+            11 | 12 => WS2PConnectionState::Close,
+            _ => WS2PConnectionState::NeverTry,
+        }
+    }
+}
+
+impl WS2PConnectionState {
+    pub fn from_u32(integer: u32, from_db: bool) -> Self {
+        if from_db {
+            WS2PConnectionState::from(integer)
+        } else {
+            match integer {
+                1 => WS2PConnectionState::TryToOpenWS,
+                2 => WS2PConnectionState::WSError,
+                3 | 4 => WS2PConnectionState::Unreachable,
+                5 | 6 => WS2PConnectionState::NoResponse,
+                7 => WS2PConnectionState::ConnectMessOk,
+                8 => WS2PConnectionState::OkMessOkWaitingAckMess,
+                9 => WS2PConnectionState::AckMessOk,
+                10 => WS2PConnectionState::Denial,
+                11 => WS2PConnectionState::Close,
+                12 => WS2PConnectionState::Established,
+                _ => WS2PConnectionState::NeverTry,
+            }
+        }
+    }
+    pub fn to_u32(self) -> u32 {
+        match self {
+            WS2PConnectionState::NeverTry => 0,
+            _ => 1,
+        }
+    }
+}
-- 
GitLab


From c5cfa20ca07f20a8d1f5a51812b3d1d66c40e155 Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Thu, 25 Apr 2019 00:56:20 +0200
Subject: [PATCH 5/5] [build] Update Cargo.lock

---
 Cargo.lock | 45 ++++++++++++---------------------------------
 1 file changed, 12 insertions(+), 33 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 4f80ede3..7462c888 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -457,7 +457,6 @@ dependencies = [
  "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -548,22 +547,23 @@ dependencies = [
 name = "durs-ws2p-v1-legacy"
 version = "0.1.0-a0.1"
 dependencies = [
+ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "dubp-documents 0.12.0",
  "duniter-conf 0.1.0-a0.1",
  "duniter-module 0.1.0-a0.1",
  "duniter-network 0.1.0-a0.1",
  "dup-crypto 0.6.0",
+ "durs-common-tools 0.1.0",
  "durs-message 0.1.0-a0.1",
  "durs-network-documents 0.3.1",
  "durs-wot 0.8.0-a0.9",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1145,6 +1145,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "serde"
 version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "serde_derive"
@@ -1210,33 +1213,6 @@ name = "snowflake"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "sqlite"
-version = "0.23.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "sqlite3-src"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "sqlite3-sys"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite3-src 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "strsim"
 version = "0.7.0"
@@ -1377,6 +1353,11 @@ dependencies = [
  "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "unwrap"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "url"
 version = "1.7.2"
@@ -1571,9 +1552,6 @@ dependencies = [
 "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
 "checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15"
 "checksum snowflake 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
-"checksum sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d7b10278336e7fd9dc259399a0f9ff419616738b6a841b136c362e16db626"
-"checksum sqlite3-src 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "62cd5d67c1eb94a2a019b8049f625f65ae7faee8f3c54f0197e5dbc68d5f698c"
-"checksum sqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71fec807a1534bd13eeaaec396175d67c79bdc68df55e18a452726ec62a8fb08"
 "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
 "checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3"
 "checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04"
@@ -1592,6 +1570,7 @@ dependencies = [
 "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+"checksum unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e33648dd74328e622c7be51f3b40a303c63f93e6fa5f08778b6203a4c25c20f"
 "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
 "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
 "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
-- 
GitLab