Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Opening local dapp #4041

Merged
merged 3 commits into from
Jan 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 70 additions & 46 deletions dapps/src/apps/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -28,49 +28,8 @@ struct LocalDapp {
info: EndpointInfo,
}

fn local_dapps(dapps_path: String) -> Vec<LocalDapp> {
let files = fs::read_dir(dapps_path.as_str());
if let Err(e) = files {
warn!(target: "dapps", "Unable to load local dapps from: {}. Reason: {:?}", dapps_path, e);
return vec![];
}

let files = files.expect("Check is done earlier");
files.map(|dir| {
let entry = dir?;
let file_type = entry.file_type()?;

// skip files
if file_type.is_file() {
return Err(io::Error::new(io::ErrorKind::NotFound, "Not a file"));
}

// take directory name and path
entry.file_name().into_string()
.map(|name| (name, entry.path()))
.map_err(|e| {
info!(target: "dapps", "Unable to load dapp: {:?}. Reason: {:?}", entry.path(), e);
io::Error::new(io::ErrorKind::NotFound, "Invalid name")
})
})
.filter_map(|m| {
if let Err(ref e) = m {
debug!(target: "dapps", "Ignoring local dapp: {:?}", e);
}
m.ok()
})
.map(|(name, path)| {
// try to get manifest file
let info = read_manifest(&name, path.clone());
LocalDapp {
id: name,
path: path,
info: info,
}
})
.collect()
}

/// 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);

Expand All @@ -97,13 +56,78 @@ fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
})
}

pub fn local_endpoints(dapps_path: String, signer_address: Option<(String, u16)>) -> Endpoints {
/// 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>)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to have short doc comments for non-trivial functions, even if they're non-visible outside their crates.

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) {
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.display(), e);
return vec![];
}

let files = files.expect("Check is done earlier");
files.map(|dir| {
let entry = dir?;
let file_type = entry.file_type()?;

// skip files
if file_type.is_file() {
return Err(io::Error::new(io::ErrorKind::NotFound, "Not a file"));
}

// take directory name and path
entry.file_name().into_string()
.map(|name| (name, entry.path()))
.map_err(|e| {
info!(target: "dapps", "Unable to load dapp: {:?}. Reason: {:?}", entry.path(), e);
io::Error::new(io::ErrorKind::NotFound, "Invalid name")
})
})
.filter_map(|m| {
if let Err(ref e) = m {
debug!(target: "dapps", "Ignoring local dapp: {:?}", e);
}
m.ok()
})
.map(|(name, path)| local_dapp(name, path))
.collect()
}
11 changes: 10 additions & 1 deletion dapps/src/apps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -43,14 +44,22 @@ 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,
fetch: F,
) -> 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()));
Expand Down
30 changes: 25 additions & 5 deletions dapps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>,
Expand All @@ -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),
Expand All @@ -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,
Expand Down Expand Up @@ -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> {
Expand All @@ -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(),
Expand All @@ -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(),
Expand Down Expand Up @@ -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>,
Expand All @@ -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({
Expand Down
4 changes: 2 additions & 2 deletions dapps/src/tests/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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()
}
Expand Down
2 changes: 2 additions & 0 deletions parity/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
13 changes: 7 additions & 6 deletions parity/cli/usage.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -36,15 +37,15 @@ Operating Options:
(default: {flag_mode_alarm}).
--auto-update SET Set a releases set to automatically update and
install.
all - All updates in the our release track.
all - All updates in the our release track.
critical - Only consensus/security updates.
none - No updates will be auto-installed.
none - No updates will be auto-installed.
(default: {flag_auto_update}).
--release-track TRACK Set which release track we should use for updates.
stable - Stable releases.
beta - Beta releases.
stable - Stable releases.
beta - Beta releases.
nightly - Nightly releases (unstable).
testing - Testing releases (do not use).
testing - Testing releases (do not use).
current - Whatever track this executable was
released on (default: {flag_release_track}).
--no-download Normally new releases will be downloaded ready for
Expand Down Expand Up @@ -362,7 +363,7 @@ Legacy Options:
--cache MB Equivalent to --cache-size MB.

Internal Options:
--can-restart Executable will auto-restart if exiting with 69.
--can-restart Executable will auto-restart if exiting with 69.

Miscellaneous Options:
-c --config CONFIG Specify a filename containing a configuration file.
Expand Down
Loading