Commit f61ed3f2 authored by Éloïs's avatar Éloïs

rework project architecture

parent ed65eadc
......@@ -7,11 +7,11 @@ members = [
"lib/core/module",
"lib/core/network",
"lib/modules/blockchain",
# "lib/modules/skeleton-module",
# "lib/modules/skeleton",
"lib/modules/tui",
"lib/modules/ws2p",
"lib/modules/ws2p-v1-legacy",
"lib/modules-lib/ws2p/ws2p-messages",
"lib/modules/ws2p/ws2p",
"lib/modules/ws2p/ws2p-messages",
"lib/tools/crypto",
"lib/tools/dal",
"lib/tools/documents",
......
......@@ -7,8 +7,8 @@ license = "AGPL-3.0"
[dependencies]
duniter-core = { path = "../../lib/core/core" }
# durs-skeleton-module = { path = "../../lib/modules/skeleton-module" }
durs-ws2p = { path = "../../lib/modules/ws2p" }
# durs-skeleton = { path = "../../lib/modules/skeleton" }
durs-ws2p = { path = "../../lib/modules/ws2p/ws2p" }
durs-ws2p-v1-legacy = { path = "../../lib/modules/ws2p-v1-legacy" }
structopt= "0.2.*"
......
[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 = "src/lib.rs"
[dependencies]
bincode = "1.0.*"
duniter-conf= { path = "../../core/conf" }
dup-crypto = { path = "../../tools/crypto" }
dubp-documents= { path = "../../tools/documents" }
durs-network-documents = { path = "../../tools/network-documents" }
durs-ws2p-messages = { path = "../../modules-lib/ws2p/ws2p-messages" }
duniter-message= { path = "../../core/message" }
duniter-module = { path = "../../core/module" }
duniter-network = { path = "../../core/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
......@@ -10,14 +10,14 @@ path = "src/lib.rs"
[dependencies]
bincode = "1.0.*"
duniter-conf= { path = "../conf" }
dup-crypto = { path = "../crypto" }
dubp-documents= { path = "../documents" }
durs-network-documents = { path = "../network-documents" }
duniter-conf= { path = "../../../core/conf" }
dup-crypto = { path = "../../../tools/crypto" }
dubp-documents= { path = "../../../tools/documents" }
durs-network-documents = { path = "../../../tools/network-documents" }
durs-ws2p-messages = { path = "../ws2p-messages" }
duniter-message= { path = "../message" }
duniter-module = { path = "../module" }
duniter-network = { path = "../network" }
duniter-message= { path = "../../../core/message" }
duniter-module = { path = "../../../core/module" }
duniter-network = { path = "../../../core/network" }
log = "0.4.*"
serde = "1.0.*"
serde_derive = "1.0.*"
......
// 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/>.
//! Defined all network documents
use dubp_documents::v10::block::BlockDocument;
use dubp_documents::v10::certification::CertificationDocument;
use dubp_documents::v10::identity::IdentityDocument;
use dubp_documents::v10::membership::MembershipDocument;
use dubp_documents::v10::revocation::RevocationDocument;
use dubp_documents::v10::transaction::TransactionDocument;
use dubp_documents::Document;
use dubp_documents::{BlockHash, BlockId, Blockstamp};
use serde_json;
use std::ops::Deref;
#[derive(Debug, Clone)]
/// Block v10 in network format (Some events require a blockchain access to reconstitute the corresponding document)
pub struct NetworkBlockV10 {
/// Uncompleted block document
pub uncompleted_block_doc: BlockDocument,
/// revoked
pub revoked: Vec<serde_json::Value>,
/// certifications
pub certifications: Vec<serde_json::Value>,
}
#[derive(Debug, Clone)]
/// Block in network format (Some events require a blockchain access to reconstitute the corresponding document)
pub enum NetworkBlock {
/// Block V1
V10(Box<NetworkBlockV10>),
/// Block V11
V11(),
}
impl NetworkBlock {
/// Return uncompleted block document
pub fn uncompleted_block_doc(&self) -> BlockDocument {
match *self {
NetworkBlock::V10(ref network_block_v10) => {
network_block_v10.deref().uncompleted_block_doc.clone()
}
_ => panic!("Block version not supported !"),
}
}
/// Return blockstamp
pub fn blockstamp(&self) -> Blockstamp {
match *self {
NetworkBlock::V10(ref network_block_v10) => {
network_block_v10.deref().uncompleted_block_doc.blockstamp()
}
_ => panic!("Block version not supported !"),
}
}
/// Return previous blockstamp
pub fn previous_blockstamp(&self) -> Blockstamp {
match *self {
NetworkBlock::V10(ref network_block_v10) => Blockstamp {
id: BlockId(network_block_v10.deref().uncompleted_block_doc.number.0 - 1),
hash: BlockHash(
network_block_v10
.deref()
.uncompleted_block_doc
.previous_hash,
),
},
_ => panic!("Block version not supported !"),
}
}
}
#[derive(Debug, Clone)]
/// Network Document
pub enum BlockchainDocument {
/// Network Block
Block(NetworkBlock),
/// Identity Document
Identity(Box<IdentityDocument>),
/// Membership Document
Membership(Box<MembershipDocument>),
/// Certification Document
Certification(Box<CertificationDocument>),
/// Revocation Document
Revocation(Box<RevocationDocument>),
/// Transaction Document
Transaction(Box<TransactionDocument>),
}
// 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/>.
//! Defined network events.
use documents::*;
use network_head::NetworkHead;
use network_peer::PeerCard;
use NodeFullId;
#[derive(Debug, Clone)]
/// Type containing a network event, each time a network event occurs it's relayed to all modules
pub enum NetworkEvent {
/// A connection has changed state(`u32` is the new state, `Option<String>` est l'uid du noeud)
ConnectionStateChange(NodeFullId, u32, Option<String>, String),
/// Receiving Pending Documents
ReceiveDocuments(Vec<BlockchainDocument>),
/// Receipt of peer cards
ReceivePeers(Vec<PeerCard>),
/// Receiving heads
ReceiveHeads(Vec<NetworkHead>),
}
// 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/>.
//! Defined network requests.
use documents::*;
use dubp_documents::Blockstamp;
use duniter_module::*;
use *;
#[derive(Debug, Copy, Clone)]
/// Type containing a request addressed to the network module
pub enum OldNetworkRequest {
/// Get a current block of a specific node
GetCurrent(ModuleReqFullId, NodeFullId),
//GetBlock(NodeFullId, u64),
/// Get a blocks chunk from specified node
GetBlocks(ModuleReqFullId, NodeFullId, u32, u32),
/// Get pending wot documents from specified node
GetRequirementsPending(ModuleReqFullId, NodeFullId, u32),
/// Obtain the current network consensus
GetConsensus(ModuleReqFullId),
/// Getting the heads cache
GetHeadsCache(ModuleReqFullId),
/// Get a list of known endpoints
GetEndpoints(ModuleReqFullId),
}
impl OldNetworkRequest {
/// Get request full identitifier
pub fn get_req_full_id(&self) -> ModuleReqFullId {
match *self {
OldNetworkRequest::GetCurrent(ref req_id, _)
| OldNetworkRequest::GetBlocks(ref req_id, _, _, _)
| OldNetworkRequest::GetRequirementsPending(ref req_id, _, _)
| OldNetworkRequest::GetConsensus(ref req_id)
| OldNetworkRequest::GetHeadsCache(ref req_id)
| OldNetworkRequest::GetEndpoints(ref req_id) => *req_id,
}
}
/// Get request identitifier
pub fn get_req_id(&self) -> ModuleReqId {
self.get_req_full_id().1
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Type returned when the network module does not get a satisfying answer to a request
pub enum OldNetworkRequestError {
/// Receiving an invalid format response
WrongFormat(),
/// Unknow error
UnknowError(),
/// No response received
NoResponse(),
/// Unable to reach the target node
ReceiverUnreachable(),
}
#[derive(Debug, Clone)]
/// Type containing the response to a network request
pub enum NetworkResponse {
/// CurrentBlock
CurrentBlock(ModuleReqFullId, NodeFullId, Box<NetworkBlock>),
/// Block
Block(ModuleReqFullId, NodeFullId, Box<NetworkBlock>),
/// Chunk
Chunk(ModuleReqFullId, NodeFullId, Vec<Box<NetworkBlock>>),
/// PendingDocuments
PendingDocuments(ModuleReqFullId, Vec<BlockchainDocument>),
/// Consensus
Consensus(ModuleReqFullId, Result<Blockstamp, NetworkConsensusError>),
/// HeadsCache
HeadsCache(ModuleReqFullId, Box<NetworkHead>),
}
impl NetworkResponse {
/// Get request full identifier
pub fn get_req_full_id(&self) -> ModuleReqFullId {
match *self {
NetworkResponse::CurrentBlock(ref req_id, _, _)
| NetworkResponse::Block(ref req_id, _, _)
| NetworkResponse::Chunk(ref req_id, _, _)
| NetworkResponse::PendingDocuments(ref req_id, _)
| NetworkResponse::Consensus(ref req_id, _)
| NetworkResponse::HeadsCache(ref req_id, _) => *req_id,
}
}
/// Get request identifier
pub fn get_req_id(&self) -> ModuleReqId {
self.get_req_full_id().1
}
}
// 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/>.
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_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 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,
) {
println!("DEBUG: Receive CONNECT message !");
// 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 !");
}
}
// Update Status to ConnectMessOk
handler.conn_datas.state = WS2PConnectionState::ConnectMessOk;
handler.send_new_conn_state_to_service();
// 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 dubp_documents::CurrencyName;
//use duniter_module::ModuleReqId;
use controllers::handler::Ws2pConnectionHandler;
use controllers::ws::deflate::DeflateBuilder;
use controllers::ws::listen;
use controllers::*;
use services::*;
//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);
println!("DEBUG: call function listen({}) ...", ws_url);
// Connect to websocket
listen(ws_url, move |ws| {
println!("DEBUG: Listen on host:port...");
DeflateBuilder::new().build(
Ws2pConnectionHandler::new(
WsSender(ws),
service_sender.clone(),
currency.clone(),
self_node.clone(),
Ws2pConnectionDatas::new(WS2Pv2ConnectType::Incoming),
)
.expect("WS2P Service unrechable"),
)
})
}
#[cfg(test)]
mod tests {
use super::*;
use dup_crypto::keys::*;
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() {
// create service channel
let (service_sender, _service_receiver): (
mpsc::Sender<Ws2pServiceSender>,
mpsc::Receiver<Ws2pServiceSender>,
) = mpsc::channel();
thread::spawn(move || {
let result = listen_on_ws2p_v2_endpoint(
&CurrencyName(String::from("default")),
service_sender,
MySelfWs2pNode {
my_node_id: NodeId(1),
my_key_pair: KeyPairEnum::Ed25519(keypair1()),
my_features: WS2PFeatures(vec![5u8]),
},
"localhost",
10899,
);
if let Err(e) = result {
panic!("Listen error: {}", e);
}
});
thread::sleep(Duration::from_secs(10));
// Force to print stdout
assert!(false);
}
}
// 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 controllers.
extern crate ws;
//use constants::*;
use self::ws::Sender;
use dubp_documents::Blockstamp;
use dup_crypto::hashs::Hash;
//use dup_crypto::keys::*;
use durs_network_documents::network_peer::PeerCardV11;
use durs_network_documents::*;
use durs_ws2p_messages::v2::api_features::WS2PFeatures;
use durs_ws2p_messages::v2::connect::WS2Pv2ConnectType;
use durs_ws2p_messages::*;
//use std::sync::mpsc;
use std::time::SystemTime;
pub mod handler;
pub mod incoming_connections;
pub mod outgoing_connections;
/// Order transmitted to the controller
#[derive(Debug, Clone)]
pub enum Ws2pControllerOrder {
/// Give a message to be transmitted
SendMsg(Box<WS2PMessage>),
/// Close the connection
Close,
}
/// 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)]
/// WS2P connection state
pub enum WS2PConnectionState {
/// Never try to establish this connection
NeverTry,
/// Try to open websocket
TryToOpenWS,
/// Websocket error
WSError,
/// Try to send connect message
TryToSendConnectMess,
/// Endpoint unreachable
Unreachable,
/// Waiting connect message
WaitingConnectMess,
/// No response
NoResponse,
/// Negociation timeout
NegociationTimeout,
/// Receive valid connect message
ConnectMessOk,
/// Receive valid OK message but wait ACK message
OkMessOkWaitingAckMess,
/// Receive valid ACK message
AckMessOk,
/// Connection denial (maybe due to many different reasons : receive wrong message, wrong format, wrong signature, etc)
Denial,
/// Connection closed
Close,