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

Loading local Dapps from FS. #1214

Merged
merged 5 commits into from
Jun 3, 2016
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dapps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ parity-dapps-builtins = { git = "https://github.com/ethcore/parity-dapps-builtin
parity-dapps-wallet = { git = "https://github.com/ethcore/parity-dapps-wallet-rs.git", version = "0.5.0", optional = true }
parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.3.0", optional = true }
parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.2.0", optional = true }
mime_guess = { version = "1.6.1" }
clippy = { version = "0.0.69", optional = true}

[build-dependencies]
Expand Down
28 changes: 17 additions & 11 deletions dapps/src/api/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use std::sync::Arc;
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
use endpoint::{Endpoint, Endpoints, EndpointInfo, Handler, EndpointPath};

use api::response::as_json;

pub struct RestApi {
endpoints: Arc<Endpoints>,
}

#[derive(Debug, PartialEq, Serialize)]
struct App {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct App {
pub id: String,
pub name: String,
pub description: String,
Expand All @@ -34,6 +34,19 @@ struct App {
pub icon_url: String,
}

impl App {
fn from_info(id: &str, info: &EndpointInfo) -> Self {
App {
id: id.to_owned(),
name: info.name.to_owned(),
description: info.description.to_owned(),
version: info.version.to_owned(),
author: info.author.to_owned(),
icon_url: info.icon_url.to_owned(),
}
}
}

impl RestApi {
pub fn new(endpoints: Arc<Endpoints>) -> Box<Endpoint> {
Box::new(RestApi {
Expand All @@ -43,14 +56,7 @@ impl RestApi {

fn list_apps(&self) -> Vec<App> {
self.endpoints.iter().filter_map(|(ref k, ref e)| {
e.info().map(|ref info| App {
id: k.to_owned().clone(),
name: info.name.to_owned(),
description: info.description.to_owned(),
version: info.version.to_owned(),
author: info.author.to_owned(),
icon_url: info.icon_url.to_owned(),
})
e.info().map(|ref info| App::from_info(k, info))
}).collect()
}
}
Expand Down
1 change: 1 addition & 0 deletions dapps/src/api/mod.rs.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ mod api;
mod response;

pub use self::api::RestApi;
pub use self::api::App;
116 changes: 116 additions & 0 deletions dapps/src/apps/fs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// 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 serde_json;
use std::io;
use std::io::Read;
use std::fs;
use std::path::PathBuf;
use page::LocalPageEndpoint;
use endpoint::{Endpoints, EndpointInfo};
use api::App;

struct LocalDapp {
id: String,
path: PathBuf,
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 = try!(dir);
let file_type = try!(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()
}

fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
path.push("manifest.json");

fs::File::open(path.clone())
.map_err(|e| format!("{:?}", e))
.and_then(|mut f| {
// Reat file
let mut s = String::new();
try!(f.read_to_string(&mut s).map_err(|e| format!("{:?}", e)));
// Try to deserialize manifest
serde_json::from_str::<App>(&s).map_err(|e| format!("{:?}", e))
})
.map(|app| EndpointInfo {
name: app.name,
description: app.description,
version: app.version,
author: app.author,
icon_url: app.icon_url,
})
.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) -> 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))
);
}
pages
}
13 changes: 8 additions & 5 deletions dapps/src/apps.rs → dapps/src/apps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ use page::PageEndpoint;
use proxypac::ProxyPac;
use parity_dapps::WebApp;

mod fs;

extern crate parity_dapps_status;
extern crate parity_dapps_builtins;


pub const DAPPS_DOMAIN : &'static str = ".parity";
pub const RPC_PATH : &'static str = "rpc";
pub const API_PATH : &'static str = "api";
Expand All @@ -36,22 +37,24 @@ pub fn utils() -> Box<Endpoint> {
Box::new(PageEndpoint::with_prefix(parity_dapps_builtins::App::default(), UTILS_PATH.to_owned()))
}

pub fn all_endpoints() -> Endpoints {
let mut pages = Endpoints::new();
pages.insert("proxy".into(), ProxyPac::boxed());

pub fn all_endpoints(dapps_path: String) -> Endpoints {
// fetch fs dapps at first to avoid overwriting builtins
let mut pages = fs::local_endpoints(dapps_path);
// Home page needs to be safe embed
// because we use Cross-Origin LocalStorage.
// TODO [ToDr] Account naming should be moved to parity.
pages.insert("home".into(), Box::new(
PageEndpoint::new_safe_to_embed(parity_dapps_builtins::App::default())
));
pages.insert("proxy".into(), ProxyPac::boxed());
insert::<parity_dapps_status::App>(&mut pages, "status");
insert::<parity_dapps_status::App>(&mut pages, "parity");

// Optional dapps
wallet_page(&mut pages);
daodapp_page(&mut pages);
makerotc_page(&mut pages);

pages
}

Expand Down
14 changes: 7 additions & 7 deletions dapps/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ pub struct EndpointPath {
pub port: u16,
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct EndpointInfo {
pub name: &'static str,
pub description: &'static str,
pub version: &'static str,
pub author: &'static str,
pub icon_url: &'static str,
pub name: String,
pub description: String,
pub version: String,
pub author: String,
pub icon_url: String,
}

pub trait Endpoint : Send + Sync {
fn info(&self) -> Option<EndpointInfo> { None }
fn info(&self) -> Option<&EndpointInfo> { None }

fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>>;
}
Expand Down
13 changes: 8 additions & 5 deletions dapps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ extern crate jsonrpc_core;
extern crate jsonrpc_http_server;
extern crate parity_dapps;
extern crate ethcore_rpc;
extern crate mime_guess;

mod endpoint;
mod apps;
Expand All @@ -73,6 +74,7 @@ static DAPPS_DOMAIN : &'static str = ".parity";

/// Webapps HTTP+RPC server build.
pub struct ServerBuilder {
dapps_path: String,
handler: Arc<IoHandler>,
}

Expand All @@ -84,22 +86,23 @@ impl Extendable for ServerBuilder {

impl ServerBuilder {
/// Construct new dapps server
pub fn new() -> Self {
pub fn new(dapps_path: String) -> Self {
ServerBuilder {
dapps_path: dapps_path,
handler: Arc::new(IoHandler::new())
}
}

/// Asynchronously start server with no authentication,
/// returns result with `Server` handle on success or an error.
pub fn start_unsecure_http(&self, addr: &SocketAddr) -> Result<Server, ServerError> {
Server::start_http(addr, NoAuth, self.handler.clone())
Server::start_http(addr, NoAuth, self.handler.clone(), self.dapps_path.clone())
}

/// Asynchronously start server with `HTTP Basic Authentication`,
/// return result with `Server` handle on success or an error.
pub fn start_basic_auth_http(&self, addr: &SocketAddr, username: &str, password: &str) -> Result<Server, ServerError> {
Server::start_http(addr, HttpBasicAuth::single_user(username, password), self.handler.clone())
Server::start_http(addr, HttpBasicAuth::single_user(username, password), self.handler.clone(), self.dapps_path.clone())
}
}

Expand All @@ -110,10 +113,10 @@ pub struct Server {
}

impl Server {
fn start_http<A: Authorization + 'static>(addr: &SocketAddr, authorization: A, handler: Arc<IoHandler>) -> Result<Server, ServerError> {
fn start_http<A: Authorization + 'static>(addr: &SocketAddr, authorization: A, handler: Arc<IoHandler>, dapps_path: String) -> Result<Server, ServerError> {
let panic_handler = Arc::new(Mutex::new(None));
let authorization = Arc::new(authorization);
let endpoints = Arc::new(apps::all_endpoints());
let endpoints = Arc::new(apps::all_endpoints(dapps_path));
let special = Arc::new({
let mut special = HashMap::new();
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone()));
Expand Down
Loading