1use crate::service;2use futures::{future::{select, Map}, FutureExt, TryFutureExt, channel::oneshot, compat::Future01CompatExt};3use std::cell::RefCell;4use tokio::runtime::Runtime;5pub use sc_cli::{VersionInfo, IntoExit, error};6use sc_cli::{display_role, informant, parse_and_prepare, ParseAndPrepare, NoCustom};7use sc_service::{AbstractService, Roles as ServiceRoles, Configuration};8use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};9use crate::chain_spec;10use log::info;111213pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()> where14 I: IntoIterator<Item = T>,15 T: Into<std::ffi::OsString> + Clone,16 E: IntoExit,17{18 type Config<T> = Configuration<(), T>;19 match parse_and_prepare::<NoCustom, NoCustom, _>(&version, "substrate-node", args) {20 ParseAndPrepare::Run(cmd) => cmd.run(load_spec, exit,21 |exit, _cli_args, _custom_args, config: Config<_>| {22 info!("{}", version.name);23 info!(" version {}", config.full_version());24 info!(" by {}, 2017, 2018", version.author);25 info!("Chain specification: {}", config.chain_spec.name());26 info!("Node name: {}", config.name);27 info!("Roles: {}", display_role(&config));28 let runtime = Runtime::new().map_err(|e| format!("{:?}", e))?;29 match config.roles {30 ServiceRoles::LIGHT => run_until_exit(31 runtime,32 service::new_light(config)?,33 exit34 ),35 _ => run_until_exit(36 runtime,37 service::new_full(config)?,38 exit39 ),40 }41 }),42 ParseAndPrepare::BuildSpec(cmd) => cmd.run::<NoCustom, _, _, _>(load_spec),43 ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>|44 Ok(new_full_start!(config).0), load_spec, exit),45 ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>|46 Ok(new_full_start!(config).0), load_spec, exit),47 ParseAndPrepare::CheckBlock(cmd) => cmd.run_with_builder(|config: Config<_>|48 Ok(new_full_start!(config).0), load_spec, exit),49 ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec),50 ParseAndPrepare::RevertChain(cmd) => cmd.run_with_builder(|config: Config<_>|51 Ok(new_full_start!(config).0), load_spec),52 ParseAndPrepare::CustomCommand(_) => Ok(())53 }?;5455 Ok(())56}5758fn load_spec(id: &str) -> Result<Option<chain_spec::ChainSpec>, String> {59 Ok(match chain_spec::Alternative::from(id) {60 Some(spec) => Some(spec.load()?),61 None => None,62 })63}6465fn run_until_exit<T, E>(66 mut runtime: Runtime,67 service: T,68 e: E,69) -> error::Result<()>70where71 T: AbstractService,72 E: IntoExit,73{74 let (exit_send, exit) = oneshot::channel();7576 let informant = informant::build(&service);7778 let future = select(exit, informant)79 .map(|_| Ok(()))80 .compat();8182 runtime.executor().spawn(future);8384 85 86 let _telemetry = service.telemetry();8788 let service_res = {89 let exit = e.into_exit();90 let service = service91 .map_err(|err| error::Error::Service(err))92 .compat();93 let select = select(service, exit)94 .map(|_| Ok(()))95 .compat();96 runtime.block_on(select)97 };9899 let _ = exit_send.send(());100101 102103 use futures01::Future;104105 let _ = runtime.shutdown_on_idle().wait();106107 service_res108}109110111pub struct Exit;112impl IntoExit for Exit {113 type Exit = Map<oneshot::Receiver<()>, fn(Result<(), oneshot::Canceled>) -> ()>;114 fn into_exit(self) -> Self::Exit {115 116 let (exit_send, exit) = oneshot::channel();117118 let exit_send_cell = RefCell::new(Some(exit_send));119 ctrlc::set_handler(move || {120 let exit_send = exit_send_cell.try_borrow_mut().expect("signal handler not reentrant; qed").take();121 if let Some(exit_send) = exit_send {122 exit_send.send(()).expect("Error sending exit notification");123 }124 }).expect("Error setting Ctrl-C handler");125126 exit.map(drop)127 }128}