diff --git a/Cargo.lock b/Cargo.lock index eb3b85a8743437a0d1ad4b4a303740cd8d6bb887..36fad37cd74fe9c995a48b042434abf12d114f38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,6 +389,7 @@ dependencies = [ "dup-crypto 0.6.0", "durs-common-tools 0.1.0", "durs-module 0.1.0-a0.1", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -418,6 +419,7 @@ dependencies = [ "simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/doc/en/dev/developing-a-durs-module.md b/doc/en/dev/developing-a-durs-module.md index c1dc07ddd5fe097dbd55e73d983b09649821d886..4454ef412f39c54ceb8236ee2a8567ec4590135b 100644 --- a/doc/en/dev/developing-a-durs-module.md +++ b/doc/en/dev/developing-a-durs-module.md @@ -216,8 +216,9 @@ If you do have a subcommand, simply return `true`. soft_meta_datas: &SoftwareMetaDatas<DC>, keys: RequiredKeysContent, module_conf: Self::ModuleConf, + module_user_conf: Option<Self::ModuleUserConf>, subcommand_args: Self::ModuleOpt, - ) { + ) -> Option<Self::ModuleUserConf> { } ``` diff --git a/doc/fr/developpeurs/developper-un-module-durs.md b/doc/fr/developpeurs/developper-un-module-durs.md index 9d2d50ca41360c8a915c936b754c9fc9f2498f9c..2292390308b3c71941ae1d48fcc15cc665e40351 100644 --- a/doc/fr/developpeurs/developper-un-module-durs.md +++ b/doc/fr/developpeurs/developper-un-module-durs.md @@ -225,8 +225,9 @@ Déclaration : soft_meta_datas: &SoftwareMetaDatas<DC>, keys: RequiredKeysContent, module_conf: Self::ModuleConf, + module_user_conf: Option<Self::ModuleUserConf>, subcommand_args: Self::ModuleOpt, - ) { + ) -> Option<Self::ModuleUserConf> { } ``` diff --git a/lib/core/conf/Cargo.toml b/lib/core/conf/Cargo.toml index 49eb83631465a2cd9206c35c1e07f4887471218d..9094937b9d3b69d1d6c03b6a63087bccc9ff5d55 100644 --- a/lib/core/conf/Cargo.toml +++ b/lib/core/conf/Cargo.toml @@ -15,6 +15,7 @@ dup-crypto = { path = "../../tools/crypto" } dubp-documents= { path = "../../tools/documents" } durs-module = { path = "../module" } durs-common-tools = { path = "../../tools/common-tools" } +failure = "0.1.5" log = "0.4.*" rand = "0.4.*" serde = "1.0.*" diff --git a/lib/core/conf/src/lib.rs b/lib/core/conf/src/lib.rs index c60668367f79b56b592ba78ce9f4d28a73b7b331..85910f6ed466662ba2d1a0b918319f1ff4814291 100644 --- a/lib/core/conf/src/lib.rs +++ b/lib/core/conf/src/lib.rs @@ -41,6 +41,7 @@ use durs_common_tools::fatal_error; use durs_module::{ DursConfTrait, DursGlobalConfTrait, ModuleName, RequiredKeys, RequiredKeysContent, }; +use failure::Fail; use rand::Rng; use serde::ser::{Serialize, SerializeStruct, Serializer}; use std::collections::HashSet; @@ -503,9 +504,9 @@ pub fn keypairs_filepath(profiles_path: &Option<PathBuf>, profile: &str) -> Path pub fn load_conf( mut profile_path: PathBuf, keypairs_file_path: &Option<PathBuf>, -) -> (DuRsConf, DuniterKeyPairs) { +) -> Result<(DuRsConf, DuniterKeyPairs), DursConfFileError> { // Load conf - let (conf, keypairs) = load_conf_at_path(profile_path.clone(), keypairs_file_path); + let (conf, keypairs) = load_conf_at_path(profile_path.clone(), keypairs_file_path)?; // Create currency dir profile_path.push(conf.currency().to_string()); @@ -514,7 +515,21 @@ pub fn load_conf( } // Return conf and keypairs - (conf, keypairs) + Ok((conf, keypairs)) +} + +/// Error with configuration file +#[derive(Debug, Fail)] +pub enum DursConfFileError { + /// Read error + #[fail(display = "fail to read configuration file: {}", _0)] + ReadError(std::io::Error), + /// Parse error + #[fail(display = "fail to parse configuration file: {}", _0)] + ParseError(serde_json::Error), + /// Write error + #[fail(display = "fail to write configuration file: {}", _0)] + WriteError(std::io::Error), } /// Load configuration. at specified path @@ -522,7 +537,7 @@ pub fn load_conf( pub fn load_conf_at_path( profile_path: PathBuf, keypairs_file_path: &Option<PathBuf>, -) -> (DuRsConf, DuniterKeyPairs) { +) -> Result<(DuRsConf, DuniterKeyPairs), DursConfFileError> { // Get KeyPairs let keypairs_path = if let Some(ref keypairs_file_path) = keypairs_file_path { keypairs_file_path.clone() @@ -614,26 +629,24 @@ pub fn load_conf_at_path( let mut conf_path = profile_path; conf_path.push(constants::CONF_FILENAME); let conf = if conf_path.as_path().exists() { - if let Ok(mut f) = File::open(conf_path.as_path()) { - let mut contents = String::new(); - if f.read_to_string(&mut contents).is_ok() { + match File::open(conf_path.as_path()) { + Ok(mut f) => { + let mut contents = String::new(); + f.read_to_string(&mut contents) + .map_err(DursConfFileError::ReadError)?; // Parse conf file let conf: DuRsConf = - serde_json::from_str(&contents).expect("Conf: Fail to parse conf file !"); + serde_json::from_str(&contents).map_err(DursConfFileError::ParseError)?; // Upgrade conf to latest version let (conf, upgraded) = conf.upgrade(); // If conf is upgraded, rewrite conf file if upgraded { - write_conf_file(conf_path.as_path(), &conf).unwrap_or_else(|_| { - panic!(dbg!("Fatal error : fail to write conf file !")) - }); + write_conf_file(conf_path.as_path(), &conf) + .map_err(DursConfFileError::WriteError)?; } conf - } else { - panic!("Fail to read conf file !"); } - } else { - panic!("Fail to open conf file !"); + Err(e) => return Err(DursConfFileError::ReadError(e)), } } else { // Create conf file with default conf @@ -644,7 +657,7 @@ pub fn load_conf_at_path( }; // Return conf and keypairs - (conf, keypairs) + Ok((conf, keypairs)) } /// Save keypairs in profile folder @@ -663,6 +676,19 @@ pub fn write_keypairs_file( Ok(()) } +/// Write new module conf +pub fn write_new_module_conf<DC: DursConfTrait>( + conf: &mut DC, + profile_path: PathBuf, + module_name: ModuleName, + new_module_conf: serde_json::Value, +) { + conf.set_module_conf(module_name, new_module_conf); + let mut conf_path = profile_path; + conf_path.push(crate::constants::CONF_FILENAME); + write_conf_file(conf_path.as_path(), conf).expect("Fail to write new conf file ! "); +} + /// Save configuration in profile folder pub fn write_conf_file<DC: DursConfTrait>( conf_path: &Path, @@ -742,10 +768,11 @@ mod tests { } #[test] - fn load_conf_file_v1() -> std::io::Result<()> { + fn load_conf_file_v1() -> Result<(), DursConfFileError> { let profile_path = PathBuf::from("./test/v1/"); - save_old_conf(PathBuf::from(profile_path.clone()))?; - let (conf, _keys) = load_conf_at_path(profile_path.clone(), &None); + save_old_conf(PathBuf::from(profile_path.clone())) + .map_err(DursConfFileError::WriteError)?; + let (conf, _keys) = load_conf_at_path(profile_path.clone(), &None)?; assert_eq!( conf.modules() .get("ws2p") @@ -768,15 +795,16 @@ mod tests { ] }) ); - restore_old_conf_and_save_upgraded_conf(profile_path)?; + restore_old_conf_and_save_upgraded_conf(profile_path) + .map_err(DursConfFileError::WriteError)?; Ok(()) } #[test] - fn load_conf_file_v2() { + fn load_conf_file_v2() -> Result<(), DursConfFileError> { let profile_path = PathBuf::from("./test/v2/"); - let (conf, _keys) = load_conf_at_path(profile_path, &None); + let (conf, _keys) = load_conf_at_path(profile_path, &None)?; assert_eq!( conf.modules() .get("ws2p") @@ -799,5 +827,6 @@ mod tests { ] }) ); + Ok(()) } } diff --git a/lib/core/core/Cargo.toml b/lib/core/core/Cargo.toml index 708e843b3918347f0a61220427227a2346d1ec74..a158b7590306e4e420f47c093ce95c59aa3ed85b 100644 --- a/lib/core/core/Cargo.toml +++ b/lib/core/core/Cargo.toml @@ -27,5 +27,6 @@ serde_json = "1.0.*" simplelog = "0.5.*" structopt= "0.2.*" threadpool = "1.7.*" +unwrap = "1.2.1" [features] diff --git a/lib/core/core/src/errors.rs b/lib/core/core/src/errors.rs index a7f541452aea638c304e31e6e5c790c34c5d1fa7..0aac0cdf1a2bf9789d21a76db3dfdecb6909d322 100644 --- a/lib/core/core/src/errors.rs +++ b/lib/core/core/src/errors.rs @@ -22,6 +22,9 @@ use failure::Fail; #[derive(Debug, Fail)] /// Durs server error pub enum DursCoreError { + /// Error with configuration file + #[fail(display = "Error with configuration file: {}", _0)] + ConfFileError(durs_conf::DursConfFileError), /// Fail to remove configuration file #[fail(display = "Fail to remove configuration file: {}", _0)] FailRemoveConfFile(std::io::Error), diff --git a/lib/core/core/src/lib.rs b/lib/core/core/src/lib.rs index ec5a683ba6a6fc5c9e09f5f03558ed1176076170..113b4e44ca646405cf2cb37945fc9d179474585e 100644 --- a/lib/core/core/src/lib.rs +++ b/lib/core/core/src/lib.rs @@ -55,6 +55,7 @@ use std::collections::HashMap; use std::path::PathBuf; use std::sync::mpsc; use std::thread; +use unwrap::unwrap; #[macro_export] /// Plug modules in durs core @@ -111,8 +112,7 @@ impl DursCore<DuRsConf> { soft_name: &'static str, soft_version: &'static str, ) -> Result<(), DursCoreError> { - let durs_core = DursCore::<DuRsConf>::init(soft_name, soft_version, durs_core_opts, 0)?; - + let mut durs_core = DursCore::<DuRsConf>::init(soft_name, soft_version, durs_core_opts, 0)?; // Load module conf and keys let module_conf_json = durs_core .soft_meta_datas @@ -122,7 +122,7 @@ impl DursCore<DuRsConf> { .get(&M::name().to_string().as_str()) .cloned(); - let (module_conf, required_keys) = get_module_conf_and_keys::<M>( + let ((module_conf, module_user_conf), required_keys) = get_module_conf_and_keys::<M>( &durs_core.soft_meta_datas.conf.get_global_conf(), module_conf_json, durs_core.keypairs, @@ -131,15 +131,22 @@ impl DursCore<DuRsConf> { module_name: M::name(), error: e.into(), })?; - // Execute module subcommand - M::exec_subcommand( + let new_module_conf = M::exec_subcommand( &durs_core.soft_meta_datas, required_keys, module_conf, + module_user_conf, module_command, ); + durs_conf::write_new_module_conf( + &mut durs_core.soft_meta_datas.conf, + durs_core.soft_meta_datas.profile_path.clone(), + M::name().into(), + unwrap!(serde_json::value::to_value(new_module_conf)), + ); + Ok(()) } @@ -227,7 +234,8 @@ impl DursCore<DuRsConf> { // Load global conf let (conf, keypairs) = - durs_conf::load_conf(profile_path.clone(), &durs_core_opts.keypairs_file); + durs_conf::load_conf(profile_path.clone(), &durs_core_opts.keypairs_file) + .map_err(DursCoreError::ConfFileError)?; info!("Success to load global conf."); // Instanciate durs core @@ -355,7 +363,7 @@ impl DursCore<DuRsConf> { let keypairs = self.keypairs; // Load module conf and keys - let (module_conf, required_keys) = get_module_conf_and_keys::<NM>( + let ((module_conf, _), required_keys) = get_module_conf_and_keys::<NM>( &soft_meta_datas.conf.get_global_conf(), module_conf_json, keypairs, @@ -429,7 +437,7 @@ impl DursCore<DuRsConf> { .cloned(); let keypairs = self.keypairs; // Load module conf and keys - let (module_conf, required_keys) = get_module_conf_and_keys::<M>( + let ((module_conf, _), required_keys) = get_module_conf_and_keys::<M>( &soft_meta_datas.conf.get_global_conf(), module_conf_json, keypairs, @@ -477,12 +485,21 @@ impl DursCore<DuRsConf> { } } +/// Module configurations and required keys +pub type ModuleConfsAndKeys<M> = ( + ( + <M as DursModule<DuRsConf, DursMsg>>::ModuleConf, + Option<<M as DursModule<DuRsConf, DursMsg>>::ModuleUserConf>, + ), + RequiredKeysContent, +); + /// Get module conf and keys pub fn get_module_conf_and_keys<M: DursModule<DuRsConf, DursMsg>>( global_conf: &<DuRsConf as DursConfTrait>::GlobalConf, module_conf_json: Option<serde_json::Value>, keypairs: DuniterKeyPairs, -) -> Result<(M::ModuleConf, RequiredKeysContent), ModuleConfError> { +) -> Result<ModuleConfsAndKeys<M>, ModuleConfError> { Ok(( get_module_conf::<M>(global_conf, module_conf_json)?, DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), keypairs), @@ -493,11 +510,11 @@ pub fn get_module_conf_and_keys<M: DursModule<DuRsConf, DursMsg>>( pub fn get_module_conf<M: DursModule<DuRsConf, DursMsg>>( global_conf: &<DuRsConf as DursConfTrait>::GlobalConf, module_conf_json: Option<serde_json::Value>, -) -> Result<M::ModuleConf, ModuleConfError> { +) -> Result<(M::ModuleConf, Option<M::ModuleUserConf>), ModuleConfError> { if let Some(module_conf_json) = module_conf_json { - let module_user_conf: M::ModuleUserConf = + let module_user_conf: Option<M::ModuleUserConf> = serde_json::from_str(module_conf_json.to_string().as_str())?; - M::generate_module_conf(global_conf, Some(module_user_conf)) + M::generate_module_conf(global_conf, module_user_conf) } else { M::generate_module_conf(global_conf, None) } diff --git a/lib/core/module/src/lib.rs b/lib/core/module/src/lib.rs index 8db64900bb52b48294cf3fabcddf19397e4762e6..eaa7e56de816994a51882cb3fed3260a19c5d834 100644 --- a/lib/core/module/src/lib.rs +++ b/lib/core/module/src/lib.rs @@ -343,15 +343,23 @@ pub fn module_valid_filters< #[derive(Debug, Fail)] /// Error when generating the configuration of a module pub enum ModuleConfError { - /// Parse error - #[fail(display = "{}", _0)] - ParseError(serde_json::Error), /// Combination forbidden #[fail(display = "Forbidden configuration: {}", cause)] CombinationForbidden { /// Cause cause: String, }, + /// Invalid field + #[fail(display = "Field '{}' is invalid: {}", field_name, cause)] + InvalidField { + /// Field name + field_name: &'static str, + /// Cause + cause: String, + }, + /// Parse error + #[fail(display = "{}", _0)] + ParseError(serde_json::Error), } impl From<serde_json::Error> for ModuleConfError { @@ -388,7 +396,7 @@ impl From<ModuleConfError> for PlugModuleError { /// All Duniter-rs modules must implement this trait. pub trait DursModule<DC: DursConfTrait, M: ModuleMessage> { ///Module user configuration (configuration provided by the user) - type ModuleUserConf: Clone + Debug + DeserializeOwned + Send + Serialize + Sync; + type ModuleUserConf: Clone + Debug + Default + DeserializeOwned + Send + Serialize + Sync; /// Module real configuration (configuration calculated from the configuration provided by the user and the global configuration) type ModuleConf: 'static + Clone + Debug + Default + Send + Sync; /// Module subcommand options @@ -404,7 +412,7 @@ pub trait DursModule<DC: DursConfTrait, M: ModuleMessage> { fn generate_module_conf( global_conf: &DC::GlobalConf, module_user_conf: Option<Self::ModuleUserConf>, - ) -> Result<Self::ModuleConf, ModuleConfError>; + ) -> Result<(Self::ModuleConf, Option<Self::ModuleUserConf>), ModuleConfError>; /// Define if module have a cli subcommand fn have_subcommand() -> bool { false @@ -414,8 +422,10 @@ pub trait DursModule<DC: DursConfTrait, M: ModuleMessage> { _soft_meta_datas: &SoftwareMetaDatas<DC>, _keys: RequiredKeysContent, _module_conf: Self::ModuleConf, + _module_user_conf: Option<Self::ModuleUserConf>, _subcommand_args: Self::ModuleOpt, - ) { + ) -> Option<Self::ModuleUserConf> { + None } /// Launch the module fn start( diff --git a/lib/modules/skeleton/lib.rs b/lib/modules/skeleton/lib.rs index f983f75177f15f3e37261ed6b2d11facc8b91a00..3405246db33909828c764b206c192889071fd5d5 100644 --- a/lib/modules/skeleton/lib.rs +++ b/lib/modules/skeleton/lib.rs @@ -62,7 +62,7 @@ impl Default for SkeletonConf { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// Skeleton Module Configuration pub struct SkeletonUserConf { test_fake_conf_field: Option<String>, @@ -132,40 +132,32 @@ impl DursModule<DuRsConf, DursMsg> for SkeletonModule { fn generate_module_conf( _global_conf: &<DuRsConf as DursConfTrait>::GlobalConf, module_user_conf: Option<Self::ModuleUserConf>, - ) -> Result<Self::ModuleConf, ModuleConfError> { + ) -> Result<(Self::ModuleConf, Option<Self::ModuleUserConf>), ModuleConfError> { let mut conf = SkeletonConf::default(); - if let Some(module_user_conf) = module_user_conf { - if let Some(test_fake_conf_field) = module_user_conf.test_fake_conf_field { - conf.test_fake_conf_field = test_fake_conf_field; + if let Some(ref module_user_conf) = module_user_conf { + if let Some(ref test_fake_conf_field) = module_user_conf.test_fake_conf_field { + conf.test_fake_conf_field = test_fake_conf_field.to_owned(); } } - Ok(conf) + Ok((conf, module_user_conf)) } fn exec_subcommand( - soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, + _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, _keys: RequiredKeysContent, module_conf: Self::ModuleConf, + _module_user_conf: Option<Self::ModuleUserConf>, subcommand_args: Self::ModuleOpt, - ) { - let mut conf = soft_meta_datas.conf.clone(); - let new_skeleton_conf = SkeletonConf { - test_fake_conf_field: subcommand_args.new_conf_field.clone(), + ) -> Option<Self::ModuleUserConf> { + let new_skeleton_conf = SkeletonUserConf { + test_fake_conf_field: Some(subcommand_args.new_conf_field.to_owned()), }; - conf.set_module_conf( - ModuleName(MODULE_NAME.to_owned()), - serde_json::value::to_value(new_skeleton_conf) - .expect("Fail to jsonifie SkeletonConf !"), - ); - let mut conf_path = soft_meta_datas.profile_path.clone(); - conf_path.push(durs_conf::constants::CONF_FILENAME); - durs_conf::write_conf_file(conf_path.as_path(), &conf) - .expect("Fail to write new conf file ! "); println!( "Succesfully exec skeleton subcommand whit terminal name : {} and conf={:?}!", subcommand_args.new_conf_field, module_conf - ) + ); + Some(new_skeleton_conf) } fn start( _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, diff --git a/lib/modules/tui/lib.rs b/lib/modules/tui/lib.rs index b065e35db36813187192937b52759937e69e6eb7..e0aa018b723a004376d821e0c7e2b2ed3c8778e6 100644 --- a/lib/modules/tui/lib.rs +++ b/lib/modules/tui/lib.rs @@ -390,8 +390,8 @@ impl DursModule<DuRsConf, DursMsg> for TuiModule { fn generate_module_conf( _global_conf: &<DuRsConf as DursConfTrait>::GlobalConf, _module_user_conf: Option<Self::ModuleUserConf>, - ) -> Result<Self::ModuleConf, ModuleConfError> { - Ok(TuiConf {}) + ) -> Result<(Self::ModuleConf, Option<Self::ModuleUserConf>), ModuleConfError> { + Ok((TuiConf {}, None)) } fn start( _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, diff --git a/lib/modules/ws2p-v1-legacy/src/lib.rs b/lib/modules/ws2p-v1-legacy/src/lib.rs index 292d44f2f5fa6622632e30bd704430c987b4a5f5..f70e5df0bb577b067b0e3e0588cf286af45d124b 100644 --- a/lib/modules/ws2p-v1-legacy/src/lib.rs +++ b/lib/modules/ws2p-v1-legacy/src/lib.rs @@ -43,6 +43,7 @@ pub mod parsers; mod requests; mod responses; pub mod serializer; +mod subcommands; pub mod ws2p_db; pub mod ws_connections; @@ -52,6 +53,7 @@ use crate::constants::*; use crate::ok_message::WS2POkMessageV1; use crate::parsers::blocks::parse_json_block; use crate::requests::sent::send_dal_request; +use crate::subcommands::WS2PSubCommands; use crate::ws2p_db::DbEndpoint; use crate::ws_connections::messages::WS2PConnectionMessage; use crate::ws_connections::states::WS2PConnectionState; @@ -74,10 +76,11 @@ 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::collections::{HashMap, HashSet}; use std::fs; use std::ops::Deref; use std::path::PathBuf; +use std::str::FromStr; use std::sync::mpsc; use std::thread; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -95,28 +98,33 @@ pub fn ssl() -> bool { true } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] /// WS2P Configuration -pub struct WS2PConf { +pub struct WS2PUserConf { /// Limit of outcoming connections - pub outcoming_quota: usize, + pub outcoming_quota: Option<usize>, + /// List of prefered public keys + pub prefered_pubkeys: Option<HashSet<String>>, /// Default WS2P endpoints provides by configuration file - pub sync_endpoints: Vec<EndpointV1>, + pub sync_endpoints: Option<Vec<EndpointV1>>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq)] /// WS2P Configuration -pub struct WS2PUserConf { +pub struct WS2PConf { /// Limit of outcoming connections - pub outcoming_quota: Option<usize>, + pub outcoming_quota: usize, + /// List of prefered public keys + pub prefered_pubkeys: HashSet<PubKey>, /// Default WS2P endpoints provides by configuration file - pub sync_endpoints: Option<Vec<EndpointV1>>, + pub sync_endpoints: Vec<EndpointV1>, } impl Default for WS2PConf { fn default() -> Self { WS2PConf { outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA, + prefered_pubkeys: HashSet::new(), sync_endpoints: vec![ unwrap!(EndpointV1::parse_from_raw( "WS2P c1c39a0a ts.g1.librelois.fr 443 /ws2p", @@ -318,13 +326,25 @@ impl NetworkModule<DuRsConf, DursMsg> for WS2PModule { } } -#[derive(StructOpt, Debug, Copy, Clone)] +#[derive(Clone, Debug, StructOpt)] #[structopt( name = "ws2p", raw(setting = "structopt::clap::AppSettings::ColoredHelp") )] -/// WS2Pv1 subcommand options -pub struct WS2POpt {} +/// WS2P1 subcommand options +pub struct WS2POpt { + /// Ws2p1 subcommands + #[structopt(subcommand)] + pub subcommand: WS2PSubCommands, +} + +macro_rules! fields_overload { + ($struct:ident; $option_struct:ident; [$($field:ident),+]) => {{ + $(if let Some($field) = $option_struct.$field { + $struct.$field = $field; + })+ + }}; +} impl DursModule<DuRsConf, DursMsg> for WS2PModule { type ModuleUserConf = WS2PUserConf; @@ -343,10 +363,11 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule { fn have_subcommand() -> bool { true } + fn generate_module_conf( global_conf: &<DuRsConf as DursConfTrait>::GlobalConf, module_user_conf: Option<Self::ModuleUserConf>, - ) -> Result<Self::ModuleConf, ModuleConfError> { + ) -> Result<(Self::ModuleConf, Option<Self::ModuleUserConf>), ModuleConfError> { let mut conf = WS2PConf::default(); if global_conf.currency() == CurrencyName("g1-test".to_owned()) { @@ -360,24 +381,49 @@ impl DursModule<DuRsConf, DursMsg> for WS2PModule { ))]; } - if let Some(module_user_conf) = module_user_conf { - if let Some(outcoming_quota) = module_user_conf.outcoming_quota { + if let Some(module_user_conf) = module_user_conf.clone() { + /*if let Some(outcoming_quota) = module_user_conf.outcoming_quota { conf.outcoming_quota = outcoming_quota; } if let Some(sync_endpoints) = module_user_conf.sync_endpoints { conf.sync_endpoints = sync_endpoints; + }*/ + if let Some(prefered_pubkeys) = module_user_conf.prefered_pubkeys { + conf.prefered_pubkeys = prefered_pubkeys + .iter() + .enumerate() + .map(|(i, p)| { + PubKey::from_str(p).map_err(|e| ModuleConfError::InvalidField { + field_name: stringify!(prefered_pubkeys), + cause: format!("pubkey n°{} is invalid: {}", i, e), + }) + }) + .collect::<Result<HashSet<PubKey>, ModuleConfError>>()?; } + fields_overload!( + conf; + module_user_conf; + [ + outcoming_quota, + sync_endpoints + ] + ) } - Ok(conf) + Ok((conf, module_user_conf)) } fn exec_subcommand( _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, _keys: RequiredKeysContent, _module_conf: Self::ModuleConf, - _subcommand_args: WS2POpt, - ) { - println!("Succesfully exec ws2p subcommand !") + module_user_conf: Option<Self::ModuleUserConf>, + opts: WS2POpt, + ) -> Option<Self::ModuleUserConf> { + match opts.subcommand { + WS2PSubCommands::Prefered { + subcommand: prefered_subcommand, + } => prefered_subcommand.execute(module_user_conf), + } } fn start( soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, diff --git a/lib/modules/ws2p-v1-legacy/src/subcommands/mod.rs b/lib/modules/ws2p-v1-legacy/src/subcommands/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..cab62bf96eeec9ec4310244e08433c73d2f6bfd8 --- /dev/null +++ b/lib/modules/ws2p-v1-legacy/src/subcommands/mod.rs @@ -0,0 +1,34 @@ +// 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/>. + +//! WS2P1 module subcommands + +pub mod prefered; + +use prefered::Ws2pPreferedSubCommands; + +#[derive(Clone, Debug, StructOpt)] +/// Ws2p1 subcommands +pub enum WS2PSubCommands { + /// Prefered keys + #[structopt( + name = "prefered", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") + )] + Prefered { + #[structopt(subcommand)] + subcommand: Ws2pPreferedSubCommands, + }, +} diff --git a/lib/modules/ws2p-v1-legacy/src/subcommands/prefered.rs b/lib/modules/ws2p-v1-legacy/src/subcommands/prefered.rs new file mode 100644 index 0000000000000000000000000000000000000000..a442661cae09acede1d61c523c97c394f15f29ec --- /dev/null +++ b/lib/modules/ws2p-v1-legacy/src/subcommands/prefered.rs @@ -0,0 +1,174 @@ +// 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/>. + +//! WS2P1 module subcommand prefered + +use dup_crypto::keys::PubKey; +use std::collections::HashSet; +use std::fs; +use std::io::BufRead; +use std::path::PathBuf; +use std::str::FromStr; + +#[derive(Clone, Debug, StructOpt)] +/// Ws2p1 prefered subcommands +pub enum Ws2pPreferedSubCommands { + /// Add prefered pubkey + #[structopt( + name = "add", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") + )] + Add { + /// Public key to add + public_keys: Vec<PubKey>, + }, + /// Add prefered pubkeys from file (one pubkey per line) + #[structopt( + name = "add-file", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") + )] + AddFromFile { + /// File path + #[structopt(parse(from_os_str))] + file_path: PathBuf, + }, + /// Clear prefered pubkeys + #[structopt( + name = "clear", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") + )] + Clear, + /// Remove prefered pubkey + #[structopt( + name = "rem", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") + )] + Rem { + /// Public key to remove + public_keys: Vec<PubKey>, + }, + /// Show prefered pubkeys + #[structopt( + name = "show", + raw(setting = "structopt::clap::AppSettings::ColoredHelp") + )] + Show, +} + +impl Ws2pPreferedSubCommands { + pub fn execute( + self, + module_user_conf: Option<crate::WS2PUserConf>, + ) -> Option<crate::WS2PUserConf> { + { + let mut prefered_pubkeys = if let Some(ref module_user_conf) = module_user_conf { + module_user_conf + .prefered_pubkeys + .clone() + .unwrap_or_else(HashSet::new) + } else { + HashSet::new() + }; + + match self { + Ws2pPreferedSubCommands::Add { public_keys } => { + for pubkey in public_keys { + prefered_pubkeys.insert(pubkey.to_string()); + println!( + "Pubkey '{}' successfully added to the list of preferred keys.", + pubkey + ); + } + let mut new_user_conf = module_user_conf.unwrap_or_default(); + new_user_conf.prefered_pubkeys = Some(prefered_pubkeys); + Some(new_user_conf) + } + Ws2pPreferedSubCommands::AddFromFile { file_path } => { + if file_path.as_path().exists() { + match fs::File::open(file_path.as_path()) { + Ok(file) => { + let mut new_prefered_pubkeys = HashSet::new(); + for (i, line) in std::io::BufReader::new(file).lines().enumerate() { + match line { + Ok(line) => match PubKey::from_str(&line) { + Ok(pubkey) => { + new_prefered_pubkeys.insert(pubkey.to_string()); + println!( + "Pubkey '{}' successfully added to the list of preferred keys.", + pubkey + ); + } + Err(e) => { + println!("Line n°{} is invalid: {}", i + 1, e); + } + }, + Err(e) => { + println!("Fail to read line n°{}: {}", i + 1, e); + return module_user_conf; + } + } + } + let mut new_user_conf = module_user_conf.unwrap_or_default(); + if let Some(ref mut prefered_pubkeys) = + new_user_conf.prefered_pubkeys + { + prefered_pubkeys.extend(new_prefered_pubkeys.into_iter()); + } else { + new_user_conf.prefered_pubkeys = Some(new_prefered_pubkeys); + } + Some(new_user_conf) + } + Err(e) => { + println!("Fail to open file: {}", e); + module_user_conf + } + } + } else { + println!("Error: file note exist !"); + module_user_conf + } + } + Ws2pPreferedSubCommands::Clear => { + if let Some(mut module_user_conf) = module_user_conf { + module_user_conf.prefered_pubkeys = None; + println!("All preferred keys removed !"); + Some(module_user_conf) + } else { + module_user_conf + } + } + Ws2pPreferedSubCommands::Rem { public_keys } => { + for pubkey in public_keys { + prefered_pubkeys.remove(&pubkey.to_string()); + println!( + "Pubkey '{}' successfully removed from the list of preferred keys", + pubkey + ); + } + let mut new_user_conf = module_user_conf.unwrap_or_default(); + new_user_conf.prefered_pubkeys = Some(prefered_pubkeys); + Some(new_user_conf) + } + Ws2pPreferedSubCommands::Show => { + println!("{} preferred keys: ", prefered_pubkeys.len()); + for pubkey in &prefered_pubkeys { + println!("{}", pubkey); + } + module_user_conf + } + } + } + } +} diff --git a/lib/modules/ws2p/ws2p/src/lib.rs b/lib/modules/ws2p/ws2p/src/lib.rs index 04f96f2a91e1218d1d1ed619ddab2b6ad1b84205..653fd29a8246fa68a750aa32e5120ed622b627ec 100644 --- a/lib/modules/ws2p/ws2p/src/lib.rs +++ b/lib/modules/ws2p/ws2p/src/lib.rs @@ -56,7 +56,7 @@ pub struct WS2PConf { pub sync_endpoints: Vec<EndpointEnum>, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] /// WS2P Configuration pub struct WS2PUserConf { /// Limit of outcoming connections @@ -160,10 +160,10 @@ impl DursModule<DuRsConf, DursMsg> for WS2Pv2Module { fn generate_module_conf( _global_conf: &<DuRsConf as DursConfTrait>::GlobalConf, module_user_conf: Option<Self::ModuleUserConf>, - ) -> Result<Self::ModuleConf, ModuleConfError> { + ) -> Result<(Self::ModuleConf, Option<Self::ModuleUserConf>), ModuleConfError> { let mut conf = WS2PConf::default(); - if let Some(module_user_conf) = module_user_conf { + if let Some(module_user_conf) = module_user_conf.clone() { if let Some(outcoming_quota) = module_user_conf.outcoming_quota { conf.outcoming_quota = outcoming_quota; } @@ -172,15 +172,17 @@ impl DursModule<DuRsConf, DursMsg> for WS2Pv2Module { } } - Ok(conf) + Ok((conf, module_user_conf)) } fn exec_subcommand( _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, _keys: RequiredKeysContent, _module_conf: Self::ModuleConf, + _module_user_conf: Option<Self::ModuleUserConf>, _subcommand_args: WS2POpt, - ) { - println!("Succesfully exec ws2p subcommand !") + ) -> Option<Self::ModuleUserConf> { + println!("Succesfully exec ws2p subcommand !"); + None } fn start( _soft_meta_datas: &SoftwareMetaDatas<DuRsConf>, diff --git a/lib/tools/crypto/src/keys/mod.rs b/lib/tools/crypto/src/keys/mod.rs index d464e60336e9c59b2add365eea21d39f90204588..9a660fec16dbedb48bcf5278c1263455bfadcfb5 100644 --- a/lib/tools/crypto/src/keys/mod.rs +++ b/lib/tools/crypto/src/keys/mod.rs @@ -55,6 +55,7 @@ use std::fmt::Display; use std::fmt::Error; use std::fmt::Formatter; use std::hash::Hash; +use std::str::FromStr; pub mod bin_signable; pub mod ed25519; @@ -270,6 +271,14 @@ impl Display for PubKey { } } +impl FromStr for PubKey { + type Err = BaseConvertionError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + ed25519::PublicKey::from_base58(s).map(PubKey::Ed25519) + } +} + impl PublicKey for PubKey { type Signature = Sig;