Skip to content
Snippets Groups Projects
Commit 2d49cb6e authored by Éloïs's avatar Éloïs
Browse files

Merge branch 'feat_disable_modules' into 'dev'

[feat] disable some modules

See merge request !74
parents c4dcc427 b690540c
Branches
Tags
1 merge request!74[feat] disable some modules
......@@ -36,6 +36,7 @@ use duniter_crypto::keys::*;
use duniter_module::{Currency, DuniterConf, ModuleId, RequiredKeys, RequiredKeysContent};
use rand::Rng;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use std::collections::HashSet;
use std::env;
use std::fs;
use std::fs::File;
......@@ -47,6 +48,19 @@ static USER_DATAS_FOLDER: &'static str = "durs-dev";
/// If no currency is specified by the user, is the currency will be chosen by default
pub static DEFAULT_CURRRENCY: &'static str = "g1";
#[derive(Debug, Clone)]
/// User request on global conf
pub enum ChangeGlobalConf {
/// Change currency
ChangeCurrency(Currency),
/// Disable module
DisableModule(ModuleId),
/// Enable module
EnableModule(ModuleId),
/// None
None(),
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
/// Duniter configuration v1
pub struct DuRsConfV1 {
......@@ -57,9 +71,9 @@ pub struct DuRsConfV1 {
/// Configuration of modules in json format (obtained from the conf.json file)
pub modules: serde_json::Value,
/// Disabled modules
pub disabled: Vec<ModuleId>,
pub disabled: HashSet<ModuleId>,
/// Enabled modules
pub enabled: Vec<ModuleId>,
pub enabled: HashSet<ModuleId>,
}
impl Default for DuRsConfV1 {
......@@ -68,8 +82,8 @@ impl Default for DuRsConfV1 {
currency: Currency::Str(String::from("g1")),
my_node_id: generate_random_node_id(),
modules: serde_json::Value::Null,
disabled: Vec::with_capacity(0),
enabled: Vec::with_capacity(0),
disabled: HashSet::with_capacity(0),
enabled: HashSet::with_capacity(0),
}
}
}
......@@ -114,13 +128,31 @@ impl DuniterConf for DuRsConf {
_ => panic!("Fail to load duniter conf : conf version not supported !"),
}
}
fn disabled_modules(&self) -> Vec<ModuleId> {
fn disable(&mut self, module: ModuleId) {
match *self {
DuRsConf::V1(ref mut conf_v1) => {
conf_v1.disabled.insert(module.clone());
conf_v1.enabled.remove(&module);
}
_ => panic!("Fail to load duniter conf : conf version not supported !"),
}
}
fn enable(&mut self, module: ModuleId) {
match *self {
DuRsConf::V1(ref mut conf_v1) => {
conf_v1.disabled.remove(&module);
conf_v1.enabled.insert(module);
}
_ => panic!("Fail to load duniter conf : conf version not supported !"),
}
}
fn disabled_modules(&self) -> HashSet<ModuleId> {
match *self {
DuRsConf::V1(ref conf_v1) => conf_v1.disabled.clone(),
_ => panic!("Fail to load duniter conf : conf version not supported !"),
}
}
fn enabled_modules(&self) -> Vec<ModuleId> {
fn enabled_modules(&self) -> HashSet<ModuleId> {
match *self {
DuRsConf::V1(ref conf_v1) => conf_v1.enabled.clone(),
_ => panic!("Fail to load duniter conf : conf version not supported !"),
......
// Copyright (C) 2018 The Duniter 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/>.
//! Crate containing Duniter-rust core.
use duniter_conf::ChangeGlobalConf;
use duniter_module::DuniterConf;
/// Change global configuration
pub fn change_global_conf<DC: DuniterConf>(
profile: &str,
mut conf: DC,
user_request: ChangeGlobalConf,
) {
match user_request {
ChangeGlobalConf::ChangeCurrency(_) => {}
ChangeGlobalConf::DisableModule(module_id) => conf.disable(module_id),
ChangeGlobalConf::EnableModule(module_id) => conf.enable(module_id),
ChangeGlobalConf::None() => {}
}
// Write new conf
super::duniter_conf::write_conf_file(profile, &conf).expect("IOError : Fail to update conf ");
println!("Configuration successfully updated.");
}
......@@ -23,6 +23,45 @@ args:
debug : print a lot of debug informations\n
trace : print all traces (highly verbose)"
subcommands:
- enable:
about: Enable some module
version: "0.1.0"
author: Elois L. <elois@duniter.org>
args:
- MODULE_NAME:
help: The module name to enable
index: 1
required: true
- disable:
about: Disable some module
version: "0.1.0"
author: Elois L. <elois@duniter.org>
args:
- MODULE_NAME:
help: The module name to disable
index: 1
required: true
- modules:
about: list module
version: "0.1.0"
author: Elois L. <elois@duniter.org>
args:
- disabled:
short: d
long: disabled
help: list only disabled modules
- enabled:
short: e
long: enabled
help: list only enabled modules
- network:
short: n
long: network
help: list only network modules
- secret:
short: s
long: secret
help: list only modules having access to the secret member key
- start:
about: start duniter server
version: "0.1.0"
......
......@@ -16,6 +16,7 @@
//! Crate containing Duniter-rust core.
#![cfg_attr(feature = "strict", deny(warnings))]
#![cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
#![deny(
missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
......@@ -40,14 +41,17 @@ extern crate simplelog;
extern crate sqlite;
extern crate threadpool;
pub mod change_conf;
use clap::{App, ArgMatches};
use duniter_blockchain::{BlockchainModule, DBExQuery, DBExTxQuery, DBExWotQuery};
pub use duniter_conf::{DuRsConf, DuniterKeyPairs};
pub use duniter_conf::{ChangeGlobalConf, DuRsConf, DuniterKeyPairs};
use duniter_message::DuniterMessage;
use duniter_module::*;
use duniter_network::{NetworkModule, SyncEndpoint};
use log::Level;
use simplelog::*;
use std::collections::HashSet;
use std::env;
use std::fs;
use std::fs::{File, OpenOptions};
......@@ -63,6 +67,8 @@ pub enum UserCommand {
Start(),
/// Sync (SyncEndpoint)
Sync(SyncEndpoint),
/// List modules
ListModules(HashSet<ModulesFilter>),
/// Other command
Other(),
}
......@@ -137,7 +143,46 @@ impl DuniterCore<DuRsConf> {
conf: conf.clone(),
};
if let Some(_matches) = cli_args.subcommand_matches("start") {
/*
* COMMAND LINE PROCESSING
*/
if let Some(matches) = cli_args.subcommand_matches("disable") {
let module_name = matches
.value_of("MODULE_NAME")
.expect("disable: you must enter a module name !")
.to_string();
change_conf::change_global_conf(
&profile,
conf,
ChangeGlobalConf::DisableModule(ModuleId(module_name)),
);
None
} else if let Some(matches) = cli_args.subcommand_matches("enable") {
let module_name = matches
.value_of("MODULE_NAME")
.expect("enable: you must enter a module name !")
.to_string();
change_conf::change_global_conf(
&profile,
conf,
ChangeGlobalConf::EnableModule(ModuleId(module_name)),
);
None
} else if let Some(matches) = cli_args.subcommand_matches("modules") {
let mut filters = HashSet::new();
if matches.is_present("disabled") {
filters.insert(ModulesFilter::Enabled(false));
} else if matches.is_present("enabled") {
filters.insert(ModulesFilter::Enabled(true));
}
if matches.is_present("network") {
filters.insert(ModulesFilter::Network());
}
if matches.is_present("secret") {
filters.insert(ModulesFilter::RequireMemberPrivKey());
}
Some(list_modules(soft_meta_datas, keypairs, filters))
} else if let Some(_matches) = cli_args.subcommand_matches("start") {
Some(start(
soft_meta_datas,
keypairs,
......@@ -312,6 +357,8 @@ impl DuniterCore<DuRsConf> {
}
/// Plug a network module
pub fn plug_network<NM: NetworkModule<DuRsConf, DuniterMessage>>(&mut self) {
let enabled = enabled::<DuRsConf, DuniterMessage, NM>(&self.soft_meta_datas.conf);
if enabled {
if let UserCommand::Start() = self.user_command {
self.network_modules_count += 1;
self.plug::<NM>();
......@@ -350,8 +397,24 @@ impl DuniterCore<DuRsConf> {
info!("Success to load {} module.", NM::id().to_string());
}
}
if let UserCommand::ListModules(ref filters) = self.user_command {
if module_valid_filters::<DuRsConf, DuniterMessage, NM>(
&self.soft_meta_datas.conf,
filters,
true,
) {
if enabled {
println!("{}", NM::id().to_string());
} else {
println!("{} (disabled)", NM::id().to_string());
}
}
}
}
/// Plug a module
pub fn plug<M: DuniterModule<DuRsConf, DuniterMessage>>(&mut self) {
let enabled = enabled::<DuRsConf, DuniterMessage, M>(&self.soft_meta_datas.conf);
if enabled {
if let UserCommand::Start() = self.user_command {
// Start module in a new thread
let rooter_sender_clone = self.rooter_sender.clone();
......@@ -385,6 +448,20 @@ impl DuniterCore<DuRsConf> {
info!("Success to load {} module.", M::id().to_string());
}
}
if let UserCommand::ListModules(ref filters) = self.user_command {
if module_valid_filters::<DuRsConf, DuniterMessage, M>(
&self.soft_meta_datas.conf,
filters,
false,
) {
if enabled {
println!("{}", M::id().to_string());
} else {
println!("{} (disabled)", M::id().to_string());
}
}
}
}
}
/// Load module conf and keys
......@@ -409,6 +486,28 @@ pub fn match_profile(cli_args: &ArgMatches) -> String {
String::from(cli_args.value_of("profile").unwrap_or("default"))
}
/// List modules
pub fn list_modules<DC: DuniterConf>(
soft_meta_datas: SoftwareMetaDatas<DC>,
keypairs: DuniterKeyPairs,
modules_filter: HashSet<ModulesFilter>,
) -> DuniterCore<DC> {
// Start rooter thread
let rooter_sender = start_rooter::<DC>(0, vec![]);
// Instanciate DuniterCore
DuniterCore {
user_command: UserCommand::ListModules(modules_filter),
soft_meta_datas,
keypairs,
run_duration_in_secs: 0,
rooter_sender,
modules_count: 0,
network_modules_count: 0,
thread_pool: ThreadPool::new(2),
}
}
/// Start rooter thread
pub fn start_rooter<DC: DuniterConf>(
run_duration_in_secs: u64,
......
......@@ -33,6 +33,7 @@ extern crate serde_json;
use duniter_crypto::keys::{KeyPair, KeyPairEnum};
use serde::de::DeserializeOwned;
use serde::ser::{Serialize, Serializer};
use std::collections::HashSet;
use std::fmt::Debug;
use std::sync::mpsc;
......@@ -98,10 +99,14 @@ pub trait DuniterConf: Clone + Debug + Default + PartialEq + Serialize + Deseria
fn set_currency(&mut self, new_currency: Currency);
/// Get node id
fn my_node_id(&self) -> u32;
/// Disable a module
fn disable(&mut self, module: ModuleId);
/// Enable a module
fn enable(&mut self, module: ModuleId);
/// Get disabled modules
fn disabled_modules(&self) -> Vec<ModuleId>;
fn disabled_modules(&self) -> HashSet<ModuleId>;
/// Get enabled modules
fn enabled_modules(&self) -> Vec<ModuleId>;
fn enabled_modules(&self) -> HashSet<ModuleId>;
/// Get modules conf
fn modules(&self) -> serde_json::Value;
}
......@@ -182,6 +187,54 @@ pub enum ModulePriority {
Optional(),
}
/// Determines if a module is activated or not
pub fn enabled<DC: DuniterConf, Mess: ModuleMessage, M: DuniterModule<DC, Mess>>(
conf: &DC,
) -> bool {
let disabled_modules = conf.disabled_modules();
let enabled_modules = conf.enabled_modules();
match M::priority() {
ModulePriority::Essential() => true,
ModulePriority::Recommended() => !disabled_modules.contains(&M::id()),
ModulePriority::Optional() => enabled_modules.contains(&M::id()),
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Modules filter
/// If bool = false, the meaning of the filter is reversed.
pub enum ModulesFilter {
/// Enabled modules
Enabled(bool),
/// Network modules
Network(),
/// Modules that require member private key
RequireMemberPrivKey(),
}
/// Returns true only if the module checks all filters
pub fn module_valid_filters<DC: DuniterConf, Mess: ModuleMessage, M: DuniterModule<DC, Mess>>(
conf: &DC,
filters: &HashSet<ModulesFilter>,
network_module: bool,
) -> bool {
if filters.contains(&ModulesFilter::Network()) && !network_module {
return false;
}
if filters.contains(&ModulesFilter::RequireMemberPrivKey())
&& M::ask_required_keys() != RequiredKeys::MemberKeyPair()
{
return false;
}
if filters.contains(&ModulesFilter::Enabled(true)) && !enabled::<DC, Mess, M>(conf) {
return false;
}
if filters.contains(&ModulesFilter::Enabled(false)) && enabled::<DC, Mess, M>(conf) {
return false;
}
true
}
/// All Duniter-rs modules must implement this trait.
pub trait DuniterModule<DC: DuniterConf, M: ModuleMessage> {
/// Module configuration
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment