Opening local dapp (#4041)
* Opening local dapp * Using Path/PathBuf instead of Strings * Fixing typo and adding some docs to apps::fs functions
This commit is contained in:
parent
332a45846d
commit
e983339edd
@ -17,7 +17,7 @@
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use page::{LocalPageEndpoint, PageCache};
|
||||
use endpoint::{Endpoints, EndpointInfo};
|
||||
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest};
|
||||
@ -28,10 +28,79 @@ struct LocalDapp {
|
||||
info: EndpointInfo,
|
||||
}
|
||||
|
||||
fn local_dapps(dapps_path: String) -> Vec<LocalDapp> {
|
||||
let files = fs::read_dir(dapps_path.as_str());
|
||||
/// Tries to find and read manifest file in given `path` to extract `EndpointInfo`
|
||||
/// If manifest is not found sensible default `EndpointInfo` is returned based on given `name`.
|
||||
fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
|
||||
path.push(MANIFEST_FILENAME);
|
||||
|
||||
fs::File::open(path.clone())
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
.and_then(|mut f| {
|
||||
// Reat file
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s).map_err(|e| format!("{:?}", e))?;
|
||||
// Try to deserialize manifest
|
||||
deserialize_manifest(s)
|
||||
})
|
||||
.map(Into::into)
|
||||
.unwrap_or_else(|e| {
|
||||
warn!(target: "dapps", "Cannot read manifest file at: {:?}. Error: {:?}", path, e);
|
||||
|
||||
EndpointInfo {
|
||||
name: name.into(),
|
||||
description: name.into(),
|
||||
version: "0.0.0".into(),
|
||||
author: "?".into(),
|
||||
icon_url: "icon.png".into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns Dapp Id and Local Dapp Endpoint for given filesystem path.
|
||||
/// Parses the path to extract last component (for name).
|
||||
/// `None` is returned when path is invalid or non-existent.
|
||||
pub fn local_endpoint<P: AsRef<Path>>(path: P, signer_address: Option<(String, u16)>) -> Option<(String, Box<LocalPageEndpoint>)> {
|
||||
let path = path.as_ref().to_owned();
|
||||
path.canonicalize().ok().and_then(|path| {
|
||||
let name = path.file_name().and_then(|name| name.to_str());
|
||||
name.map(|name| {
|
||||
let dapp = local_dapp(name.into(), path.clone());
|
||||
(dapp.id, Box::new(LocalPageEndpoint::new(
|
||||
dapp.path, dapp.info, PageCache::Disabled, signer_address.clone())
|
||||
))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
fn local_dapp(name: String, path: PathBuf) -> LocalDapp {
|
||||
// try to get manifest file
|
||||
let info = read_manifest(&name, path.clone());
|
||||
LocalDapp {
|
||||
id: name,
|
||||
path: path,
|
||||
info: info,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns endpoints for Local Dapps found for given filesystem path.
|
||||
/// Scans the directory and collects `LocalPageEndpoints`.
|
||||
pub fn local_endpoints<P: AsRef<Path>>(dapps_path: P, signer_address: Option<(String, u16)>) -> Endpoints {
|
||||
let mut pages = Endpoints::new();
|
||||
for dapp in local_dapps(dapps_path.as_ref()) {
|
||||
pages.insert(
|
||||
dapp.id,
|
||||
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, PageCache::Disabled, signer_address.clone()))
|
||||
);
|
||||
}
|
||||
pages
|
||||
}
|
||||
|
||||
|
||||
fn local_dapps(dapps_path: &Path) -> Vec<LocalDapp> {
|
||||
let files = fs::read_dir(dapps_path);
|
||||
if let Err(e) = files {
|
||||
warn!(target: "dapps", "Unable to load local dapps from: {}. Reason: {:?}", dapps_path, e);
|
||||
warn!(target: "dapps", "Unable to load local dapps from: {}. Reason: {:?}", dapps_path.display(), e);
|
||||
return vec![];
|
||||
}
|
||||
|
||||
@ -59,51 +128,6 @@ fn local_dapps(dapps_path: String) -> Vec<LocalDapp> {
|
||||
}
|
||||
m.ok()
|
||||
})
|
||||
.map(|(name, path)| {
|
||||
// try to get manifest file
|
||||
let info = read_manifest(&name, path.clone());
|
||||
LocalDapp {
|
||||
id: name,
|
||||
path: path,
|
||||
info: info,
|
||||
}
|
||||
})
|
||||
.map(|(name, path)| local_dapp(name, path))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
|
||||
path.push(MANIFEST_FILENAME);
|
||||
|
||||
fs::File::open(path.clone())
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
.and_then(|mut f| {
|
||||
// Reat file
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s).map_err(|e| format!("{:?}", e))?;
|
||||
// Try to deserialize manifest
|
||||
deserialize_manifest(s)
|
||||
})
|
||||
.map(Into::into)
|
||||
.unwrap_or_else(|e| {
|
||||
warn!(target: "dapps", "Cannot read manifest file at: {:?}. Error: {:?}", path, e);
|
||||
|
||||
EndpointInfo {
|
||||
name: name.into(),
|
||||
description: name.into(),
|
||||
version: "0.0.0".into(),
|
||||
author: "?".into(),
|
||||
icon_url: "icon.png".into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn local_endpoints(dapps_path: String, signer_address: Option<(String, u16)>) -> Endpoints {
|
||||
let mut pages = Endpoints::new();
|
||||
for dapp in local_dapps(dapps_path) {
|
||||
pages.insert(
|
||||
dapp.id,
|
||||
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, PageCache::Disabled, signer_address.clone()))
|
||||
);
|
||||
}
|
||||
pages
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
// 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::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use endpoint::{Endpoints, Endpoint};
|
||||
use page::PageEndpoint;
|
||||
@ -43,7 +44,8 @@ pub fn utils() -> Box<Endpoint> {
|
||||
}
|
||||
|
||||
pub fn all_endpoints<F: Fetch>(
|
||||
dapps_path: String,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
signer_address: Option<(String, u16)>,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
remote: Remote,
|
||||
@ -51,6 +53,13 @@ pub fn all_endpoints<F: Fetch>(
|
||||
) -> Endpoints {
|
||||
// fetch fs dapps at first to avoid overwriting builtins
|
||||
let mut pages = fs::local_endpoints(dapps_path, signer_address.clone());
|
||||
for path in extra_dapps {
|
||||
if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), signer_address.clone()) {
|
||||
pages.insert(id, endpoint);
|
||||
} else {
|
||||
warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display());
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE [ToDr] Dapps will be currently embeded on 8180
|
||||
insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(signer_address.clone()));
|
||||
|
@ -88,6 +88,7 @@ mod web;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::net::SocketAddr;
|
||||
use std::collections::HashMap;
|
||||
@ -123,7 +124,8 @@ impl<F> WebProxyTokens for F where F: Fn(String) -> bool + Send + Sync {
|
||||
|
||||
/// Webapps HTTP+RPC server build.
|
||||
pub struct ServerBuilder<T: Fetch = FetchClient> {
|
||||
dapps_path: String,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
handler: Arc<IoHandler>,
|
||||
registrar: Arc<ContractClient>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
@ -141,9 +143,10 @@ impl<T: Fetch> Extendable for ServerBuilder<T> {
|
||||
|
||||
impl ServerBuilder {
|
||||
/// Construct new dapps server
|
||||
pub fn new(dapps_path: String, registrar: Arc<ContractClient>, remote: Remote) -> Self {
|
||||
pub fn new<P: AsRef<Path>>(dapps_path: P, registrar: Arc<ContractClient>, remote: Remote) -> Self {
|
||||
ServerBuilder {
|
||||
dapps_path: dapps_path,
|
||||
dapps_path: dapps_path.as_ref().to_owned(),
|
||||
extra_dapps: vec![],
|
||||
handler: Arc::new(IoHandler::new()),
|
||||
registrar: registrar,
|
||||
sync_status: Arc::new(|| false),
|
||||
@ -160,6 +163,7 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
pub fn fetch<X: Fetch>(self, fetch: X) -> ServerBuilder<X> {
|
||||
ServerBuilder {
|
||||
dapps_path: self.dapps_path,
|
||||
extra_dapps: vec![],
|
||||
handler: self.handler,
|
||||
registrar: self.registrar,
|
||||
sync_status: self.sync_status,
|
||||
@ -188,6 +192,12 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Change extra dapps paths (apart from `dapps_path`)
|
||||
pub fn extra_dapps<P: AsRef<Path>>(mut self, extra_dapps: &[P]) -> Self {
|
||||
self.extra_dapps = extra_dapps.iter().map(|p| p.as_ref().to_owned()).collect();
|
||||
self
|
||||
}
|
||||
|
||||
/// Asynchronously start server with no authentication,
|
||||
/// returns result with `Server` handle on success or an error.
|
||||
pub fn start_unsecured_http(self, addr: &SocketAddr, hosts: Option<Vec<String>>) -> Result<Server, ServerError> {
|
||||
@ -197,6 +207,7 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
NoAuth,
|
||||
self.handler.clone(),
|
||||
self.dapps_path.clone(),
|
||||
self.extra_dapps.clone(),
|
||||
self.signer_address.clone(),
|
||||
self.registrar.clone(),
|
||||
self.sync_status.clone(),
|
||||
@ -215,6 +226,7 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
HttpBasicAuth::single_user(username, password),
|
||||
self.handler.clone(),
|
||||
self.dapps_path.clone(),
|
||||
self.extra_dapps.clone(),
|
||||
self.signer_address.clone(),
|
||||
self.registrar.clone(),
|
||||
self.sync_status.clone(),
|
||||
@ -270,7 +282,8 @@ impl Server {
|
||||
hosts: Option<Vec<String>>,
|
||||
authorization: A,
|
||||
handler: Arc<IoHandler>,
|
||||
dapps_path: String,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
signer_address: Option<(String, u16)>,
|
||||
registrar: Arc<ContractClient>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
@ -287,7 +300,14 @@ impl Server {
|
||||
remote.clone(),
|
||||
fetch.clone(),
|
||||
));
|
||||
let endpoints = Arc::new(apps::all_endpoints(dapps_path, signer_address.clone(), web_proxy_tokens, remote.clone(), fetch.clone()));
|
||||
let endpoints = Arc::new(apps::all_endpoints(
|
||||
dapps_path,
|
||||
extra_dapps,
|
||||
signer_address.clone(),
|
||||
web_proxy_tokens,
|
||||
remote.clone(),
|
||||
fetch.clone(),
|
||||
));
|
||||
let cors_domains = Self::cors_domains(signer_address.clone());
|
||||
|
||||
let special = Arc::new({
|
||||
|
@ -51,7 +51,7 @@ pub fn init_server<F, B>(hosts: Option<Vec<String>>, process: F, remote: Remote)
|
||||
let mut dapps_path = env::temp_dir();
|
||||
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
||||
let server = process(ServerBuilder::new(
|
||||
dapps_path.to_str().unwrap().into(), registrar.clone(), remote,
|
||||
&dapps_path, registrar.clone(), remote,
|
||||
))
|
||||
.signer_address(Some(("127.0.0.1".into(), SIGNER_PORT)))
|
||||
.start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), hosts).unwrap();
|
||||
@ -66,7 +66,7 @@ pub fn serve_with_auth(user: &str, pass: &str) -> Server {
|
||||
let registrar = Arc::new(FakeRegistrar::new());
|
||||
let mut dapps_path = env::temp_dir();
|
||||
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
||||
ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar.clone(), Remote::new_sync())
|
||||
ServerBuilder::new(&dapps_path, registrar.clone(), Remote::new_sync())
|
||||
.signer_address(Some(("127.0.0.1".into(), SIGNER_PORT)))
|
||||
.start_basic_auth_http(&"127.0.0.1:0".parse().unwrap(), None, user, pass).unwrap()
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ usage! {
|
||||
cmd_snapshot: bool,
|
||||
cmd_restore: bool,
|
||||
cmd_ui: bool,
|
||||
cmd_dapp: bool,
|
||||
cmd_tools: bool,
|
||||
cmd_hash: bool,
|
||||
cmd_kill: bool,
|
||||
@ -525,6 +526,7 @@ mod tests {
|
||||
cmd_snapshot: false,
|
||||
cmd_restore: false,
|
||||
cmd_ui: false,
|
||||
cmd_dapp: false,
|
||||
cmd_tools: false,
|
||||
cmd_hash: false,
|
||||
cmd_db: false,
|
||||
|
@ -5,6 +5,7 @@ Parity. Ethereum Client.
|
||||
Usage:
|
||||
parity [options]
|
||||
parity ui [options]
|
||||
parity dapp <path> [options]
|
||||
parity daemon <pid-file> [options]
|
||||
parity account (new | list ) [options]
|
||||
parity account import <path>... [options]
|
||||
|
@ -17,7 +17,7 @@
|
||||
use std::time::Duration;
|
||||
use std::io::Read;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::cmp::max;
|
||||
use cli::{Args, ArgsError};
|
||||
use util::{Hashable, U256, Uint, Bytes, version_data, Secret, Address};
|
||||
@ -335,6 +335,7 @@ impl Configuration {
|
||||
net_settings: self.network_settings(),
|
||||
dapps_conf: dapps_conf,
|
||||
signer_conf: signer_conf,
|
||||
dapp: self.dapp_to_open()?,
|
||||
ui: self.args.cmd_ui,
|
||||
name: self.args.flag_identity,
|
||||
custom_bootnodes: self.args.flag_bootnodes.is_some(),
|
||||
@ -507,10 +508,28 @@ impl Configuration {
|
||||
hosts: self.dapps_hosts(),
|
||||
user: self.args.flag_dapps_user.clone(),
|
||||
pass: self.args.flag_dapps_pass.clone(),
|
||||
dapps_path: self.directories().dapps,
|
||||
dapps_path: PathBuf::from(self.directories().dapps),
|
||||
extra_dapps: if self.args.cmd_dapp {
|
||||
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn dapp_to_open(&self) -> Result<Option<String>, String> {
|
||||
if !self.args.cmd_dapp {
|
||||
return Ok(None);
|
||||
}
|
||||
let path = self.args.arg_path.get(0).map(String::as_str).unwrap_or(".");
|
||||
let path = Path::new(path).canonicalize()
|
||||
.map_err(|e| format!("Invalid path: {}. Error: {:?}", path, e))?;
|
||||
let name = path.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| "Root path is not supported.".to_owned())?;
|
||||
Ok(Some(name.into()))
|
||||
}
|
||||
|
||||
fn gas_pricer_config(&self) -> Result<GasPricerConfig, String> {
|
||||
if let Some(d) = self.args.flag_gasprice.as_ref() {
|
||||
return Ok(GasPricerConfig::Fixed(to_u256(d)?));
|
||||
@ -1030,6 +1049,7 @@ mod tests {
|
||||
dapps_conf: Default::default(),
|
||||
signer_conf: Default::default(),
|
||||
ui: false,
|
||||
dapp: None,
|
||||
name: "".into(),
|
||||
custom_bootnodes: false,
|
||||
fat_db: Default::default(),
|
||||
@ -1224,6 +1244,22 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_dapp_opening() {
|
||||
// given
|
||||
let temp = RandomTempPath::new();
|
||||
let name = temp.file_name().unwrap().to_str().unwrap();
|
||||
create_dir(temp.as_str().to_owned()).unwrap();
|
||||
|
||||
// when
|
||||
let conf0 = parse(&["parity", "dapp", temp.to_str().unwrap()]);
|
||||
|
||||
// then
|
||||
assert_eq!(conf0.dapp_to_open(), Ok(Some(name.into())));
|
||||
let extra_dapps = conf0.dapps_config().extra_dapps;
|
||||
assert_eq!(extra_dapps, vec![temp.to_owned()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_bail_on_empty_line_in_reserved_peers() {
|
||||
let temp = RandomTempPath::new();
|
||||
|
@ -14,6 +14,7 @@
|
||||
// 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::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use io::PanicHandler;
|
||||
use rpc_apis;
|
||||
@ -33,7 +34,8 @@ pub struct Configuration {
|
||||
pub hosts: Option<Vec<String>>,
|
||||
pub user: Option<String>,
|
||||
pub pass: Option<String>,
|
||||
pub dapps_path: String,
|
||||
pub dapps_path: PathBuf,
|
||||
pub extra_dapps: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Default for Configuration {
|
||||
@ -46,7 +48,8 @@ impl Default for Configuration {
|
||||
hosts: Some(Vec::new()),
|
||||
user: None,
|
||||
pass: None,
|
||||
dapps_path: replace_home(&data_dir, "$BASE/dapps"),
|
||||
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
||||
extra_dapps: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -80,7 +83,14 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<We
|
||||
(username.to_owned(), password)
|
||||
});
|
||||
|
||||
Ok(Some(setup_dapps_server(deps, configuration.dapps_path, &addr, configuration.hosts, auth)?))
|
||||
Ok(Some(setup_dapps_server(
|
||||
deps,
|
||||
configuration.dapps_path,
|
||||
configuration.extra_dapps,
|
||||
&addr,
|
||||
configuration.hosts,
|
||||
auth
|
||||
)?))
|
||||
}
|
||||
|
||||
pub use self::server::WebappServer;
|
||||
@ -94,7 +104,8 @@ mod server {
|
||||
pub struct WebappServer;
|
||||
pub fn setup_dapps_server(
|
||||
_deps: Dependencies,
|
||||
_dapps_path: String,
|
||||
_dapps_path: PathBuf,
|
||||
_extra_dapps: Vec<PathBuf>,
|
||||
_url: &SocketAddr,
|
||||
_allowed_hosts: Option<Vec<String>>,
|
||||
_auth: Option<(String, String)>,
|
||||
@ -106,6 +117,7 @@ mod server {
|
||||
#[cfg(feature = "dapps")]
|
||||
mod server {
|
||||
use super::Dependencies;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::net::SocketAddr;
|
||||
use std::io;
|
||||
@ -122,7 +134,8 @@ mod server {
|
||||
|
||||
pub fn setup_dapps_server(
|
||||
deps: Dependencies,
|
||||
dapps_path: String,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
url: &SocketAddr,
|
||||
allowed_hosts: Option<Vec<String>>,
|
||||
auth: Option<(String, String)>,
|
||||
@ -130,7 +143,7 @@ mod server {
|
||||
use ethcore_dapps as dapps;
|
||||
|
||||
let server = dapps::ServerBuilder::new(
|
||||
dapps_path,
|
||||
&dapps_path,
|
||||
Arc::new(Registrar { client: deps.client.clone() }),
|
||||
deps.remote.clone(),
|
||||
);
|
||||
@ -141,6 +154,7 @@ mod server {
|
||||
.fetch(deps.fetch.clone())
|
||||
.sync_status(Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())))
|
||||
.web_proxy_tokens(Arc::new(move |token| signer.is_valid_web_proxy_access_token(&token)))
|
||||
.extra_dapps(&extra_dapps)
|
||||
.signer_address(deps.signer.address());
|
||||
|
||||
let server = rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::UnsafeContext);
|
||||
|
@ -92,6 +92,7 @@ pub struct RunCmd {
|
||||
pub net_settings: NetworkSettings,
|
||||
pub dapps_conf: dapps::Configuration,
|
||||
pub signer_conf: signer::Configuration,
|
||||
pub dapp: Option<String>,
|
||||
pub ui: bool,
|
||||
pub name: String,
|
||||
pub custom_bootnodes: bool,
|
||||
@ -118,6 +119,17 @@ pub fn open_ui(dapps_conf: &dapps::Configuration, signer_conf: &signer::Configur
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn open_dapp(dapps_conf: &dapps::Configuration, dapp: &str) -> Result<(), String> {
|
||||
if !dapps_conf.enabled {
|
||||
return Err("Cannot use DAPP command with Dapps turned off.".into())
|
||||
}
|
||||
|
||||
let url = format!("http://{}:{}/{}/", dapps_conf.interface, dapps_conf.port, dapp);
|
||||
url::open(&url);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<bool, String> {
|
||||
if cmd.ui && cmd.dapps_conf.enabled {
|
||||
// Check if Parity is already running
|
||||
@ -441,6 +453,10 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
open_ui(&cmd.dapps_conf, &cmd.signer_conf)?;
|
||||
}
|
||||
|
||||
if let Some(dapp) = cmd.dapp {
|
||||
open_dapp(&cmd.dapps_conf, &dapp)?;
|
||||
}
|
||||
|
||||
// Handle exit
|
||||
let restart = wait_for_exit(panic_handler, Some(updater), can_restart);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user