diff --git a/parity/cli.rs b/parity/cli.rs index 9b0e8c0be..6d5cdee19 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -186,6 +186,7 @@ Legacy Options: Miscellaneous Options: -l --logging LOGGING Specify the logging level. Must conform to the same format as RUST_LOG. + --no-color Don't use terminal color codes in output. -v --version Show information about version. -h --help Show this screen. "#; @@ -247,6 +248,7 @@ pub struct Args { pub flag_to: String, pub flag_format: Option, pub flag_jitvm: bool, + pub flag_no_color: bool, // legacy... pub flag_geth: bool, pub flag_nodekey: Option, diff --git a/parity/informant.rs b/parity/informant.rs index d22e4b728..c69c8938e 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -15,10 +15,12 @@ // along with Parity. If not, see . extern crate ansi_term; +use self::ansi_term::Colour::{White, Yellow, Green, Cyan, Blue, Purple}; +use self::ansi_term::Style; +use std::time::{Instant, Duration}; use std::sync::RwLock; use std::ops::{Deref, DerefMut}; -use ansi_term::Colour::*; use ethsync::{EthSync, SyncProvider}; use util::Uint; use ethcore::client::*; @@ -28,6 +30,8 @@ pub struct Informant { chain_info: RwLock>, cache_info: RwLock>, report: RwLock>, + last_tick: RwLock, + with_color: bool, } impl Default for Informant { @@ -36,11 +40,34 @@ impl Default for Informant { chain_info: RwLock::new(None), cache_info: RwLock::new(None), report: RwLock::new(None), + last_tick: RwLock::new(Instant::now()), + with_color: true, } } } +trait MillisecondDuration { + fn as_milliseconds(&self) -> u64; +} + +impl MillisecondDuration for Duration { + fn as_milliseconds(&self) -> u64 { + self.as_secs() * 1000 + self.subsec_nanos() as u64 / 1000000 + } +} + impl Informant { + /// Make a new instance potentially `with_color` output. + pub fn new(with_color: bool) -> Self { + Informant { + chain_info: RwLock::new(None), + cache_info: RwLock::new(None), + report: RwLock::new(None), + last_tick: RwLock::new(Instant::now()), + with_color: with_color, + } + } + fn format_bytes(b: usize) -> String { match binary_prefix(b as f64) { Standalone(bytes) => format!("{} bytes", bytes), @@ -48,42 +75,64 @@ impl Informant { } } - pub fn tick(&self, client: &Client, sync: &EthSync) { - // 5 seconds betwen calls. TODO: calculate this properly. - let dur = 5usize; + pub fn tick(&self, client: &Client, maybe_sync: Option<&EthSync>) { + let elapsed = self.last_tick.read().unwrap().elapsed(); + if elapsed < Duration::from_secs(5) { + return; + } + + *self.last_tick.write().unwrap() = Instant::now(); let chain_info = client.chain_info(); let queue_info = client.queue_info(); let cache_info = client.blockchain_cache_info(); - let sync_info = sync.status(); let mut write_report = self.report.write().unwrap(); let report = client.report(); + let paint = |c: Style, t: String| match self.with_color { + true => format!("{}", c.paint(t)), + false => t, + }; + if let (_, _, &Some(ref last_report)) = ( self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), write_report.deref() ) { - println!("#{} {} {} blk/s {} tx/s {} Kgas/s {}/{} peers #{} {}+{} Qed {} db {} chain {} queue {} sync", - White.bold().paint(format!("{:<7}", chain_info.best_block_number)), - White.bold().paint(format!("{}", chain_info.best_block_hash)), + println!("{} {} {} blk/s {} tx/s {} Mgas/s {}{}+{} Qed {} db {} chain {} queue{}", + paint(White.bold(), format!("{:>8}", format!("#{}", chain_info.best_block_number))), + paint(White.bold(), format!("{}", chain_info.best_block_hash)), - Yellow.bold().paint(format!("{:3}", (report.blocks_imported - last_report.blocks_imported) / dur)), - Yellow.bold().paint(format!("{:3}", (report.transactions_applied - last_report.transactions_applied) / dur)), - Yellow.bold().paint(format!("{:4}", ((report.gas_processed - last_report.gas_processed) / From::from(dur * 1000)).low_u64())), + paint(Yellow.bold(), format!("{:4}", ((report.blocks_imported - last_report.blocks_imported) * 1000) as u64 / elapsed.as_milliseconds())), + paint(Yellow.bold(), format!("{:4}", ((report.transactions_applied - last_report.transactions_applied) * 1000) as u64 / elapsed.as_milliseconds())), + paint(Yellow.bold(), format!("{:3}", ((report.gas_processed - last_report.gas_processed) / From::from(elapsed.as_milliseconds() * 1000)).low_u64())), - Green.bold().paint(format!("{:2}", sync_info.num_active_peers)), - Green.bold().paint(format!("{:2}", sync_info.num_peers)), + match maybe_sync { + Some(sync) => { + let sync_info = sync.status(); + format!("{}/{} peers {} ", + paint(Green.bold(), format!("{:2}", sync_info.num_active_peers)), + paint(Green.bold(), format!("{:2}", sync_info.num_peers)), + paint(Cyan.bold(), format!("{:>8}", format!("#{}", sync_info.last_imported_block_number.unwrap_or(chain_info.best_block_number)))), + ) + } + None => String::new() + }, - Cyan.bold().paint(format!("{:<7}", sync_info.last_imported_block_number.unwrap_or(chain_info.best_block_number))), - Blue.bold().paint(format!("{:4}", queue_info.unverified_queue_size)), - Blue.bold().paint(format!("{:4}", queue_info.verified_queue_size)), + paint(Blue.bold(), format!("{:5}", queue_info.unverified_queue_size)), + paint(Blue.bold(), format!("{:5}", queue_info.verified_queue_size)), - Purple.bold().paint(format!("{:>8}", Informant::format_bytes(report.state_db_mem))), - Purple.bold().paint(format!("{:>8}", Informant::format_bytes(cache_info.total()))), - Purple.bold().paint(format!("{:>8}", Informant::format_bytes(queue_info.mem_used))), - Purple.bold().paint(format!("{:>8}", Informant::format_bytes(sync_info.mem_used))), + paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(report.state_db_mem))), + paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(cache_info.total()))), + paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(queue_info.mem_used))), + match maybe_sync { + Some(sync) => { + let sync_info = sync.status(); + format!(" {} sync", paint(Purple.bold(), format!("{:>8}", Informant::format_bytes(sync_info.mem_used)))) + } + None => String::new() + }, ); } diff --git a/parity/io_handler.rs b/parity/io_handler.rs index 07cebb5b7..d130d584c 100644 --- a/parity/io_handler.rs +++ b/parity/io_handler.rs @@ -39,12 +39,11 @@ impl IoHandler for ClientIoHandler { fn initialize(&self, io: &IoContext) { io.register_timer(INFO_TIMER, 5000).expect("Error registering timer"); io.register_timer(ACCOUNT_TICK_TIMER, ACCOUNT_TICK_MS).expect("Error registering account timer"); - } fn timeout(&self, _io: &IoContext, timer: TimerToken) { match timer { - INFO_TIMER => { self.info.tick(&self.client, &self.sync); } + INFO_TIMER => { self.info.tick(&self.client, Some(&self.sync)); } ACCOUNT_TICK_TIMER => { self.accounts.tick(); }, _ => {} } diff --git a/parity/main.rs b/parity/main.rs index 6a73b5f5a..5bdbce9c5 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -22,7 +22,6 @@ #![cfg_attr(feature="dev", allow(useless_format))] extern crate docopt; -extern crate ansi_term; extern crate num_cpus; extern crate rustc_serialize; extern crate ethcore_util as util; @@ -66,8 +65,9 @@ mod configuration; use ctrlc::CtrlC; use util::*; +use std::time::Duration; use std::fs::File; -use std::thread::yield_now; +use std::thread::sleep; use std::io::{BufReader, BufRead}; use util::panics::{MayPanic, ForwardPanic, PanicHandler}; use ethcore::client::{BlockID, BlockChainClient}; @@ -76,6 +76,7 @@ use ethcore::service::ClientService; use ethsync::EthSync; use ethminer::{Miner, MinerService, ExternalMiner}; use daemonize::Daemonize; +use informant::Informant; use die::*; use cli::print_version; @@ -218,7 +219,7 @@ fn execute_client(conf: Configuration) { // Register IO handler let io_handler = Arc::new(ClientIoHandler { client: service.client(), - info: Default::default(), + info: Informant::new(!conf.args.flag_no_color), sync: sync.clone(), accounts: account_service.clone(), }); @@ -370,13 +371,16 @@ fn execute_import(conf: Configuration) { } }; + let informant = Informant::new(!conf.args.flag_no_color); + let do_import = |bytes| { - while client.queue_info().is_full() { yield_now(); } + while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } match client.import_block(bytes) { - Ok(_) => { println!("Block imported ok"); } + Ok(_) => {} Err(Error::Import(ImportError::AlreadyInChain)) => { trace!("Skipping block already in chain."); } Err(e) => die!("Cannot import block: {:?}", e) } + informant.tick(client.deref(), None); }; match format {