diff --git a/Cargo.lock b/Cargo.lock index 6aaa53b4a3f149b50199f4402d00354e29381baf..a1bb5e00f6673d11ae1ad07dc71a151e605919a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,6 +217,7 @@ dependencies = [ "duniter-crypto 0.1.2", "duniter-message 0.1.0", "duniter-module 0.1.0", + "duniter-network 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -224,6 +225,7 @@ dependencies = [ "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "simplelog 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -369,7 +371,6 @@ dependencies = [ name = "durs" version = "0.1.0" dependencies = [ - "duniter-conf 0.1.0", "duniter-core 0.1.0", "duniter-tui 0.1.0", "duniter-ws2p 0.1.0", @@ -484,6 +485,17 @@ name = "libc" version = "0.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libz-sys" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "linked-hash-map" version = "0.5.1" @@ -1064,6 +1076,8 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1125,6 +1139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" +"checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" diff --git a/Cargo.toml b/Cargo.toml index 9674d5b625837386d3be78a46382d5f93dd7227c..3eecdcaed45e67aa65b3fbca4941d536e73be393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ description = "DUniter-RS (durs) is a new implementation of Duniter protocol and license = "AGPL-3.0" [dependencies] -duniter-conf = { path = "./conf" } duniter-core = { path = "./core" } duniter-tui = { path = "./tui", optional = true } duniter-ws2p = { path = "./ws2p" } diff --git a/blockchain/dbex.rs b/blockchain/dbex.rs index ebb8d5965553c17ec3f8beb66c8cb1180a104b50..8833738f3993a2946c23cfdf4551410098acbeda 100644 --- a/blockchain/dbex.rs +++ b/blockchain/dbex.rs @@ -28,7 +28,7 @@ pub enum DBExWotQuery { /// Ask distance of all members AllDistances(bool), /// Show members expire date - ExpireMembers(bool, bool), + ExpireMembers(bool), /// Show members list ListMembers(bool), /// Ask member datas @@ -51,14 +51,14 @@ pub enum DBExQuery { TxQuery(DBExTxQuery), } -pub fn dbex<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExQuery) { +pub fn dbex<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DBExQuery) { match *query { - DBExQuery::WotQuery(ref wot_query) => dbex_wot(profile, conf, wot_query), - DBExQuery::TxQuery(ref tx_query) => dbex_tx(profile, conf, tx_query), + DBExQuery::WotQuery(ref wot_query) => dbex_wot(profile, conf, csv, wot_query), + DBExQuery::TxQuery(ref tx_query) => dbex_tx(profile, conf, csv, tx_query), } } -pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExTxQuery) { +pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, _csv: bool, query: &DBExTxQuery) { // Get db path let db_path = duniter_conf::get_blockchain_db_path(profile, &conf.currency()); @@ -114,7 +114,7 @@ pub fn dbex_tx<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExTxQuery) { ); } -pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExWotQuery) { +pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DBExWotQuery) { // Get db path let db_path = duniter_conf::get_blockchain_db_path(profile, &conf.currency()); @@ -204,13 +204,17 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExWotQuery) for (wot_id, distance_datas) in distances_datas { let distance_percent: f64 = f64::from(distance_datas.success) / f64::from(distance_datas.sentries) * 100.0; - println!( - "{} -> distance: {:.2}% ({}/{})", - wot_uid_index[&wot_id], - distance_percent, - distance_datas.success, - distance_datas.sentries - ); + if csv { + println!("{}, {}", wot_uid_index[&wot_id], distance_percent,); + } else { + println!( + "{} -> distance: {:.2}% ({}/{})", + wot_uid_index[&wot_id], + distance_percent, + distance_datas.success, + distance_datas.sentries + ); + } } println!( "compute_distances_duration = {},{:03}.", @@ -218,7 +222,7 @@ pub fn dbex_wot<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExWotQuery) compute_distances_duration.subsec_nanos() / 1_000_000 ); } - DBExWotQuery::ExpireMembers(ref reverse, ref _csv) => { + DBExWotQuery::ExpireMembers(ref reverse) => { // Open blockchain database let blockchain_db = open_db::<LocalBlockchainV10Datas>(&db_path, "blockchain.db") .expect("Fail to open blockchain db"); diff --git a/blockchain/lib.rs b/blockchain/lib.rs index 49bb2e27088b9c6941a063b1773228b370163de6..a52ce9d8dbcc9f622503b52dfd9b429065b7f973 100644 --- a/blockchain/lib.rs +++ b/blockchain/lib.rs @@ -192,8 +192,8 @@ impl BlockchainModule { } } /// Databases explorer - pub fn dbex<DC: DuniterConf>(profile: &str, conf: &DC, req: &DBExQuery) { - dbex::dbex(profile, conf, req); + pub fn dbex<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, req: &DBExQuery) { + dbex::dbex(profile, conf, csv, req); } /// Synchronize blockchain from a duniter-ts database pub fn sync_ts<DC: DuniterConf>( diff --git a/core/Cargo.toml b/core/Cargo.toml index a748b2c0c33057fd6c478ef8b601f81ce2c3a8cb..1cfd1489f5cfb3774b4b2b4f5358c79bf592f58a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -15,6 +15,7 @@ duniter-conf = { path = "../conf" } duniter-crypto = { path = "../crypto" } duniter-message = { path = "../message" } duniter-module = { path = "../module" } +duniter-network = { path = "../network" } lazy_static = "1.0.0" log = "0.4.1" rand = "0.4.2" @@ -22,6 +23,7 @@ regex = "1.0.0" rust-crypto = "0.2.36" serde = "1.0.57" serde_derive = "1.0.57" +serde_json = "1.0.20" simplelog = "0.5.2" sqlite = "0.23.9" threadpool = "1.7.1" diff --git a/core/cli/en.yml b/core/cli/en.yml index f48ad39c470a09614e91eb64a45e998c9a675193..56657e63a56d771b255a543f46bf2f10572e2e8d 100644 --- a/core/cli/en.yml +++ b/core/cli/en.yml @@ -27,6 +27,30 @@ subcommands: about: start duniter server version: "0.1.0" author: Elois L. <elois@duniter.org> + - sync: + about: synchronization from network + version: "0.1.0" + author: Elois L. <elois@duniter.org> + args: + - DOMAIN_OR_IP: + help: The domain name or ip address of the node from which to synchronize. + index: 1 + required: true + - PORT: + help: The port number of the node from which to synchronize. + index: 2 + required: true + - PATH: + help: The endpoint path of the node from which to synchronize. + index: 3 + - cautious: + short: c + long: cautious + help: cautious mode (check all protocol rules, very slow) + - unsafe: + short: u + long: unsafe + help: unsafe mode (not check blocks inner hashs, very dangerous) - sync_ts: about: synchronization via a duniter-ts database version: "0.1.0" diff --git a/core/lib.rs b/core/lib.rs index f61af82f94a1c4a177467e160b68e951ae55009c..50cf7b326b3c8524dc915637e000b862ef2e6ed1 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -33,15 +33,18 @@ extern crate duniter_conf; extern crate duniter_crypto; extern crate duniter_message; extern crate duniter_module; +extern crate duniter_network; +extern crate serde_json; extern crate simplelog; extern crate sqlite; extern crate threadpool; use clap::{App, ArgMatches}; use duniter_blockchain::{BlockchainModule, DBExQuery, DBExTxQuery, DBExWotQuery}; -use duniter_conf::{DuRsConf, DuniterKeyPairs}; +pub use duniter_conf::{DuRsConf, DuniterKeyPairs}; use duniter_message::DuniterMessage; use duniter_module::*; +use duniter_network::{NetworkModule, SyncEndpoint}; use log::Level; use simplelog::*; use std::env; @@ -52,27 +55,34 @@ use std::thread; use std::time::Duration; use threadpool::ThreadPool; +#[derive(Debug, Clone)] +/// User command +pub enum UserCommand { + /// Start + Start(), + /// Sync (SyncEndpoint) + Sync(SyncEndpoint), + /// Other command + Other(), +} + #[derive(Debug)] /// Duniter Core Datas pub struct DuniterCore<DC: DuniterConf> { /// Does the entered command require to launch server ? - pub start: bool, - /// Software name - pub soft_name: &'static str, - /// Soft version - pub soft_version: &'static str, - /// User profile - pub profile: String, + pub user_command: UserCommand, + /// Software meta datas + pub soft_meta_datas: SoftwareMetaDatas<DC>, /// Keypairs pub keypairs: DuniterKeyPairs, - /// Duniter configuration - pub conf: DC, /// Run duration. Zero = infinite duration. pub run_duration_in_secs: u64, /// Sender channel of rooter thread pub rooter_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>, /// Count the number of plugged modules pub modules_count: usize, + /// Count the number of plugged network modules + pub network_modules_count: usize, /// ThreadPool that execute plugged modules pub thread_pool: ThreadPool, } @@ -115,16 +125,49 @@ impl DuniterCore<DuRsConf> { let (conf, keypairs) = duniter_conf::load_conf(profile.as_str()); info!("Success to load global conf."); + // Define SoftwareMetaDatas + let soft_meta_datas = SoftwareMetaDatas { + soft_name, + soft_version, + profile: profile.clone(), + conf: conf.clone(), + }; + if let Some(_matches) = cli_args.subcommand_matches("start") { Some(start( - soft_name, - soft_version, - &profile, + soft_meta_datas, keypairs, - conf, run_duration_in_secs, external_followers, )) + } else if let Some(matches) = cli_args.subcommand_matches("sync") { + let domain_or_ip = matches + .value_of("DOMAIN_OR_IP") + .expect("sync: you must enter a domain name or ip address !") + .to_string(); + let port: u16 = matches + .value_of("PORT") + .expect("sync: you must enter a port number !") + .parse() + .expect("sync: port : you must enter an integer value !"); + let path = if let Some(path) = matches.value_of("PATH") { + Some(path.to_string()) + } else { + None + }; + let sync_endpoint = SyncEndpoint { + domain_or_ip, + port, + path, + tls: false, + }; + Some(sync( + soft_meta_datas, + keypairs, + sync_endpoint, + matches.is_present("cautious"), + !matches.is_present("unsafe"), + )) } else if let Some(matches) = cli_args.subcommand_matches("sync_ts") { let ts_profile = matches.value_of("TS_PROFILE").unwrap_or("duniter_default"); sync_ts( @@ -141,6 +184,7 @@ impl DuniterCore<DuRsConf> { dbex( profile.as_str(), &conf, + csv, &DBExQuery::WotQuery(DBExWotQuery::AllDistances( distances_matches.is_present("reverse"), )), @@ -150,6 +194,7 @@ impl DuniterCore<DuRsConf> { dbex( profile.as_str(), &conf, + csv, &DBExQuery::WotQuery(DBExWotQuery::MemberDatas(String::from(uid))), ); } else if let Some(members_matches) = matches.subcommand_matches("members") { @@ -157,15 +202,16 @@ impl DuniterCore<DuRsConf> { dbex( profile.as_str(), &conf, + csv, &DBExQuery::WotQuery(DBExWotQuery::ExpireMembers( members_matches.is_present("reverse"), - csv, )), ); } else { dbex( profile.as_str(), &conf, + csv, &DBExQuery::WotQuery(DBExWotQuery::ListMembers( members_matches.is_present("reverse"), )), @@ -176,6 +222,7 @@ impl DuniterCore<DuRsConf> { dbex( &profile, &conf, + csv, &DBExQuery::TxQuery(DBExTxQuery::Balance(String::from(address))), ); } @@ -226,7 +273,10 @@ impl DuniterCore<DuRsConf> { } /// Start blockchain module pub fn start_blockchain(&self) { - if self.start { + if self.network_modules_count == 0 { + panic!("You must plug at least one network layer !"); + } + if let UserCommand::Start() = self.user_command { thread::sleep(Duration::from_secs(2)); // Create blockchain module channel let (blockchain_sender, blockchain_receiver): ( @@ -246,8 +296,8 @@ impl DuniterCore<DuRsConf> { // Instantiate blockchain module and load is conf let mut blockchain_module = BlockchainModule::load_blockchain_conf( - &self.profile, - &self.conf, + &self.soft_meta_datas.profile, + &self.soft_meta_datas.conf, RequiredKeysContent::MemberKeyPair(None), ); info!("Success to load Blockchain module."); @@ -256,34 +306,67 @@ impl DuniterCore<DuRsConf> { blockchain_module.start_blockchain(&blockchain_receiver); } } + /// Plug a network module + pub fn plug_network<NM: NetworkModule<DuRsConf, DuniterMessage>>(&mut self) { + if let UserCommand::Start() = self.user_command { + self.network_modules_count += 1; + self.plug::<NM>(); + } else if let UserCommand::Sync(ref sync_endpoint) = self.user_command { + self.network_modules_count += 1; + // Load module conf and keys + let (module_conf, required_keys) = self.load_module_conf_and_keys::<NM>(); + // Start module in a new thread + let rooter_sender = self.rooter_sender.clone(); + let soft_meta_datas = self.soft_meta_datas.clone(); + let sync_endpoint = sync_endpoint.clone(); + self.thread_pool.execute(move || { + NM::sync( + &soft_meta_datas, + required_keys, + &module_conf, + rooter_sender, + sync_endpoint, + ).expect(&format!( + "Fatal error : fail to load {} Module !", + NM::id().to_string() + )); + }); + self.modules_count += 1; + info!("Success to load {} module.", NM::id().to_string()); + } + } + /// Load module conf and keys + pub fn load_module_conf_and_keys<M: DuniterModule<DuRsConf, DuniterMessage>>( + &self, + ) -> (serde_json::value::Value, RequiredKeysContent) { + let module_conf = if let Some(module_conf_) = self + .soft_meta_datas + .conf + .clone() + .modules() + .get(&M::id().to_string().as_str()) + { + module_conf_.clone() + } else { + M::default_conf() + }; + let required_keys = + DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), self.keypairs); + + (module_conf, required_keys) + } /// Plug a module pub fn plug<M: DuniterModule<DuRsConf, DuniterMessage>>(&mut self) { - if self.start { + if let UserCommand::Start() = self.user_command { + // Load module conf and keys + let (module_conf, required_keys) = self.load_module_conf_and_keys::<M>(); // Start module in a new thread - let soft_name_clone = &(*self.soft_name); - let soft_version_clone = &(*self.soft_version); - let required_keys = - DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), self.keypairs); - let module_conf = if let Some(module_conf_) = self - .conf - .clone() - .modules() - .get(&M::id().to_string().as_str()) - { - module_conf_.clone() - } else { - M::default_conf() - }; let rooter_sender_clone = self.rooter_sender.clone(); - let conf_clone = self.conf.clone(); - let profile_copy = self.profile.clone(); + let soft_meta_datas = self.soft_meta_datas.clone(); self.thread_pool.execute(move || { M::start( - soft_name_clone, - soft_version_clone, - &profile_copy, + &soft_meta_datas, required_keys, - &conf_clone, &module_conf, rooter_sender_clone, false, @@ -303,18 +386,11 @@ pub fn match_profile(cli_args: &ArgMatches) -> String { String::from(cli_args.value_of("profile").unwrap_or("default")) } -/// Launch duniter server -pub fn start<DC: DuniterConf>( - soft_name: &'static str, - soft_version: &'static str, - profile: &str, - keypairs: DuniterKeyPairs, - conf: DC, +/// Start rooter thread +pub fn start_rooter<DC: DuniterConf>( run_duration_in_secs: u64, external_followers: Vec<mpsc::Sender<DuniterMessage>>, -) -> DuniterCore<DC> { - info!("Starting Duniter-rs..."); - +) -> mpsc::Sender<RooterThreadMessage<DuniterMessage>> { // Create senders channel let (rooter_sender, main_receiver): ( mpsc::Sender<RooterThreadMessage<DuniterMessage>>, @@ -408,17 +484,54 @@ pub fn start<DC: DuniterConf>( } }); + rooter_sender +} + +/// Launch duniter server +pub fn start<DC: DuniterConf>( + soft_meta_datas: SoftwareMetaDatas<DC>, + keypairs: DuniterKeyPairs, + run_duration_in_secs: u64, + external_followers: Vec<mpsc::Sender<DuniterMessage>>, +) -> DuniterCore<DC> { + info!("Starting Duniter-rs..."); + + // Start rooter thread + let rooter_sender = start_rooter::<DC>(run_duration_in_secs, external_followers); + // Instanciate DuniterCore DuniterCore { - start: true, - soft_name, - soft_version, - profile: profile.to_string(), + user_command: UserCommand::Start(), + soft_meta_datas, keypairs, - conf, run_duration_in_secs, rooter_sender, modules_count: 0, + network_modules_count: 0, + thread_pool: ThreadPool::new(2), + } +} + +/// Launch synchronisation from network +pub fn sync<DC: DuniterConf>( + soft_meta_datas: SoftwareMetaDatas<DC>, + keypairs: DuniterKeyPairs, + sync_endpoint: SyncEndpoint, + _cautious: bool, + _verif_hashs: bool, +) -> DuniterCore<DC> { + // Start rooter thread + let rooter_sender = start_rooter::<DC>(0, vec![]); + + // Instanciate DuniterCore + DuniterCore { + user_command: UserCommand::Sync(sync_endpoint), + soft_meta_datas, + keypairs, + run_duration_in_secs: 0, + rooter_sender, + modules_count: 0, + network_modules_count: 0, thread_pool: ThreadPool::new(2), } } @@ -436,9 +549,9 @@ pub fn sync_ts<DC: DuniterConf>( } /// Launch databases explorer -pub fn dbex<DC: DuniterConf>(profile: &str, conf: &DC, query: &DBExQuery) { +pub fn dbex<DC: DuniterConf>(profile: &str, conf: &DC, csv: bool, query: &DBExQuery) { // Launch databases explorer - BlockchainModule::dbex(profile, conf, query); + BlockchainModule::dbex(profile, conf, csv, query); } /// Initialize logger diff --git a/module/lib.rs b/module/lib.rs index 7707d3127cebf2484cedd1e1ee2e03599caf5be6..1bc026b423fd9d7c0b948d341044ac065bd1c932 100644 --- a/module/lib.rs +++ b/module/lib.rs @@ -128,6 +128,19 @@ pub trait DuniterConf: Clone + Debug + Default + PartialEq + Serialize + Deseria fn modules(&self) -> serde_json::Value; } +/// Sofware meta datas +#[derive(Debug, Clone)] +pub struct SoftwareMetaDatas<DC: DuniterConf> { + /// Software name + pub soft_name: &'static str, + /// Software version + pub soft_version: &'static str, + /// User profile + pub profile: String, + /// User configuration + pub conf: DC, +} + /// The different modules of Duniter-rs can exchange messages with the type of their choice, /// provided that this type implements the ModuleMessage trait. pub trait ModuleMessage: Clone + Debug {} @@ -203,11 +216,8 @@ pub trait DuniterModule<DC: DuniterConf, M: ModuleMessage> { fn default_conf() -> serde_json::Value; /// Launch the module fn start( - soft_name: &str, - soft_version: &str, - profile: &str, + soft_meta_datas: &SoftwareMetaDatas<DC>, keys: RequiredKeysContent, - conf: &DC, module_conf: &serde_json::Value, main_sender: mpsc::Sender<RooterThreadMessage<M>>, load_conf_only: bool, diff --git a/network/lib.rs b/network/lib.rs index 60478a07f67c1d716d5ab809a98484600791cf0b..a25307910c632fc655b52004d6b610258933e2e2 100644 --- a/network/lib.rs +++ b/network/lib.rs @@ -45,11 +45,37 @@ use duniter_documents::blockchain::v10::documents::{ }; use duniter_documents::blockchain::Document; use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash}; -use duniter_module::{ModuleReqFullId, ModuleReqId}; +use duniter_module::*; use network_head::NetworkHead; use network_peer::NetworkPeer; use std::fmt::{Debug, Display, Error, Formatter}; use std::ops::Deref; +use std::sync::mpsc; + +/// NetworkModule +pub trait NetworkModule<DC: DuniterConf, M: ModuleMessage>: DuniterModule<DC, M> { + /// Launch synchronisation + fn sync( + soft_meta_datas: &SoftwareMetaDatas<DC>, + keys: RequiredKeysContent, + module_conf: &serde_json::Value, + main_sender: mpsc::Sender<RooterThreadMessage<M>>, + sync_endpoint: SyncEndpoint, + ) -> Result<(), ModuleInitError>; +} + +#[derive(Debug, Clone)] +/// Synchronisation endpoint +pub struct SyncEndpoint { + /// Domaine name or IP + pub domain_or_ip: String, + /// Port number + pub port: u16, + /// Optionnal path + pub path: Option<String>, + /// Use TLS + pub tls: bool, +} #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] /// Random identifier with which several Duniter nodes with the same network keypair can be differentiated diff --git a/src/main.rs b/src/main.rs index 2c9748b753cca19bed36b90d3c2a173191380309..eacbede7127d6d3001943d637eac47312c4f8c02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,13 +21,13 @@ trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, unused_qualifications )] -extern crate duniter_conf; + extern crate duniter_core; #[cfg(feature = "tui")] extern crate duniter_tui; extern crate duniter_ws2p; -pub use duniter_conf::DuRsConf; +pub use duniter_core::DuRsConf; pub use duniter_core::DuniterCore; #[cfg(feature = "tui")] pub use duniter_tui::TuiModule; @@ -47,7 +47,7 @@ fn main() { //duniter_core.plug::<PoolModule>(); //duniter_core.plug::<PowModule>(); plug_tui_module(&mut duniter_core); - duniter_core.plug::<WS2PModule>(); + duniter_core.plug_network::<WS2PModule>(); duniter_core.start_blockchain(); }; } diff --git a/tui/lib.rs b/tui/lib.rs index 55028786e5443704466389bbab4b07d6b0506fce..3e877a8af94ebd3f586bab9df07b64db81b3466f 100644 --- a/tui/lib.rs +++ b/tui/lib.rs @@ -362,11 +362,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for TuiModule { serde_json::Value::default() } fn start( - _soft_name: &str, - _soft_version: &str, - _profile: &str, + _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, _keys: RequiredKeysContent, - _conf: &DuRsConf, module_conf: &serde_json::Value, main_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>, load_conf_only: bool, diff --git a/ws2p/Cargo.toml b/ws2p/Cargo.toml index 2b4b0f4debae043a864f4cab75c1652ddbc8ce63..89d3ace4289a8c9dc78deb4d03639a25bb60f26f 100644 --- a/ws2p/Cargo.toml +++ b/ws2p/Cargo.toml @@ -26,7 +26,7 @@ sqlite = "0.23.9" serde = "1.0.24" serde_derive = "1.0.24" serde_json = "1.0.20" -ws = "0.7.6" +ws = { version = "0.7.6", features = ["permessage-deflate"] } [features] ssl = ["ws/ssl"] diff --git a/ws2p/lib.rs b/ws2p/lib.rs index 5a25d52b0e902eb6aed2987d246e87d22c84ff56..277934e848a7c82fa127f2a7b3ee8ba110a6e9c4 100644 --- a/ws2p/lib.rs +++ b/ws2p/lib.rs @@ -147,6 +147,20 @@ impl Default for WS2PModule { } } +impl NetworkModule<DuRsConf, DuniterMessage> for WS2PModule { + fn sync( + _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, + _keys: RequiredKeysContent, + _module_conf: &serde_json::Value, + _main_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>, + _sync_endpoint: SyncEndpoint, + ) -> Result<(), ModuleInitError> { + println!("Downlaod blockchain from network..."); + println!("Error : not yet implemented !"); + Ok(()) + } +} + impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { fn id() -> ModuleId { ModuleId(String::from("ws2p")) @@ -169,11 +183,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { }) } fn start( - soft_name: &str, - soft_version: &str, - profile: &str, + soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, keys: RequiredKeysContent, - duniter_conf: &DuRsConf, module_conf: &serde_json::Value, rooter_sender: mpsc::Sender<RooterThreadMessage<DuniterMessage>>, load_conf_only: bool, @@ -198,7 +209,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { RequiredKeysContent::NetworkKeyPair(key_pair) => key_pair, _ => panic!("WS2PModule fatal error at load_conf() : keys != NetworkKeyPair"), }; - let conf = WS2PModuleDatas::parse_ws2p_conf(duniter_conf, module_conf); + let conf = WS2PModuleDatas::parse_ws2p_conf(&soft_meta_datas.conf, module_conf); let mut ws2p_endpoints = HashMap::new(); for ep in conf.sync_endpoints.clone() { ws2p_endpoints.insert( @@ -209,7 +220,7 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { info!("Load sync endpoint {}", ep.raw()); } ws2p_module.key_pair = Some(key_pair); - ws2p_module.currency = Some(duniter_conf.currency().to_string()); + ws2p_module.currency = Some(soft_meta_datas.conf.currency().to_string()); ws2p_module.conf = Some(conf.clone()); ws2p_module.ws2p_endpoints = ws2p_endpoints; @@ -248,7 +259,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { }); // open ws2p bdd - let mut db_path = duniter_conf::datas_path(profile, &duniter_conf.currency()); + 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 !"); @@ -315,8 +327,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { ws2p_module.my_head = Some(heads::generate_my_head( &key_pair, &conf.clone(), - soft_name, - soft_version, + soft_meta_datas.soft_name, + soft_meta_datas.soft_version, ¤t_blockstamp, None, )); @@ -401,8 +413,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { ws2p_module.my_head = Some(heads::generate_my_head( &key_pair, &conf.clone(), - soft_name, - soft_version, + soft_meta_datas.soft_name, + soft_meta_datas.soft_version, ¤t_blockstamp, None, )); @@ -454,8 +466,8 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { Some(heads::generate_my_head( &key_pair, &conf.clone(), - soft_name, - soft_version, + soft_meta_datas.soft_name, + soft_meta_datas.soft_version, ¤t_blockstamp, None, )); @@ -630,7 +642,10 @@ impl DuniterModule<DuRsConf, DuniterMessage> for WS2PModule { WS2PSignal::ReqResponse(req_id, req, recipient_full_id, response) => { match req { NetworkRequest::GetCurrent(ref _req_id, _receiver) => { - info!("WS2PSignal::ReceiveCurrent({}, {:?})", req_id.0, req); + info!( + "WS2PSignal::ReceiveCurrent({}, {:?}, {:#?})", + req_id.0, req, response + ); if let Some(block) = parse_json_block(&response) { ws2p_module.send_network_event(&NetworkEvent::ReqResponse( Box::new(NetworkResponse::CurrentBlock( diff --git a/ws2p/ws2p_connection.rs b/ws2p/ws2p_connection.rs index 214ef3290051b81a56f39d3cc5cb787fc6ead58e..5c1be57d031e136b4a053ee8f4479d134e3ead45 100644 --- a/ws2p/ws2p_connection.rs +++ b/ws2p/ws2p_connection.rs @@ -6,6 +6,7 @@ use duniter_network::{NetworkDocument, NodeUUID}; use parsers::blocks::parse_json_block; 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}; @@ -617,17 +618,19 @@ pub fn connect_to_ws2p_endpoint( info!("Try connection to {} ...", ws_url); // Connect to websocket - connect(ws_url, |ws| Client { - ws, - conductor_sender: conductor_sender.clone(), - currency: String::from(currency), - key_pair, - connect_message: connect_message.clone(), - conn_meta_datas: conn_meta_datas.clone(), - last_mess_time: SystemTime::now(), - spam_interval: false, - spam_counter: 0, - timeout: None, + 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, + }) }) }