Commit 4382d616 authored by Éloïs's avatar Éloïs

[feat] WS2Pv2 controllers

parent ad7f960c
......@@ -448,7 +448,9 @@ dependencies = [
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.78 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......
......@@ -43,13 +43,61 @@ extern crate durs_network_documents;
/// WS2Pv2 Messages
pub mod v2;
use v2::WS2Pv0Message;
use dup_crypto::hashs::Hash;
use dup_crypto::keys::bin_signable::BinSignable;
use dup_crypto::keys::SigError;
use v2::WS2Pv2Message;
#[derive(Debug, Clone, Eq, PartialEq)]
/// WS2Pv0Message
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
/// WS2Pv2Message
pub enum WS2PMessage {
/// Version 2
V0(WS2Pv0Message),
V2(WS2Pv2Message),
}
/// Enumerate errors can happen when parsing and checking messages
#[derive(Debug)]
pub enum WS2PMessageError {
/// Error at deserialization
DeserError(bincode::Error),
/// Invalid hash
InvalidHash,
/// Invalid signature
SigError(SigError),
}
impl From<bincode::Error> for WS2PMessageError {
fn from(e: bincode::Error) -> Self {
WS2PMessageError::DeserError(e)
}
}
impl WS2PMessage {
/// Verify signature validity
pub fn verify(&self) -> Result<(), SigError> {
match *self {
WS2PMessage::V2(ref msg_v2) => msg_v2.verify(),
}
}
/// Get message hash
pub fn hash(&self) -> Option<Hash> {
match *self {
WS2PMessage::V2(ref msg_v2) => msg_v2.message_hash,
}
}
/// Parse and check bin message
pub fn parse_and_check_bin_message(bin_msg: &[u8]) -> Result<WS2PMessage, WS2PMessageError> {
let msg: WS2PMessage = bincode::deserialize(&bin_msg)?;
let hash = msg.hash();
if hash.is_some() && Hash::compute(&bin_msg) == hash.expect("safe unwrap") {
match msg.verify() {
Ok(()) => Ok(msg),
Err(e) => Err(WS2PMessageError::SigError(e)),
}
} else {
Err(WS2PMessageError::InvalidHash)
}
}
}
#[cfg(test)]
......@@ -65,8 +113,8 @@ mod tests {
use durs_network_documents::*;
use std::net::Ipv4Addr;
use std::str::FromStr;
use v2::payload_container::WS2Pv0MessagePayload;
use v2::WS2Pv0Message;
use v2::payload_container::WS2Pv2MessagePayload;
use v2::WS2Pv2Message;
pub fn keypair1() -> ed25519::KeyPair {
ed25519::KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate(
......@@ -117,10 +165,10 @@ mod tests {
}
}
pub fn test_ws2p_message(payload: WS2Pv0MessagePayload) {
pub fn test_ws2p_message(payload: WS2Pv2MessagePayload) {
let keypair1 = keypair1();
let mut ws2p_message = WS2Pv0Message {
currency_code: CurrencyName(String::from("g1")),
let mut ws2p_message = WS2Pv2Message {
currency_name: CurrencyName(String::from("g1")),
issuer_node_id: NodeId(0),
issuer_pubkey: PubKey::Ed25519(keypair1.public_key()),
payload,
......@@ -132,15 +180,15 @@ mod tests {
if let Ok(bin_msg) = sign_result {
// Test binarization
assert_eq!(
serialize(&ws2p_message).expect("Fail to serialize WS2Pv0Message !"),
serialize(&ws2p_message).expect("Fail to serialize WS2Pv2Message !"),
bin_msg
);
// Test sign
ws2p_message
.verify()
.expect("WS2Pv0Message : Invalid signature !");
.expect("WS2Pv2Message : Invalid signature !");
// Test debinarization
let debinarization_result: Result<WS2Pv0Message, bincode::Error> =
let debinarization_result: Result<WS2Pv2Message, bincode::Error> =
deserialize(&bin_msg);
if let Ok(ws2p_message2) = debinarization_result {
assert_eq!(ws2p_message, ws2p_message2);
......
......@@ -28,15 +28,38 @@ impl WS2PFeatures {
true
}
/// Check flag DEF
pub fn _def(&self) -> bool {
pub fn def(&self) -> bool {
self.0[0] | 0b1111_1110 == 255u8
}
/// Check flag LOW
pub fn _low(&self) -> bool {
pub fn low(&self) -> bool {
self.0[0] | 0b1111_1101 == 255u8
}
/// Check flag ABF
pub fn _abf(&self) -> bool {
pub fn abf(&self) -> bool {
self.0[0] | 0b1111_1011 == 255u8
}
/// Check features compatibility
pub fn check_features_compatibility(
&self,
remote_features: &WS2PFeatures,
) -> Result<WS2PFeatures, ()> {
let mut merged_features = self.clone();
// Remove features unsuported by remote node
if self.def() && !remote_features.def() {
merged_features.0[0] &= 0b1111_1110;
}
if self.low() && !remote_features.low() {
merged_features.0[0] &= 0b1111_1101;
}
if self.abf() && !remote_features.abf() {
merged_features.0[0] &= 0b1111_1011;
}
// Check incompatiblities
if remote_features.low() && !self.low() {
Err(())
} else {
Ok(merged_features)
}
}
}
// 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
......@@ -37,16 +37,62 @@ impl WS2PConnectFlags {
true
}
/// Check flag SYNC
pub fn _sync(&self) -> bool {
self.0[0] & 0b0000_0001 == 1u8
pub fn sync(&self) -> bool {
0b1111_1110 | self.0[0] == 255u8
}
/// Check flag ASK_SYNC_CHUNK
pub fn _ask_sync_chunk(&self) -> bool {
self.0[0] & 0b0000_0010 == 2u8
pub fn ask_sync_chunk(&self) -> bool {
0b1111_1101 | self.0[0] == 255u8
}
/// Check flag RES_SYNC_CHUNK
pub fn _res_sync_chunk(&self) -> bool {
self.0[0] & 0b0000_0100 == 4u8
pub fn res_sync_chunk(&self) -> bool {
0b1111_1011 | self.0[0] == 255u8
}
}
impl From<WS2Pv2ConnectType> for WS2PConnectFlags {
fn from(connect_type: WS2Pv2ConnectType) -> Self {
match connect_type {
WS2Pv2ConnectType::Classic | WS2Pv2ConnectType::Incoming => WS2PConnectFlags(vec![]),
WS2Pv2ConnectType::Sync(_) => WS2PConnectFlags(vec![1u8]),
WS2Pv2ConnectType::AskChunk(_) => WS2PConnectFlags(vec![3u8]),
WS2Pv2ConnectType::SendChunks => WS2PConnectFlags(vec![5u8]),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
/// WS2Pv2ConnectType
pub enum WS2Pv2ConnectType {
/// Classic outgoing connection
Classic,
/// Incoming connection
Incoming,
/// Sync outgoing connection (from blockstamp, or from genesis block if blockstamp is none)
Sync(Option<Blockstamp>),
/// Sync outgoing connection to request chunk
AskChunk(Blockstamp),
/// Sync outgoing connection to send chunk
SendChunks,
}
impl WS2Pv2ConnectType {
/// Create WS2Pv2ConnectType from WS2PConnectFlags
pub fn from_flags(
flags: &WS2PConnectFlags,
blockstamp: Option<Blockstamp>,
) -> WS2Pv2ConnectType {
if flags.sync() {
if flags.ask_sync_chunk() && blockstamp.is_some() {
WS2Pv2ConnectType::AskChunk(blockstamp.expect("safe unwrap"))
} else if flags.res_sync_chunk() {
WS2Pv2ConnectType::SendChunks
} else {
WS2Pv2ConnectType::Sync(blockstamp)
}
} else {
WS2Pv2ConnectType::Classic
}
}
}
......@@ -82,6 +128,27 @@ impl Default for WS2Pv2ConnectMsg {
}
}
/// Generate connect message
pub fn generate_connect_message(
connect_type: WS2Pv2ConnectType,
api_features: WS2PFeatures,
challenge: Hash,
peer_card: Option<PeerCardV11>,
) -> WS2Pv2ConnectMsg {
let chunkstamp = if let WS2Pv2ConnectType::AskChunk(chunkstamp) = connect_type {
Some(chunkstamp)
} else {
None
};
WS2Pv2ConnectMsg {
challenge,
api_features,
flags_queries: WS2PConnectFlags::from(connect_type),
peer_card,
chunkstamp,
}
}
#[cfg(test)]
mod tests {
use super::super::*;
......@@ -90,6 +157,24 @@ mod tests {
use dup_crypto::keys::text_signable::TextSignable;
use tests::*;
#[test]
fn test_ws2p_connect_flags() {
// test sync()
assert!(WS2PConnectFlags(vec![1u8]).sync());
assert!(WS2PConnectFlags(vec![3u8]).sync());
assert!(WS2PConnectFlags(vec![5u8]).sync());
// test ask_sync_chunk()
assert_eq!(WS2PConnectFlags(vec![1u8]).ask_sync_chunk(), false);
assert!(WS2PConnectFlags(vec![3u8]).ask_sync_chunk());
assert_eq!(WS2PConnectFlags(vec![5u8]).ask_sync_chunk(), false);
// test res_sync_chunk()
assert_eq!(WS2PConnectFlags(vec![1u8]).res_sync_chunk(), false);
assert_eq!(WS2PConnectFlags(vec![3u8]).res_sync_chunk(), false);
assert!(WS2PConnectFlags(vec![5u8]).res_sync_chunk());
}
#[test]
fn test_ws2p_message_connect() {
let keypair1 = keypair1();
......@@ -111,6 +196,6 @@ mod tests {
.unwrap(),
),
};
test_ws2p_message(WS2Pv0MessagePayload::Connect(Box::new(connect_msg)));
test_ws2p_message(WS2Pv2MessagePayload::Connect(Box::new(connect_msg)));
}
}
......@@ -38,29 +38,50 @@ use v2::payload_container::*;
/// WS2P v2 message metadata size
pub static WS2P_V2_MESSAGE_METADATA_SIZE: &'static usize = &144;
/// WS2Pv0Message
/// WS2Pv2Message
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct WS2Pv0Message {
pub struct WS2Pv2Message {
/// Currency name
pub currency_code: CurrencyName,
pub currency_name: CurrencyName,
/// Issuer NodeId
pub issuer_node_id: NodeId,
/// Issuer plublic key
pub issuer_pubkey: PubKey,
/// Message payload
pub payload: WS2Pv0MessagePayload,
pub payload: WS2Pv2MessagePayload,
/// Message hash
pub message_hash: Option<Hash>,
/// Signature
pub signature: Option<Sig>,
}
impl WS2Pv0Message {
impl WS2Pv2Message {
/// WS2P Version number
pub const WS2P_VERSION: u16 = 0;
/// Encapsulate message payload
pub fn encapsulate_payload(
currency_name: CurrencyName,
issuer_node_id: NodeId,
issuer_keypair: KeyPairEnum,
payload: WS2Pv2MessagePayload,
) -> Result<(WS2Pv2Message, Vec<u8>), SignError> {
let mut msg = WS2Pv2Message {
currency_name,
issuer_node_id,
issuer_pubkey: issuer_keypair.public_key(),
payload,
message_hash: None,
signature: None,
};
match msg.sign(issuer_keypair.private_key()) {
Ok(bin_msg) => Ok((msg, bin_msg)),
Err(e) => Err(e),
}
}
}
impl<'de> BinSignable<'de> for WS2Pv0Message {
impl<'de> BinSignable<'de> for WS2Pv2Message {
fn issuer_pubkey(&self) -> PubKey {
self.issuer_pubkey
}
......@@ -89,7 +110,7 @@ mod tests {
#[test]
fn test_ws2p_message_ack() {
test_ws2p_message(WS2Pv0MessagePayload::Ack(Hash::random()));
test_ws2p_message(WS2Pv2MessagePayload::Ack(Hash::random()));
}
#[test]
......@@ -98,6 +119,6 @@ mod tests {
let mut peer = create_peer_card_v11();
peer.sign(PrivKey::Ed25519(keypair1.private_key()))
.expect("Fail to sign peer card !");
test_ws2p_message(WS2Pv0MessagePayload::Peers(vec![peer]));
test_ws2p_message(WS2Pv2MessagePayload::Peers(vec![peer]));
}
}
......@@ -73,6 +73,6 @@ mod tests {
],
}),
};
test_ws2p_message(WS2Pv0MessagePayload::Ok(ok_msg));
test_ws2p_message(WS2Pv2MessagePayload::Ok(ok_msg));
}
}
......@@ -32,9 +32,9 @@ use durs_network_documents::network_peer::PeerCardV11;
/// WS2P v2 message payload metadata size
pub static WS2P_V2_MESSAGE_PAYLOAD_METADATA_SIZE: &'static usize = &8;
/// WS2Pv0MessagePayload
/// WS2Pv2MessagePayload
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum WS2Pv0MessagePayload {
pub enum WS2Pv2MessagePayload {
/// CONNECT message
Connect(Box<WS2Pv2ConnectMsg>),
/// ACK message
......
......@@ -71,7 +71,7 @@ mod tests {
id: 27,
body: WS2Pv2ReqResBody::None,
};
test_ws2p_message(WS2Pv0MessagePayload::ReqRes(response));
test_ws2p_message(WS2Pv2MessagePayload::ReqRes(response));
}
#[test]
......@@ -81,7 +81,7 @@ mod tests {
id: 28,
body: WS2Pv2ReqResBody::BadRequest(reason),
};
test_ws2p_message(WS2Pv0MessagePayload::ReqRes(response));
test_ws2p_message(WS2Pv2MessagePayload::ReqRes(response));
}
#[test]
......@@ -94,7 +94,7 @@ mod tests {
id: 28,
body: WS2Pv2ReqResBody::Current(blockstamp),
};
test_ws2p_message(WS2Pv0MessagePayload::ReqRes(response));
test_ws2p_message(WS2Pv2MessagePayload::ReqRes(response));
}
#[test]
......@@ -109,7 +109,7 @@ mod tests {
id: 29,
body: WS2Pv2ReqResBody::BlocksHashs(hashs),
};
test_ws2p_message(WS2Pv0MessagePayload::ReqRes(response));
test_ws2p_message(WS2Pv2MessagePayload::ReqRes(response));
}
#[test]
......@@ -119,6 +119,6 @@ mod tests {
id: 29,
body: WS2Pv2ReqResBody::WotPool(vec![cert_doc.clone(), cert_doc.clone()], vec![]),
};
test_ws2p_message(WS2Pv0MessagePayload::ReqRes(response));
test_ws2p_message(WS2Pv2MessagePayload::ReqRes(response));
}
}
......@@ -87,6 +87,6 @@ mod tests {
id: 27,
body: WS2Pv2RequestBody::ChunkByHash(chunkstamp),
};
test_ws2p_message(WS2Pv0MessagePayload::Request(request));
test_ws2p_message(WS2Pv2MessagePayload::Request(request));
}
}
......@@ -79,6 +79,6 @@ mod tests {
member_pubkey: Some(PubKey::Ed25519(keypair1.public_key())),
member_proof: Some(Sig::Ed25519(keypair1.private_key().sign(&challenge.0))),
};
test_ws2p_message(WS2Pv0MessagePayload::SecretFlags(msg));
test_ws2p_message(WS2Pv2MessagePayload::SecretFlags(msg));
}
}
......@@ -16,13 +16,16 @@
pub static WS2P_DEFAULT_OUTCOMING_QUOTA: &'static usize = &10;
/*pub static WS2P_OUTCOMING_INTERVAL_AT_STARTUP: &'static u64 = &75;
pub static WS2P_OUTCOMING_INTERVAL: &'static u64 = &300;
pub static WS2P_NEGOTIATION_TIMEOUT: &'static u64 = &15;
pub static WS2P_REQUEST_TIMEOUT: &'static u64 = &30;
pub static WS2P_EXPIRE_TIMEOUT: &'static u64 = &120;
pub static WS2P_OUTCOMING_INTERVAL: &'static u64 = &300;*/
pub static WS2P_NEGOTIATION_TIMEOUT: &'static u64 = &15_000;
pub static WS2P_EXPIRE_TIMEOUT_IN_SECS: &'static u64 = &120;
pub static WS2P_RECV_SERVICE_FREQ_IN_MS: &'static u64 = &1_000;
pub static WS2P_SPAM_INTERVAL_IN_MILLI_SECS: &'static u64 = &80;
pub static WS2P_SPAM_LIMIT: &'static usize = &6;
pub static WS2P_SPAM_SLEEP_TIME_IN_SEC: &'static u64 = &100;
pub static WS2P_INVALID_MSGS_LIMIT: &'static usize = &5;
/*
pub static WS2P_REQUEST_TIMEOUT: &'static u64 = &30_000;
pub static DURATION_BEFORE_RECORDING_ENDPOINT: &'static u64 = &180;
pub static BLOCKS_REQUEST_INTERVAL: &'static u64 = &60;
pub static PENDING_IDENTITIES_REQUEST_INTERVAL: &'static u64 = &40;
......
// 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
......@@ -46,6 +46,8 @@ extern crate durs_ws2p_messages;
mod constants;
mod generate_peer;
pub mod controllers;
pub mod services;
use constants::*;
use duniter_conf::DuRsConf;
......
[package]
name = "durs-ws2p"
version = "0.1.0-a0.1"
authors = ["librelois <elois@ifee.fr>"]
description = "WebSocketToPeer API for DURS Project."
license = "AGPL-3.0"
[lib]
path = "lib.rs"
[dependencies]
bincode = "1.0.*"
duniter-conf= { path = "../conf" }
dup-crypto = { path = "../crypto" }
dubp-documents= { path = "../documents" }
durs-network-documents = { path = "../network-documents" }
durs-ws2p-messages = { path = "../ws2p-messages" }
duniter-documents = { path = "../documents" }
duniter-message= { path = "../message" }
duniter-module = { path = "../module" }
duniter-network = { path = "../network" }
log = "0.4.*"
serde = "1.0.*"
serde_derive = "1.0.*"
serde_json = "1.0.*"
structopt= "0.2.*"
ws = { version = "0.7.*", features = ["permessage-deflate"] }
[features]
ssl = ["ws/ssl"]
# Treat warnings as a build error.
strict = []
\ No newline at end of file
// 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/>.
//! Process WS2P CONNECT mesage.
use controllers::handler::*;
use controllers::ws::CloseCode;
use controllers::*;
use durs_network_documents::NodeFullId;
use durs_ws2p_messages::v2::connect::WS2Pv2ConnectMsg;
//use services::Ws2pServiceSender;
//use std::sync::mpsc;
/// Process WS2pv2 CONNECT Message
pub fn process_ws2p_v2_connect_msg(
handler: &mut Ws2pConnectionHandler,
remote_full_id: NodeFullId,
connect_msg: &WS2Pv2ConnectMsg,
) {
// Get remote node datas
let remote_challenge = connect_msg.challenge;
let remote_node_datas = Ws2pRemoteNodeDatas {
challenge: connect_msg.challenge,
peer_card: None,
current_blockstamp: None,
};
if let WS2PConnectionState::WaitingConnectMess = handler.conn_datas.state {
// Check remote node datas
if let WS2Pv2ConnectType::Incoming = handler.conn_datas.connect_type {
handler.conn_datas.remote_full_id = Some(remote_full_id);
handler.conn_datas.remote_datas = Some(remote_node_datas);
// Get remote_connect_type
handler.conn_datas.remote_connect_type = Some(WS2Pv2ConnectType::from_flags(
&connect_msg.flags_queries,
connect_msg.chunkstamp,
));
} else {
let expected_full_id = handler
.conn_datas
.remote_full_id
.expect("Outcoming connection must have expected remote node full id !");
if remote_full_id == expected_full_id {
handler.conn_datas.remote_datas = Some(remote_node_datas);
} else {
let _ = handler
.ws
.0
.close_with_reason(CloseCode::Invalid, "Unexpected PUBKEY or NODE_ID !");
}
// Flags not allowed from incoming node
if !connect_msg.flags_queries.is_empty() {
let _ = handler.ws.0.close_with_reason(
CloseCode::Invalid,
"Unexpected CONNECT FLAGS from incoming node. !",
);
}
// Get remote_connect_type
handler.conn_datas.remote_connect_type = Some(WS2Pv2ConnectType::Incoming);
}
} else {
let _ = handler
.ws
.0
.close_with_reason(CloseCode::Invalid, "Unexpected CONNECT message !");
}
// Check features compatibility
match handler
.local_node
.my_features
.check_features_compatibility(&connect_msg.api_features)
{
Ok(merged_features) => handler.conn_datas.features = Some(merged_features),
Err(_) => {
let _ = handler
.ws
.0
.close_with_reason(CloseCode::Unsupported, "Unsupported features !");
}
}
// Encapsulate and binarize ACK message
let (_, bin_ack_msg) = WS2Pv2Message::encapsulate_payload(
handler.currency.clone(),
handler.local_node.my_node_id,
handler.local_node.my_key_pair,
WS2Pv2MessagePayload::Ack(remote_challenge),
)
.expect("WS2P : Fail to sign own ack message !");
// Send ACk Message
match handler.ws.0.send(Message::binary(bin_ack_msg)) {
Ok(()) => {
// Update state
handler.conn_datas.state = WS2PConnectionState::ConnectMessOk;
}
Err(_) => {
handler.conn_datas.state = WS2PConnectionState::Unreachable;
let _ = handler
.ws
.0
.close_with_reason(CloseCode::Error, "Fail to send ACk message !");
}
}
}
This diff is collapsed.
// 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 incoming connections controllers.
use duniter_documents::CurrencyName;
//use duniter_module::ModuleReqId;
use controllers::handler::Ws2pConnectionHandler;
use controllers::ws::deflate::DeflateBuilder;
use controllers::ws::listen;
use controllers::*;
use services::Ws2pServiceSender;
//use duniter_network::*;
use durs_ws2p_messages::v2::connect::WS2Pv2ConnectType;
use std::sync::mpsc;
/// Listen on WSPv2 host:port
pub fn listen_on_ws2p_v2_endpoint(
currency: &CurrencyName,
service_sender: mpsc::Sender<Ws2pServiceSender>,
self_node: MySelfWs2pNode,
host: &str,
port: u16,
) -> ws::Result<()> {
// Get endpoint url
let ws_url = format!("{}:{}", host, port);
// Log
info!("Listen on {} ...", ws_url);
// Connect to websocket
listen(ws_url, move |ws| {
DeflateBuilder::new().build(Ws2pConnectionHandler::new(
WsSender(ws),
service_sender.clone(),
currency.clone(),
self_node.clone(),
Ws2pConnectionDatas::new(WS2Pv2ConnectType::Incoming),
))
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
use std::time::Duration;
pub fn keypair1() -> ed25519::KeyPair {
ed25519::KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate(
"JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV".as_bytes(),
"JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV_".as_bytes(),
)
}
#[ignore]
#[test]
fn listen_on_localhost() {