IPC (feature-gated) (#1654)
* moving ipc deriving to trait * refactoring of the client * all compiled * proved all working * warnings purged * allow hypervisor to specify initialization payload in two ways * using binary initialisation payload for sync * some docs * logger to separate crate * log settings for sync bin * forwarding logging arguments to the sync
This commit is contained in:
committed by
Arkadiy Paronyan
parent
7ae9e61d6c
commit
8ab56ea3d1
@@ -34,6 +34,7 @@ use ethcore::ethereum;
|
||||
use ethcore::spec::Spec;
|
||||
use ethsync::SyncConfig;
|
||||
use rpc::IpcConfiguration;
|
||||
use ethcore_logger::Settings as LogSettings;
|
||||
|
||||
pub struct Configuration {
|
||||
pub args: Args
|
||||
@@ -564,6 +565,20 @@ impl Configuration {
|
||||
(self.args.flag_unlock.is_none() && !self.args.flag_no_signer) ||
|
||||
self.args.flag_force_signer
|
||||
}
|
||||
|
||||
pub fn log_settings(&self) -> LogSettings {
|
||||
let mut settings = LogSettings::new();
|
||||
if self.args.flag_no_color || cfg!(windows) {
|
||||
settings = settings.no_color();
|
||||
}
|
||||
if let Some(ref init) = self.args.flag_logging {
|
||||
settings = settings.init(init.to_owned())
|
||||
}
|
||||
if let Some(ref file) = self.args.flag_log_file {
|
||||
settings = settings.file(file.to_owned())
|
||||
}
|
||||
settings
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -53,15 +53,16 @@ extern crate ansi_term;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate regex;
|
||||
extern crate ethcore_logger;
|
||||
extern crate isatty;
|
||||
|
||||
#[cfg(feature = "dapps")]
|
||||
extern crate ethcore_dapps;
|
||||
|
||||
|
||||
#[macro_use]
|
||||
mod die;
|
||||
mod upgrade;
|
||||
mod setup_log;
|
||||
mod rpc;
|
||||
mod dapps;
|
||||
mod informant;
|
||||
@@ -86,7 +87,7 @@ use rustc_serialize::hex::FromHex;
|
||||
use ctrlc::CtrlC;
|
||||
use util::{H256, ToPretty, PayloadInfo, Bytes, Colour, version, journaldb, RotatingLogger};
|
||||
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
||||
use ethcore::client::{BlockID, BlockChainClient, ClientConfig, get_db_path, BlockImportError, Mode, ChainNotify};
|
||||
use ethcore::client::{BlockID, BlockChainClient, ClientConfig, get_db_path, BlockImportError, Mode};
|
||||
use ethcore::error::{ImportError};
|
||||
use ethcore::service::ClientService;
|
||||
use ethcore::spec::Spec;
|
||||
@@ -95,6 +96,9 @@ use ethcore::miner::{Miner, MinerService, ExternalMiner};
|
||||
use migration::migrate;
|
||||
use informant::Informant;
|
||||
use util::{Mutex, Condvar};
|
||||
use ethcore_logger::setup_log;
|
||||
#[cfg(feature="ipc")]
|
||||
use ethcore::client::ChainNotify;
|
||||
|
||||
use die::*;
|
||||
use cli::print_version;
|
||||
@@ -132,7 +136,7 @@ fn execute(conf: Configuration) {
|
||||
// Setup panic handler
|
||||
let panic_handler = PanicHandler::new_in_arc();
|
||||
// Setup logging
|
||||
let logger = setup_log::setup_log(&conf.args.flag_logging, conf.have_color(), &conf.args.flag_log_file);
|
||||
let logger = setup_log(&conf.log_settings());
|
||||
// Raise fdlimit
|
||||
unsafe { ::fdlimit::raise_fd_limit(); }
|
||||
|
||||
@@ -192,6 +196,8 @@ fn execute_upgrades(conf: &Configuration, spec: &Spec, client_config: &ClientCon
|
||||
}
|
||||
|
||||
fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig, panic_handler: Arc<PanicHandler>, logger: Arc<RotatingLogger>) {
|
||||
let mut hypervisor = modules::hypervisor();
|
||||
|
||||
info!("Starting {}", Colour::White.bold().paint(format!("{}", version())));
|
||||
info!("Using state DB journalling strategy {}", Colour::White.bold().paint(match client_config.pruning {
|
||||
journaldb::Algorithm::Archive => "archive",
|
||||
@@ -244,9 +250,10 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig,
|
||||
|
||||
// Sync
|
||||
let (sync_provider, manage_network, chain_notify) =
|
||||
modules::sync(sync_config, NetworkConfiguration::from(net_settings), client.clone())
|
||||
modules::sync(&mut hypervisor, sync_config, NetworkConfiguration::from(net_settings), client.clone(), &conf.log_settings())
|
||||
.unwrap_or_else(|e| die_with_error("Sync", e));
|
||||
service.add_notify(&chain_notify);
|
||||
|
||||
service.add_notify(chain_notify.clone());
|
||||
|
||||
// if network is active by default
|
||||
if match conf.mode() { Mode::Dark(..) => false, _ => !conf.args.flag_no_network } {
|
||||
@@ -311,8 +318,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig,
|
||||
});
|
||||
|
||||
let informant = Arc::new(Informant::new(service.client(), Some(sync_provider.clone()), Some(manage_network.clone()), conf.have_color()));
|
||||
let info_notify: Arc<ChainNotify> = informant.clone();
|
||||
service.add_notify(&info_notify);
|
||||
service.add_notify(informant.clone());
|
||||
// Register IO handler
|
||||
let io_handler = Arc::new(ClientIoHandler {
|
||||
client: service.client(),
|
||||
|
||||
@@ -14,28 +14,116 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethsync::{EthSync, SyncProvider, ManageNetwork, SyncConfig, NetworkConfiguration};
|
||||
use std::sync::Arc;
|
||||
use ethcore::client::{ChainNotify, BlockChainClient};
|
||||
use ethcore::client::BlockChainClient;
|
||||
use ethcore;
|
||||
use hypervisor::Hypervisor;
|
||||
use ethsync::{SyncConfig, NetworkConfiguration};
|
||||
#[cfg(not(feature="ipc"))]
|
||||
use self::no_ipc_deps::*;
|
||||
#[cfg(feature="ipc")]
|
||||
use self::ipc_deps::*;
|
||||
|
||||
pub type Modules = (Arc<SyncProvider>, Arc<ManageNetwork>, Arc<ChainNotify>);
|
||||
use ethcore_logger::Settings as LogSettings;
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
mod no_ipc_deps {
|
||||
pub use ethsync::{EthSync, SyncProvider, ManageNetwork};
|
||||
pub use ethcore::client::ChainNotify;
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
pub fn sync(
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
client: Arc<BlockChainClient>)
|
||||
-> Result<Modules, ethcore::error::Error>
|
||||
{
|
||||
pub type SyncModules = (
|
||||
GuardedSocket<SyncClient<NanoSocket>>,
|
||||
GuardedSocket<NetworkManagerClient<NanoSocket>>,
|
||||
GuardedSocket<ChainNotifyClient<NanoSocket>>
|
||||
);
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
pub type SyncModules = (Arc<SyncProvider>, Arc<ManageNetwork>, Arc<ChainNotify>);
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
mod ipc_deps {
|
||||
pub use ethsync::{SyncClient, NetworkManagerClient, ServiceConfiguration};
|
||||
pub use ethcore::client::ChainNotifyClient;
|
||||
pub use hypervisor::{SYNC_MODULE_ID, BootArgs};
|
||||
pub use nanoipc::{GuardedSocket, NanoSocket, init_client};
|
||||
pub use ipc::IpcSocket;
|
||||
pub use ipc::binary::serialize;
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
pub fn hypervisor() -> Option<Hypervisor> {
|
||||
Some(Hypervisor::new())
|
||||
}
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
pub fn sync(
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
client: Arc<BlockChainClient>)
|
||||
-> Result<Modules, ethcore::error::Error>
|
||||
pub fn hypervisor() -> Option<Hypervisor> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
fn sync_arguments(sync_cfg: SyncConfig, net_cfg: NetworkConfiguration, log_settings: &LogSettings) -> BootArgs {
|
||||
let service_config = ServiceConfiguration {
|
||||
sync: sync_cfg,
|
||||
net: net_cfg,
|
||||
};
|
||||
|
||||
// initialisation payload is passed via stdin
|
||||
let service_payload = serialize(&service_config).expect("Any binary-derived struct is serializable by definition");
|
||||
|
||||
// client service url and logging settings are passed in command line
|
||||
let mut cli_args = Vec::new();
|
||||
cli_args.push("ipc:///tmp/parity-chain.ipc".to_owned());
|
||||
if !log_settings.color { cli_args.push("--no-color".to_owned()); }
|
||||
if let Some(ref init) = log_settings.init {
|
||||
cli_args.push("-l".to_owned());
|
||||
cli_args.push(init.to_owned());
|
||||
}
|
||||
if let Some(ref file) = log_settings.file {
|
||||
cli_args.push("--log-file".to_owned());
|
||||
cli_args.push(file.to_owned());
|
||||
}
|
||||
|
||||
BootArgs::new().stdin(service_payload).cli(cli_args)
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
pub fn sync
|
||||
(
|
||||
hypervisor_ref: &mut Option<Hypervisor>,
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
_client: Arc<BlockChainClient>,
|
||||
log_settings: &LogSettings,
|
||||
)
|
||||
-> Result<SyncModules, ethcore::error::Error>
|
||||
{
|
||||
let mut hypervisor = hypervisor_ref.take().expect("There should be hypervisor for ipc configuration");
|
||||
hypervisor = hypervisor.module(SYNC_MODULE_ID, "sync", sync_arguments(sync_cfg, net_cfg, log_settings));
|
||||
|
||||
hypervisor.start();
|
||||
hypervisor.wait_for_startup();
|
||||
|
||||
let sync_client = init_client::<SyncClient<_>>("ipc:///tmp/parity-sync.ipc").unwrap();
|
||||
let notify_client = init_client::<ChainNotifyClient<_>>("ipc:///tmp/parity-sync-notify.ipc").unwrap();
|
||||
let manage_client = init_client::<NetworkManagerClient<_>>("ipc:///tmp/parity-manage-net.ipc").unwrap();
|
||||
|
||||
*hypervisor_ref = Some(hypervisor);
|
||||
Ok((sync_client, manage_client, notify_client))
|
||||
}
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
pub fn sync
|
||||
(
|
||||
_hypervisor: &mut Option<Hypervisor>,
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
client: Arc<BlockChainClient>,
|
||||
_log_settings: &LogSettings,
|
||||
)
|
||||
-> Result<SyncModules, ethcore::error::Error>
|
||||
{
|
||||
let eth_sync = try!(EthSync::new(sync_cfg, client, net_cfg).map_err(ethcore::error::Error::Util));
|
||||
Ok((eth_sync.clone() as Arc<SyncProvider>, eth_sync.clone() as Arc<ManageNetwork>, eth_sync.clone() as Arc<ChainNotify>))
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use isatty::{stderr_isatty};
|
||||
use time;
|
||||
use env_logger::LogBuilder;
|
||||
use regex::Regex;
|
||||
use util::RotatingLogger;
|
||||
use util::log::Colour;
|
||||
|
||||
/// Sets up the logger
|
||||
pub fn setup_log(init: &Option<String>, enable_color: bool, log_to_file: &Option<String>) -> Arc<RotatingLogger> {
|
||||
use rlog::*;
|
||||
|
||||
let mut levels = String::new();
|
||||
let mut builder = LogBuilder::new();
|
||||
// Disable ws info logging by default.
|
||||
builder.filter(Some("ws"), LogLevelFilter::Warn);
|
||||
builder.filter(None, LogLevelFilter::Info);
|
||||
|
||||
if env::var("RUST_LOG").is_ok() {
|
||||
let lvl = &env::var("RUST_LOG").unwrap();
|
||||
levels.push_str(lvl);
|
||||
levels.push_str(",");
|
||||
builder.parse(lvl);
|
||||
}
|
||||
|
||||
if let Some(ref s) = *init {
|
||||
levels.push_str(s);
|
||||
builder.parse(s);
|
||||
}
|
||||
|
||||
let enable_color = enable_color && stderr_isatty();
|
||||
let logs = Arc::new(RotatingLogger::new(levels));
|
||||
let logger = logs.clone();
|
||||
let maybe_file = log_to_file.as_ref().map(|f| File::create(f).unwrap_or_else(|_| die!("Cannot write to log file given: {}", f)));
|
||||
let format = move |record: &LogRecord| {
|
||||
let timestamp = time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).unwrap();
|
||||
|
||||
let with_color = if max_log_level() <= LogLevelFilter::Info {
|
||||
format!("{}{}", Colour::Black.bold().paint(timestamp), record.args())
|
||||
} else {
|
||||
format!("{}{}:{}: {}", Colour::Black.bold().paint(timestamp), record.level(), record.target(), record.args())
|
||||
};
|
||||
|
||||
let removed_color = kill_color(with_color.as_ref());
|
||||
|
||||
let ret = match enable_color {
|
||||
true => with_color,
|
||||
false => removed_color.clone(),
|
||||
};
|
||||
|
||||
if let Some(mut file) = maybe_file.as_ref() {
|
||||
// ignore errors - there's nothing we can do
|
||||
let _ = file.write_all(removed_color.as_bytes());
|
||||
let _ = file.write_all(b"\n");
|
||||
}
|
||||
logger.append(removed_color);
|
||||
|
||||
ret
|
||||
};
|
||||
builder.format(format);
|
||||
builder.init().unwrap();
|
||||
logs
|
||||
}
|
||||
|
||||
fn kill_color(s: &str) -> String {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new("\x1b\\[[^m]+m").unwrap();
|
||||
}
|
||||
RE.replace_all(s, "")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_remove_colour() {
|
||||
let before = "test";
|
||||
let after = kill_color(&Colour::Red.bold().paint(before));
|
||||
assert_eq!(after, "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_remove_multiple_colour() {
|
||||
let t = format!("{} {}", Colour::Red.bold().paint("test"), Colour::White.normal().paint("again"));
|
||||
let after = kill_color(&t);
|
||||
assert_eq!(after, "test again");
|
||||
}
|
||||
@@ -26,6 +26,7 @@ extern crate rustc_serialize;
|
||||
extern crate docopt;
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate ethcore_logger;
|
||||
|
||||
use std::sync::Arc;
|
||||
use hypervisor::{HypervisorServiceClient, SYNC_MODULE_ID, HYPERVISOR_IPC_URL};
|
||||
@@ -33,63 +34,47 @@ use ctrlc::CtrlC;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use docopt::Docopt;
|
||||
use ethcore::client::{RemoteClient, ChainNotify};
|
||||
use ethsync::{SyncProvider, SyncConfig, EthSync, ManageNetwork, NetworkConfiguration};
|
||||
use ethsync::{SyncProvider, EthSync, ManageNetwork, ServiceConfiguration};
|
||||
use std::thread;
|
||||
use util::numbers::{U256, H256};
|
||||
use std::str::FromStr;
|
||||
use nanoipc::IpcInterface;
|
||||
use util::sha3::Hashable;
|
||||
|
||||
use ethcore_logger::Settings as LogSettings;
|
||||
use ethcore_logger::setup_log;
|
||||
|
||||
const USAGE: &'static str = "
|
||||
Ethcore sync service
|
||||
Usage:
|
||||
sync <client-url> <network-id> <listen-address> <nat-enabled> <discovery-enabled> <ideal-peers> <config-path> <allow-non-reserved> [options]
|
||||
sync <client-url> [options]
|
||||
|
||||
Options:
|
||||
--public-address IP Public address.
|
||||
--boot-nodes LIST List of boot nodes.
|
||||
--reserved-nodes LIST List of reserved peers,
|
||||
--secret HEX Use node key hash
|
||||
--udp-port UDP port
|
||||
Options:
|
||||
-l --logging LOGGING Specify the logging level. Must conform to the same
|
||||
format as RUST_LOG.
|
||||
--log-file FILENAME Specify a filename into which logging should be
|
||||
directed.
|
||||
--no-color Don't use terminal color codes in output.
|
||||
";
|
||||
|
||||
#[derive(Debug, RustcDecodable)]
|
||||
struct Args {
|
||||
arg_network_id: String,
|
||||
arg_listen_address: String,
|
||||
arg_nat_enabled: bool,
|
||||
arg_discovery_enabled: bool,
|
||||
arg_ideal_peers: u32,
|
||||
arg_config_path: String,
|
||||
arg_client_url: String,
|
||||
arg_allow_non_reserved: bool,
|
||||
flag_public_address: Option<String>,
|
||||
flag_secret: Option<String>,
|
||||
flag_boot_nodes: Vec<String>,
|
||||
flag_reserved_nodes: Vec<String>,
|
||||
flag_udp_port: Option<u16>,
|
||||
flag_logging: Option<String>,
|
||||
flag_log_file: Option<String>,
|
||||
flag_no_color: bool,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn into_config(self) -> (SyncConfig, NetworkConfiguration, String) {
|
||||
let mut sync_config = SyncConfig::default();
|
||||
sync_config.network_id = U256::from_str(&self.arg_network_id).unwrap();
|
||||
|
||||
let network_config = NetworkConfiguration {
|
||||
udp_port: self.flag_udp_port,
|
||||
nat_enabled: self.arg_nat_enabled,
|
||||
boot_nodes: self.flag_boot_nodes,
|
||||
listen_address: Some(self.arg_listen_address),
|
||||
public_address: self.flag_public_address,
|
||||
use_secret: self.flag_secret.as_ref().map(|s| H256::from_str(s).unwrap_or_else(|_| s.sha3())),
|
||||
discovery_enabled: self.arg_discovery_enabled,
|
||||
ideal_peers: self.arg_ideal_peers,
|
||||
config_path: Some(self.arg_config_path),
|
||||
reserved_nodes: self.flag_reserved_nodes,
|
||||
allow_non_reserved: self.arg_allow_non_reserved,
|
||||
};
|
||||
|
||||
(sync_config, network_config, self.arg_client_url)
|
||||
pub fn log_settings(&self) -> LogSettings {
|
||||
let mut settings = LogSettings::new();
|
||||
if self.flag_no_color || cfg!(windows) {
|
||||
settings = settings.no_color();
|
||||
}
|
||||
if let Some(ref init) = self.flag_logging {
|
||||
settings = settings.init(init.to_owned())
|
||||
}
|
||||
if let Some(ref file) = self.flag_log_file {
|
||||
settings = settings.file(file.to_owned())
|
||||
}
|
||||
settings
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,16 +91,24 @@ fn run_service<T: ?Sized + Send + Sync + 'static>(addr: &str, stop_guard: Arc<At
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use std::io::{self, Read};
|
||||
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| d.decode())
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
let (sync_config, network_config, client_url) = args.into_config();
|
||||
let remote_client = nanoipc::init_client::<RemoteClient<_>>(&client_url).unwrap();
|
||||
|
||||
setup_log(&args.log_settings());
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
io::stdin().read_to_end(&mut buffer).expect("Failed to read initialisation payload");
|
||||
let service_config = ipc::binary::deserialize::<ServiceConfiguration>(&buffer).expect("Failed deserializing initialisation payload");
|
||||
|
||||
let remote_client = nanoipc::init_client::<RemoteClient<_>>(&args.arg_client_url).unwrap();
|
||||
|
||||
remote_client.handshake().unwrap();
|
||||
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
let sync = EthSync::new(sync_config, remote_client.service().clone(), network_config).unwrap();
|
||||
let sync = EthSync::new(service_config.sync, remote_client.service().clone(), service_config.net).unwrap();
|
||||
|
||||
run_service("ipc:///tmp/parity-sync.ipc", stop.clone(), sync.clone() as Arc<SyncProvider>);
|
||||
run_service("ipc:///tmp/parity-manage-net.ipc", stop.clone(), sync.clone() as Arc<ManageNetwork>);
|
||||
|
||||
Reference in New Issue
Block a user