From 8e2ab6baca3b277de9b363b1d173399b5ded4bcb Mon Sep 17 00:00:00 2001
From: librelois <elois@ifee.fr>
Date: Sat, 4 May 2019 19:07:43 +0200
Subject: [PATCH] [feat]whole+ws2p1:improve module conf handling + ws2p1 add
prefered keys
---
Cargo.lock | 2 +
doc/en/dev/developing-a-durs-module.md | 3 +-
.../developpeurs/developper-un-module-durs.md | 3 +-
lib/core/conf/Cargo.toml | 1 +
lib/core/conf/src/lib.rs | 73 +++++---
lib/core/core/Cargo.toml | 1 +
lib/core/core/src/errors.rs | 3 +
lib/core/core/src/lib.rs | 41 +++--
lib/core/module/src/lib.rs | 22 ++-
lib/modules/skeleton/lib.rs | 34 ++--
lib/modules/tui/lib.rs | 4 +-
lib/modules/ws2p-v1-legacy/src/lib.rs | 84 +++++++--
.../ws2p-v1-legacy/src/subcommands/mod.rs | 34 ++++
.../src/subcommands/prefered.rs | 174 ++++++++++++++++++
lib/modules/ws2p/ws2p/src/lib.rs | 14 +-
lib/tools/crypto/src/keys/mod.rs | 9 +
16 files changed, 412 insertions(+), 90 deletions(-)
create mode 100644 lib/modules/ws2p-v1-legacy/src/subcommands/mod.rs
create mode 100644 lib/modules/ws2p-v1-legacy/src/subcommands/prefered.rs
diff --git a/Cargo.lock b/Cargo.lock
index eb3b85a8..36fad37c 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 c1dc07dd..4454ef41 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 9d2d50ca..22923903 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 49eb8363..9094937b 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 c6066836..85910f6e 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 708e843b..a158b759 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 a7f54145..0aac0cdf 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 ec5a683b..113b4e44 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 8db64900..eaa7e56d 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 f983f751..3405246d 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 b065e35d..e0aa018b 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 292d44f2..f70e5df0 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 00000000..cab62bf9
--- /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 00000000..a442661c
--- /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 04f96f2a..653fd29a 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 d464e603..9a660fec 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;
--
GitLab