use std::fmt;
use std::panic::{self, PanicInfo};
use std::ffi::OsString;
use std::collections::HashMap;
use blockchain::Service;
use node::Node;
use super::internal::{CollectedCommand, Feedback};
use super::clap_backend::ClapBackend;
use super::ServiceFactory;
use super::details::{Run, RunDev, Finalize, GenerateNodeConfig, GenerateCommonConfig,
GenerateTestnet};
use super::keys;
use super::CommandName;
#[derive(Default)]
pub struct NodeBuilder {
commands: HashMap<CommandName, CollectedCommand>,
service_factories: Vec<Box<ServiceFactory>>,
}
impl NodeBuilder {
pub fn new() -> Self {
NodeBuilder {
commands: Self::commands(),
service_factories: Vec::new(),
}
}
pub fn with_service(mut self, mut factory: Box<ServiceFactory>) -> NodeBuilder {
for (name, command) in &mut self.commands {
command.extend(factory.command(name))
}
self.service_factories.push(factory);
self
}
#[doc(hidden)]
pub fn parse_cmd_string<I, T>(self, cmd_line: I) -> bool
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let feedback = ClapBackend::execute_cmd_string(&self.commands, cmd_line);
feedback != Feedback::None
}
pub fn parse_cmd(self) -> Option<Node> {
match ClapBackend::execute(&self.commands) {
Feedback::RunNode(ref ctx) => {
let db = Run::db_helper(ctx);
let config = ctx.get(keys::NODE_CONFIG).expect(
"could not find node_config",
);
let services: Vec<Box<Service>> = self.service_factories
.into_iter()
.map(|mut factory| factory.make_service(ctx))
.collect();
let node = Node::new(db, services, config);
Some(node)
}
_ => None,
}
}
fn panic_hook(info: &PanicInfo) {
let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
None => {
match info.payload().downcast_ref::<String>() {
Some(s) => &s[..],
None => "Box<Any>",
}
}
};
println!("error: {}", msg);
}
pub fn run(self) {
let old_hook = panic::take_hook();
panic::set_hook(Box::new(Self::panic_hook));
let feedback = self.parse_cmd();
panic::set_hook(old_hook);
if let Some(node) = feedback {
node.run().expect("Node return error")
}
}
fn commands() -> HashMap<CommandName, CollectedCommand> {
let mut commands = HashMap::new();
commands.insert(
GenerateTestnet::name(),
CollectedCommand::new(Box::new(GenerateTestnet)),
);
commands.insert(Run::name(), CollectedCommand::new(Box::new(Run)));
commands.insert(RunDev::name(), CollectedCommand::new(Box::new(RunDev)));
commands.insert(
GenerateNodeConfig::name(),
CollectedCommand::new(Box::new(GenerateNodeConfig)),
);
commands.insert(
GenerateCommonConfig::name(),
CollectedCommand::new(Box::new(GenerateCommonConfig)),
);
commands.insert(Finalize::name(), CollectedCommand::new(Box::new(Finalize)));
commands
}
}
impl fmt::Debug for NodeBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"NodeBuilder {{ commands: {:?}, services_count: {} }}",
self.commands.values(),
self.service_factories.len()
)
}
}