use exonum_node::{ConfigManager, ConnectListConfig};
use log::error;
use std::{path::Path, sync::mpsc, thread};
use crate::{
config::NodeConfig,
io::{load_config_file, save_config_file},
};
#[derive(Debug)]
pub struct DefaultConfigManager {
tx: mpsc::Sender<UpdateRequest>,
}
#[derive(Debug)]
pub struct UpdateRequest(ConnectListConfig);
impl DefaultConfigManager {
pub fn new<P>(path: P) -> Self
where
P: AsRef<Path> + Send + 'static,
{
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
for UpdateRequest(connect_list) in rx {
let res = Self::update_connect_list(connect_list, &path);
if let Err(ref error) = res {
error!("Unable to update config: {}", error);
}
}
});
Self { tx }
}
#[doc(hidden)]
pub fn update_connect_list<P>(connect_list: ConnectListConfig, path: &P) -> anyhow::Result<()>
where
P: AsRef<Path>,
{
let mut current_config: NodeConfig = load_config_file(path)?;
current_config.private_config.connect_list = connect_list;
save_config_file(¤t_config, path)?;
Ok(())
}
}
impl ConfigManager for DefaultConfigManager {
fn store_connect_list(&mut self, connect_list: ConnectListConfig) {
self.tx
.send(UpdateRequest(connect_list))
.expect("Can't message to ConfigManager thread");
}
}
#[cfg(test)]
mod tests {
use exonum::{blockchain::ConsensusConfig, crypto::KeyPair, merkledb::DbOptions};
use exonum_node::{
ConnectInfo, ConnectListConfig, MemoryPoolConfig, NetworkConfiguration, NodeApiConfig,
};
use exonum_supervisor::mode::Mode;
use tempfile::tempdir;
use std::path::PathBuf;
use super::DefaultConfigManager;
use crate::config::{GeneralConfig, NodeConfig, NodePrivateConfig, NodePublicConfig};
use crate::io::{load_config_file, save_config_file};
#[test]
fn test_update_config() {
let config = NodeConfig {
private_config: NodePrivateConfig {
listen_address: "127.0.0.1:5400".parse().unwrap(),
external_address: "127.0.0.1:5400".to_string(),
master_key_path: PathBuf::default(),
api: NodeApiConfig::default(),
network: NetworkConfiguration::default(),
mempool: MemoryPoolConfig::default(),
database: DbOptions::default(),
thread_pool_size: None,
connect_list: ConnectListConfig::default(),
consensus_public_key: KeyPair::random().public_key(),
},
public_config: NodePublicConfig {
consensus: ConsensusConfig::default(),
general: GeneralConfig {
validators_count: 1,
supervisor_mode: Mode::Simple,
},
validator_keys: None,
address: None,
},
};
let tmp_dir = tempdir().unwrap();
let config_path = tmp_dir.path().join("node.toml");
save_config_file(&config, &config_path).unwrap();
let peer = ConnectInfo {
address: "0.0.0.1:8080".to_owned(),
public_key: KeyPair::random().public_key(),
};
let connect_list = ConnectListConfig { peers: vec![peer] };
DefaultConfigManager::update_connect_list(connect_list.clone(), &config_path)
.expect("Unable to update connect list");
let config: NodeConfig = load_config_file(&config_path).unwrap();
let new_connect_list = config.private_config.connect_list;
assert_eq!(new_connect_list.peers, connect_list.peers);
}
}