diff --git a/Cargo.lock b/Cargo.lock index d9c963809..71af4a91b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,7 @@ dependencies = [ "ethsync 1.2.0", "fdlimit 0.1.0", "hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "json-ipc-server 0.1.0 (git+https://github.com/NikVolf/json-ipc-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -316,6 +317,7 @@ dependencies = [ "ethcore-util 1.2.0", "ethminer 1.2.0", "ethsync 1.2.0", + "json-ipc-server 0.1.0 (git+https://github.com/NikVolf/json-ipc-server.git)", "jsonrpc-core 2.0.3 (git+https://github.com/tomusdrw/jsonrpc-core.git)", "jsonrpc-http-server 5.1.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -551,6 +553,17 @@ name = "itertools" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "json-ipc-server" +version = "0.1.0" +source = "git+https://github.com/NikVolf/json-ipc-server.git#bd987c75b5f23c35eb7e2b0bd8b30ba88f758338" +dependencies = [ + "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.3 (git+https://github.com/tomusdrw/jsonrpc-core.git)", + "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "json-tests" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index fbc31b257..f6b328b29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ ethcore-ipc-nano = { path = "ipc/nano" } "ethcore-ipc" = { path = "ipc/rpc" } bincode = "*" serde = "0.7.0" +json-ipc-server = { git = "https://github.com/NikVolf/json-ipc-server.git" } [dependencies.hyper] version = "0.8" diff --git a/parity/cli.rs b/parity/cli.rs index e5a1d6e3d..106d65aa3 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -84,6 +84,12 @@ API and Console Options: --webapp-pass PASSWORD Specify password for WebApps server. Use only in conjunction with --webapp-user. + --ipc-disable Disable JSON-RPC over IPC service + --ipc-path PATH Specify custom path for IPC service + [default: $HOME/.parity/jsonrpc.ipc] + --ipc-api APIS Specify custom API set available via IPC service + [default: web3,eth,net,personal,ethcore] + Sealing/Mining Options: --force-sealing Force the node to author new blocks as if it were always sealing/mining. @@ -197,6 +203,9 @@ pub struct Args { pub flag_tx_limit: usize, pub flag_logging: Option, pub flag_version: bool, + pub flag_ipc_disable: bool, + pub flag_ipc_path: String, + pub flag_ipc_api: String, // geth-compatibility... pub flag_nodekey: Option, pub flag_nodiscover: bool, diff --git a/parity/configuration.rs b/parity/configuration.rs index c7f3dc957..0b32d5232 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -31,6 +31,7 @@ use ethcore::ethereum; use ethcore::spec::Spec; use ethsync::SyncConfig; use price_info::PriceInfo; +use rpc::IpcConfiguration; pub struct Configuration { pub args: Args @@ -266,6 +267,15 @@ impl Configuration { self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()) } + pub fn ipc_settings(&self) -> IpcConfiguration { + IpcConfiguration { + enabled: !self.args.flag_ipc_disable, + socket_addr: self.args.flag_ipc_path.clone() + .replace("$HOME", env::home_dir().unwrap().to_str().unwrap()), + apis: self.args.flag_ipc_api.clone(), + } + } + pub fn network_settings(&self) -> NetworkSettings { NetworkSettings { name: self.args.flag_identity.clone(), diff --git a/parity/main.rs b/parity/main.rs index 4fa18bd4d..23f299406 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -44,6 +44,7 @@ extern crate serde; extern crate bincode; #[macro_use] extern crate hyper; // for price_info.rs +extern crate json_ipc_server as jsonipc; #[cfg(feature = "rpc")] extern crate ethcore_rpc; @@ -159,14 +160,7 @@ fn execute_client(conf: Configuration) { // Sync let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); - // Setup rpc - let rpc_server = rpc::new(rpc::Configuration { - enabled: network_settings.rpc_enabled, - interface: network_settings.rpc_interface.clone(), - port: network_settings.rpc_port, - apis: conf.rpc_apis(), - cors: conf.rpc_cors(), - }, rpc::Dependencies { + let dependencies = Arc::new(rpc::Dependencies { panic_handler: panic_handler.clone(), client: client.clone(), sync: sync.clone(), @@ -177,6 +171,18 @@ fn execute_client(conf: Configuration) { settings: network_settings.clone(), }); + // Setup http rpc + let rpc_server = rpc::new_http(rpc::HttpConfiguration { + enabled: network_settings.rpc_enabled, + interface: network_settings.rpc_interface.clone(), + port: network_settings.rpc_port, + apis: conf.rpc_apis(), + cors: conf.rpc_cors(), + }, &dependencies); + + // setup ipc rpc + let ipc_server = rpc::new_ipc(conf.ipc_settings(), &dependencies); + let webapp_server = webapp::new(webapp::Configuration { enabled: conf.args.flag_webapp, interface: conf.args.flag_webapp_interface.clone(), diff --git a/parity/rpc.rs b/parity/rpc.rs index ff853d478..5a486613d 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -27,6 +27,7 @@ use util::panics::PanicHandler; use util::keys::store::{AccountService}; use util::network_settings::NetworkSettings; use die::*; +use jsonipc; #[cfg(feature = "rpc")] pub use ethcore_rpc::Server as RpcServer; @@ -35,7 +36,7 @@ use ethcore_rpc::{RpcServerError, RpcServer as Server}; #[cfg(not(feature = "rpc"))] pub struct RpcServer; -pub struct Configuration { +pub struct HttpConfiguration { pub enabled: bool, pub interface: String, pub port: u16, @@ -43,6 +44,12 @@ pub struct Configuration { pub cors: Option, } +pub struct IpcConfiguration { + pub enabled: bool, + pub socket_addr: String, + pub apis: String, +} + pub struct Dependencies { pub panic_handler: Arc, pub client: Arc, @@ -54,7 +61,7 @@ pub struct Dependencies { pub settings: Arc, } -pub fn new(conf: Configuration, deps: Dependencies) -> Option { +pub fn new_http(conf: HttpConfiguration, deps: &Arc) -> Option { if !conf.enabled { return None; } @@ -68,26 +75,16 @@ pub fn new(conf: Configuration, deps: Dependencies) -> Option { let url = format!("{}:{}", interface, conf.port); let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); - Some(setup_rpc_server(deps, &addr, conf.cors, apis)) + Some(setup_http_rpc_server(deps, &addr, conf.cors, apis)) } -#[cfg(not(feature = "rpc"))] -pub fn setup_rpc_server( - _deps: Dependencies, - _url: &SocketAddr, - _cors_domain: Option, - _apis: Vec<&str>, -) -> ! { - die!("Your Parity version has been compiled without JSON-RPC support.") +pub fn new_ipc(conf: IpcConfiguration, deps: &Arc) -> Option { + if !conf.enabled { return None; } + let apis = conf.apis.split(',').collect(); + Some(setup_ipc_rpc_server(deps, &conf.socket_addr, apis)) } -#[cfg(feature = "rpc")] -pub fn setup_rpc_server( - deps: Dependencies, - url: &SocketAddr, - cors_domain: Option, - apis: Vec<&str>, -) -> RpcServer { +fn setup_rpc_server(apis: Vec<&str>, deps: &Arc) -> Server { use ethcore_rpc::v1::*; let server = Server::new(); @@ -125,7 +122,29 @@ pub fn setup_rpc_server( } } server.add_delegate(RpcClient::new(modules).to_delegate()); + server +} + +#[cfg(not(feature = "rpc"))] +pub fn setup_http_rpc_server( + _deps: Dependencies, + _url: &SocketAddr, + _cors_domain: Option, + _apis: Vec<&str>, +) -> ! { + die!("Your Parity version has been compiled without JSON-RPC support.") +} + +#[cfg(feature = "rpc")] +pub fn setup_http_rpc_server( + dependencies: &Arc, + url: &SocketAddr, + cors_domain: Option, + apis: Vec<&str>, +) -> RpcServer { + let server = setup_rpc_server(apis, dependencies); let start_result = server.start_http(url, cors_domain); + let deps = dependencies.clone(); match start_result { Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err), Err(e) => die!("RPC: {:?}", e), @@ -138,3 +157,11 @@ pub fn setup_rpc_server( } } +pub fn setup_ipc_rpc_server(dependencies: &Arc, addr: &str, apis: Vec<&str>) -> jsonipc::Server { + let server = setup_rpc_server(apis, dependencies); + match server.start_ipc(addr) { + Err(jsonipc::Error::Io(io_error)) => die_with_io_error("RPC", io_error), + Err(any_error) => die!("RPC: {:?}", any_error), + Ok(server) => server + } +} diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 6a62b0410..1c8117335 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -23,6 +23,7 @@ rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } clippy = { version = "0.0.64", optional = true} +json-ipc-server = { git = "https://github.com/NikVolf/json-ipc-server.git" } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index d9f6af65c..d4998fdc3 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -31,6 +31,7 @@ extern crate ethcore; extern crate ethsync; extern crate ethminer; extern crate transient_hashmap; +extern crate json_ipc_server as ipc; use std::sync::Arc; use std::net::SocketAddr; @@ -41,7 +42,7 @@ pub mod v1; /// Http server. pub struct RpcServer { - handler: Arc, + handler: Arc, } impl RpcServer { @@ -62,4 +63,11 @@ impl RpcServer { let cors_domain = cors_domain.to_owned(); Server::start(addr, self.handler.clone(), cors_domain.map(jsonrpc_http_server::AccessControlAllowOrigin::Value)) } + + /// Start ipc server asynchronously and returns result with `Server` handle on success or an error. + pub fn start_ipc(&self, addr: &str) -> Result { + let server = try!(ipc::Server::new(addr, &self.handler)); + try!(server.run_async()); + Ok(server) + } }