use anyhow::Error;
use exonum::keys::{read_keys_from_file, Keys};
use serde_derive::{Deserialize, Serialize};
use structopt::StructOpt;
use std::{
net::SocketAddr,
path::{Path, PathBuf},
};
use crate::{
command::{ExonumCommand, StandardResult},
config::NodeConfig,
io::load_config_file,
password::{PassInputMethod, PassphraseUsage},
};
#[derive(Debug)]
#[non_exhaustive]
pub struct NodeRunConfig {
pub node_config: NodeConfig,
pub node_keys: Keys,
pub db_path: PathBuf,
pub node_config_path: PathBuf,
}
#[derive(StructOpt, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Run {
#[structopt(long, short = "c")]
pub node_config: PathBuf,
#[structopt(long, short = "d")]
pub db_path: PathBuf,
#[structopt(long)]
pub public_api_address: Option<SocketAddr>,
#[structopt(long)]
pub private_api_address: Option<SocketAddr>,
#[structopt(long)]
pub master_key_pass: Option<PassInputMethod>,
}
impl ExonumCommand for Run {
fn execute(self) -> Result<StandardResult, Error> {
let config_path = &self.node_config;
let mut config: NodeConfig = load_config_file(config_path)?;
let public_addr = self.public_api_address;
let private_addr = self.private_api_address;
if let Some(public_addr) = public_addr {
config.private_config.api.public_api_address = Some(public_addr);
}
if let Some(private_api_address) = private_addr {
config.private_config.api.private_api_address = Some(private_api_address);
}
let master_passphrase = self
.master_key_pass
.unwrap_or_default()
.get_passphrase(PassphraseUsage::Using)?;
let node_keys = read_secret_keys(
config_path,
&config.private_config.master_key_path,
master_passphrase.as_bytes(),
);
let run_config = NodeRunConfig {
node_config: config,
node_keys,
db_path: self.db_path,
node_config_path: self.node_config,
};
Ok(StandardResult::Run(Box::new(run_config)))
}
}
fn read_secret_keys(
config_file_path: impl AsRef<Path>,
master_key_path: &Path,
master_key_passphrase: &[u8],
) -> Keys {
let config_folder = config_file_path.as_ref().parent().unwrap();
let master_key_path = if master_key_path.is_absolute() {
master_key_path.to_owned()
} else {
config_folder.join(&master_key_path)
};
read_keys_from_file(&master_key_path, master_key_passphrase)
.expect("Could not read master_key_path from file")
}