From e3ce5d94e1067b301af7f54fd73e825f01945237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 10:49:00 +0200 Subject: [PATCH 01/14] Adding webapps crate --- Cargo.lock | 88 +++++++++++++++++++++++++ Cargo.toml | 8 ++- cov.sh | 2 + doc.sh | 1 + fmt.sh | 1 + hook.sh | 2 +- parity/main.rs | 2 + test.sh | 1 + webapp/Cargo.toml | 21 ++++++ webapp/src/lib.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 webapp/Cargo.toml create mode 100644 webapp/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 471f35067..9783413d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", + "ethcore-webapp 1.1.0", "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", @@ -107,6 +108,14 @@ dependencies = [ "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "conduit-mime-types" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cookie" version = "0.1.21" @@ -185,6 +194,15 @@ dependencies = [ "regex 0.1.61 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "eth-secp256k1" version = "0.5.4" @@ -291,6 +309,20 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-webapp" +version = "1.1.0" +dependencies = [ + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-rpc 1.1.0", + "ethcore-util 1.1.0", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethjson" version = "0.1.0" @@ -427,6 +459,23 @@ dependencies = [ "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "iron" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.4.11" @@ -461,6 +510,16 @@ dependencies = [ "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-http-server" +version = "4.0.0" +source = "git+https://github.com/tomusdrw/jsonrpc-http-server.git#46bd4e7cf8352e0efc940cf76d3dff99f1a3da15" +dependencies = [ + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.1" @@ -573,6 +632,11 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "modifier" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "net2" version = "0.2.23" @@ -637,6 +701,14 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "plugin" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "primal" version = "0.2.3" @@ -938,6 +1010,14 @@ name = "typeable" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "typemap" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicase" version = "1.4.0" @@ -964,6 +1044,14 @@ name = "unicode-xid" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unsafe-any" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "url" version = "0.2.38" diff --git a/Cargo.toml b/Cargo.toml index f38fe5b10..3fe923db7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,15 +28,19 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +ethcore-webapp = { path = "webapp", optional = true } + [dependencies.hyper] version = "0.8" default-features = false [features] -default = ["rpc"] +default = ["rpc", "webapp"] rpc = ["ethcore-rpc"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev"] +webapp = ["ethcore-webapp"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev", +"ethcore-webapp/dev"] travis-beta = ["ethcore/json-tests"] travis-nightly = ["ethcore/json-tests", "dev"] diff --git a/cov.sh b/cov.sh index d60ef223d..1698d6f36 100755 --- a/cov.sh +++ b/cov.sh @@ -23,6 +23,7 @@ cargo test \ -p ethcore-rpc \ -p parity \ -p ethminer \ + -p ethcore-webapp \ --no-run || exit $? rm -rf target/coverage mkdir -p target/coverage @@ -33,5 +34,6 @@ kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage t kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethsync-* kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_webapp-* kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethminer-* xdg-open target/coverage/index.html diff --git a/doc.sh b/doc.sh index a5e5e2e13..9b0f13817 100755 --- a/doc.sh +++ b/doc.sh @@ -7,5 +7,6 @@ cargo doc --no-deps --verbose \ -p ethcore \ -p ethsync \ -p ethcore-rpc \ + -p ethcore-webapp \ -p parity \ -p ethminer diff --git a/fmt.sh b/fmt.sh index a16d5ac1f..4d835967f 100755 --- a/fmt.sh +++ b/fmt.sh @@ -9,6 +9,7 @@ $RUSTFMT ./json/src/lib.rs $RUSTFMT ./miner/src/lib.rs $RUSTFMT ./parity/main.rs $RUSTFMT ./rpc/src/lib.rs +$RUSTFMT ./webapp/src/lib.rs $RUSTFMT ./sync/src/lib.rs $RUSTFMT ./util/src/lib.rs diff --git a/hook.sh b/hook.sh index 58bff20ab..d98297835 100755 --- a/hook.sh +++ b/hook.sh @@ -7,6 +7,6 @@ echo "set -e" >> $FILE echo "cargo build --release --features dev" >> $FILE # Build tests echo "cargo test --no-run --features dev \\" >> $FILE -echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" >> $FILE +echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethcore-webapp" >> $FILE echo "" >> $FILE chmod +x $FILE diff --git a/parity/main.rs b/parity/main.rs index f5f5cfcd4..2141a5795 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -42,6 +42,8 @@ extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; +#[cfg(feature = "webapp")] +extern crate ethcore_webapp as webapp; use std::io::{BufRead, BufReader}; use std::fs::File; diff --git a/test.sh b/test.sh index 4957fd762..5094158cc 100755 --- a/test.sh +++ b/test.sh @@ -7,6 +7,7 @@ cargo test --features ethcore/json-tests $1 \ -p ethcore \ -p ethsync \ -p ethcore-rpc \ + -p ethcore-webapp \ -p parity \ -p ethminer \ -p bigint diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml new file mode 100644 index 000000000..f6503e163 --- /dev/null +++ b/webapp/Cargo.toml @@ -0,0 +1,21 @@ +[package] +description = "Parity WebApplications crate" +name = "ethcore-webapp" +version = "1.1.0" +license = "GPL-3.0" +authors = ["Ethcore . + +//! Ethcore Webapplications for Parity +#![warn(missing_docs)] +#![cfg_attr(feature="nightly", plugin(clippy))] + +#[macro_use] +extern crate log; +extern crate hyper; +extern crate iron; +extern crate jsonrpc_core; +extern crate jsonrpc_http_server; +extern crate ethcore_rpc as rpc; +extern crate ethcore_util as util; + +use rpc::v1::*; +use std::sync::Arc; +use std::thread; + +use util::panics::PanicHandler; +use iron::request::Url; +use self::jsonrpc_core::{IoHandler, IoDelegate}; +use jsonrpc_http_server::ServerHandler; + +/// Http server. +pub struct WebappServer { + handler: Arc, +} + +impl WebappServer { + /// Construct new http server object + pub fn new() -> Self { + let server = WebappServer { + handler: Arc::new(IoHandler::new()), + }; + // TODO add more + server.add_delegate(Web3Client::new().to_delegate()); + + server + } + + /// Add io delegate. + fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { + self.handler.add_delegate(delegate); + } + + /// Start server asynchronously in new thread and returns panic handler. + pub fn start_http(&self, addr: &str, threads: usize) -> Arc { + let addr = addr.to_owned(); + let panic_handler = PanicHandler::new_in_arc(); + let ph = panic_handler.clone(); + let handler = self.handler.clone(); + + thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { + let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; + let rpc = ServerHandler::new(handler, cors_domain); + let router = Router::new(rpc); + + ph.catch_panic(move || { + hyper::Server::http(addr.as_ref() as &str).unwrap() + .handle_threads(router, threads) + .unwrap(); + }).unwrap() + }).expect("Error while creating jsonrpc http thread"); + + panic_handler + } +} + + +struct Router { + rpc: ServerHandler, + // admin: Page, + // wallet: Page, + // mist: Page, +} + +impl Router { + pub fn new(rpc: ServerHandler) -> Self { + Router { + rpc: rpc, + // admin: Page { app: AdminApp::default() }, + // wallet: Page { app: WalletApp::default() }, + // mist: Page { app: MistApp::default() }, + } + } + + fn extract_url(req: &hyper::server::Request) -> Option { + match req.uri { + hyper::uri::RequestUri::AbsoluteUri(ref url) => { + match Url::from_generic_url(url.clone()) { + Ok(url) => Some(url), + _ => None, + } + }, + hyper::uri::RequestUri::AbsolutePath(ref path) => { + // Attempt to prepend the Host header (mandatory in HTTP/1.1) + let url_string = match req.headers.get::() { + Some(ref host) => { + format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) + }, + None => return None + }; + + match Url::parse(&url_string) { + Ok(url) => Some(url), + _ => None, + } + } + _ => None, + } + } + + fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { + let url = Router::extract_url(&req); + match url { + Some(url) => { + let part = url.path[0].clone(); + let url = url.path[1..].join("/"); + req.uri = hyper::uri::RequestUri::AbsolutePath(url); + (Some(part), req) + }, + None => { + (None, req) + } + } + } +} + +impl hyper::server::Handler for Router { + fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, res: hyper::server::Response<'a>) { + let (path, req) = Router::extract_request_path(req); + match path { + // Some(ref url) if url == "admin" => { + // self.admin.handle(req, res); + // }, + // Some(ref url) if url == "wallet" => { + // self.wallet.handle(req, res); + // }, + // Some(ref url) if url == "mist" => { + // self.mist.handle(req, res); + // }, + _ => self.rpc.handle(req, res), + } + } +} From 5d6ca1498e8c1943b331d2c7fa43e7a6cc8c85da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 11:06:49 +0200 Subject: [PATCH 02/14] CLI options to run webapp server --- parity/main.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 2141a5795..ecd72e0ff 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -120,7 +120,7 @@ Networking Options: string or input to SHA3 operation. API and Console Options: - -j --jsonrpc Enable the JSON-RPC API sever. + -j --jsonrpc Enable the JSON-RPC API server. --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API server, IP should be an interface's IP address, or all (all interfaces) or local [default: local]. @@ -132,6 +132,10 @@ API and Console Options: interface. APIS is a comma-delimited list of API name. Possible name are web3, eth and net. [default: web3,eth,net,personal]. + -w --webap Enable the web applications server (e.g. status page). + --webapp-port PORT Specify the port portion of the WebApps server + [default: 8080]. + Sealing/Mining Options: --usd-per-tx USD Amount of USD to be paid for a basic transaction @@ -216,6 +220,8 @@ struct Args { flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, + flag_webapp: bool, + flag_webapp_port: u16, flag_author: String, flag_usd_per_tx: String, flag_usd_per_eth: String, @@ -295,6 +301,13 @@ fn setup_rpc_server( } Some(server.start_http(url, cors_domain, ::num_cpus::get())) } +#[cfg(feature = "webapp")] +fn setup_webapp_server( + url: &str +) -> Option> { + let server = webapp::WebappServer::new(); + Some(server.start_http(url, ::num_cpus::get())) +} #[cfg(not(feature = "rpc"))] fn setup_rpc_server( @@ -309,6 +322,13 @@ fn setup_rpc_server( None } +#[cfg(not(feature = "webapp"))] +fn setup_webapp_server( + _url: &str +) -> Option> { + None +} + fn print_version() { println!("\ Parity @@ -611,6 +631,15 @@ impl Configuration { } } + if self.args.flag_webapp { + let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); + setup_webapp_server( + &url, + ).map(|handler| { + panic_handler.forward_from(handler.deref()); + }); + } + // Register IO handler let io_handler = Arc::new(ClientIoHandler { client: service.client(), From ad37b7fd2a5b3297904aa4d90974390d01e196fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:10:26 +0200 Subject: [PATCH 03/14] Adding webapps router --- Cargo.lock | 15 +++++ parity/main.rs | 5 +- webapp/Cargo.toml | 4 ++ webapp/src/apps.rs | 37 ++++++++++++ webapp/src/lib.rs | 118 ++++++--------------------------------- webapp/src/page/mod.rs | 67 ++++++++++++++++++++++ webapp/src/router/mod.rs | 89 +++++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 102 deletions(-) create mode 100644 webapp/src/apps.rs create mode 100644 webapp/src/page/mod.rs create mode 100644 webapp/src/router/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 9783413d4..62093c293 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,8 @@ dependencies = [ "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", + "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] [[package]] @@ -701,6 +703,19 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-wallet" +version = "0.1.0" +source = "git+https://github.com/tomusdrw/parity-wallet.git#9b0253f5cb88b31417450ca8be708cab2e437dfc" +dependencies = [ + "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", +] + +[[package]] +name = "parity-webapp" +version = "0.1.0" +source = "git+https://github.com/tomusdrw/parity-webapp.git#a24297256bae0ae0712c6478cd1ad681828b3800" + [[package]] name = "plugin" version = "0.2.6" diff --git a/parity/main.rs b/parity/main.rs index ecd72e0ff..b8498d520 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -132,7 +132,7 @@ API and Console Options: interface. APIS is a comma-delimited list of API name. Possible name are web3, eth and net. [default: web3,eth,net,personal]. - -w --webap Enable the web applications server (e.g. status page). + -w --webapp Enable the web applications server (e.g. status page). --webapp-port PORT Specify the port portion of the WebApps server [default: 8080]. @@ -305,7 +305,10 @@ fn setup_rpc_server( fn setup_webapp_server( url: &str ) -> Option> { + use rpc::v1::*; + let server = webapp::WebappServer::new(); + server.add_delegate(Web3Client::new().to_delegate()); Some(server.start_http(url, ::num_cpus::get())) } diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index f6503e163..377b0b556 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -15,7 +15,11 @@ hyper = { version = "0.8", default-features = false } iron = { version = "0.3" } ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } +parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } +# List of apps +parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true } clippy = { version = "0.0.61", optional = true} [features] +default = ["parity-wallet"] dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"] diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs new file mode 100644 index 000000000..6a43decab --- /dev/null +++ b/webapp/src/apps.rs @@ -0,0 +1,37 @@ +// 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 . + +use std::collections::HashMap; +use page::{Page, PageHandler}; + +extern crate parity_wallet; + +pub type Pages = HashMap>; + +pub fn all_pages() -> Pages { + let mut pages = Pages::new(); + wallet_page(&mut pages); + pages +} + +#[cfg(feature="parity-wallet")] +fn wallet_page(pages: &mut Pages) { + pages.insert("wallet".to_owned(), Box::new(PageHandler { app: parity_wallet::App::default() })); +} + +#[cfg(not(feature="parity-wallet"))] +fn wallet_page(_pages: &mut Pages) {} + diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 8fd20fdeb..7a3620e1a 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -26,16 +26,17 @@ extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate ethcore_rpc as rpc; extern crate ethcore_util as util; +extern crate parity_webapp; -use rpc::v1::*; use std::sync::Arc; -use std::thread; - use util::panics::PanicHandler; -use iron::request::Url; use self::jsonrpc_core::{IoHandler, IoDelegate}; use jsonrpc_http_server::ServerHandler; +mod apps; +mod page; +mod router; + /// Http server. pub struct WebappServer { handler: Arc, @@ -44,117 +45,32 @@ pub struct WebappServer { impl WebappServer { /// Construct new http server object pub fn new() -> Self { - let server = WebappServer { + WebappServer { handler: Arc::new(IoHandler::new()), - }; - // TODO add more - server.add_delegate(Web3Client::new().to_delegate()); - - server + } } /// Add io delegate. - fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { + pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { self.handler.add_delegate(delegate); } - /// Start server asynchronously in new thread and returns panic handler. + /// Start server asynchronously and returns panic handler. pub fn start_http(&self, addr: &str, threads: usize) -> Arc { let addr = addr.to_owned(); let panic_handler = PanicHandler::new_in_arc(); - let ph = panic_handler.clone(); let handler = self.handler.clone(); - thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { - let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; - let rpc = ServerHandler::new(handler, cors_domain); - let router = Router::new(rpc); + let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; + let rpc = ServerHandler::new(handler, cors_domain); + let router = router::Router::new(rpc, apps::all_pages()); - ph.catch_panic(move || { - hyper::Server::http(addr.as_ref() as &str).unwrap() - .handle_threads(router, threads) - .unwrap(); - }).unwrap() - }).expect("Error while creating jsonrpc http thread"); + panic_handler.catch_panic(move || { + hyper::Server::http(addr.as_ref() as &str).unwrap() + .handle_threads(router, threads) + .unwrap(); + }).unwrap(); panic_handler } } - - -struct Router { - rpc: ServerHandler, - // admin: Page, - // wallet: Page, - // mist: Page, -} - -impl Router { - pub fn new(rpc: ServerHandler) -> Self { - Router { - rpc: rpc, - // admin: Page { app: AdminApp::default() }, - // wallet: Page { app: WalletApp::default() }, - // mist: Page { app: MistApp::default() }, - } - } - - fn extract_url(req: &hyper::server::Request) -> Option { - match req.uri { - hyper::uri::RequestUri::AbsoluteUri(ref url) => { - match Url::from_generic_url(url.clone()) { - Ok(url) => Some(url), - _ => None, - } - }, - hyper::uri::RequestUri::AbsolutePath(ref path) => { - // Attempt to prepend the Host header (mandatory in HTTP/1.1) - let url_string = match req.headers.get::() { - Some(ref host) => { - format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) - }, - None => return None - }; - - match Url::parse(&url_string) { - Ok(url) => Some(url), - _ => None, - } - } - _ => None, - } - } - - fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { - let url = Router::extract_url(&req); - match url { - Some(url) => { - let part = url.path[0].clone(); - let url = url.path[1..].join("/"); - req.uri = hyper::uri::RequestUri::AbsolutePath(url); - (Some(part), req) - }, - None => { - (None, req) - } - } - } -} - -impl hyper::server::Handler for Router { - fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, res: hyper::server::Response<'a>) { - let (path, req) = Router::extract_request_path(req); - match path { - // Some(ref url) if url == "admin" => { - // self.admin.handle(req, res); - // }, - // Some(ref url) if url == "wallet" => { - // self.wallet.handle(req, res); - // }, - // Some(ref url) if url == "mist" => { - // self.mist.handle(req, res); - // }, - _ => self.rpc.handle(req, res), - } - } -} diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs new file mode 100644 index 000000000..94a25769e --- /dev/null +++ b/webapp/src/page/mod.rs @@ -0,0 +1,67 @@ +// 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 . + +use std::io::Write; +use hyper::uri::RequestUri; +use hyper::server; +use hyper::header; +use hyper::status::StatusCode; +use parity_webapp::WebApp; + +pub trait Page : Send + Sync { + fn serve_file(&self, mut path: &str, mut res: server::Response); +} + +pub struct PageHandler { + pub app: T +} + +impl Page for PageHandler { + fn serve_file(&self, mut path: &str, mut res: server::Response) { + // Support index file + if path == "" { + path = "index.html" + } + let file = self.app.file(path); + if let Some(f) = file { + *res.status_mut() = StatusCode::Ok; + res.headers_mut().set(header::ContentType(f.content_type.parse().unwrap())); + + let _ = match res.start() { + Ok(mut raw_res) => { + for chunk in f.content.chunks(1024 * 20) { + let _ = raw_res.write(chunk); + } + raw_res.end() + }, + Err(_) => { + println!("Error while writing response."); + Ok(()) + } + }; + } + } +} + +impl server::Handler for Page { + fn handle(&self, req: server::Request, mut res: server::Response) { + *res.status_mut() = StatusCode::NotFound; + + if let RequestUri::AbsolutePath(ref path) = req.uri { + self.serve_file(path, res); + } + } +} diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs new file mode 100644 index 000000000..4ed32fab9 --- /dev/null +++ b/webapp/src/router/mod.rs @@ -0,0 +1,89 @@ +// 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 . + +//! Router implementation + +use hyper; +use apps::Pages; +use iron::request::Url; +use jsonrpc_http_server::ServerHandler; + +pub struct Router { + rpc: ServerHandler, + pages: Pages, +} + +impl hyper::server::Handler for Router { + fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, res: hyper::server::Response<'a>) { + let (path, req) = Router::extract_request_path(req); + match path { + Some(ref url) if self.pages.contains_key(url) => { + self.pages.get(url).unwrap().handle(req, res); + } + _ => self.rpc.handle(req, res), + } + } +} + +impl Router { + pub fn new(rpc: ServerHandler, pages: Pages) -> Self { + Router { + rpc: rpc, + pages: pages, + } + } + + fn extract_url(req: &hyper::server::Request) -> Option { + match req.uri { + hyper::uri::RequestUri::AbsoluteUri(ref url) => { + match Url::from_generic_url(url.clone()) { + Ok(url) => Some(url), + _ => None, + } + }, + hyper::uri::RequestUri::AbsolutePath(ref path) => { + // Attempt to prepend the Host header (mandatory in HTTP/1.1) + let url_string = match req.headers.get::() { + Some(ref host) => { + format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) + }, + None => return None + }; + + match Url::parse(&url_string) { + Ok(url) => Some(url), + _ => None, + } + } + _ => None, + } + } + + fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { + let url = Router::extract_url(&req); + match url { + Some(url) => { + let part = url.path[0].clone(); + let url = url.path[1..].join("/"); + req.uri = hyper::uri::RequestUri::AbsolutePath(url); + (Some(part), req) + }, + None => { + (None, req) + } + } + } +} From da05aa51fefe34c4356d4e26fa9021d6b3f83f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:12:02 +0200 Subject: [PATCH 04/14] Adding all APIs to webapp rpc server --- parity/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/parity/main.rs b/parity/main.rs index b8498d520..0e82ea4d3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -303,12 +303,20 @@ fn setup_rpc_server( } #[cfg(feature = "webapp")] fn setup_webapp_server( + client: Arc, + sync: Arc, + secret_store: Arc, + miner: Arc, url: &str ) -> Option> { use rpc::v1::*; let server = webapp::WebappServer::new(); server.add_delegate(Web3Client::new().to_delegate()); + server.add_delegate(NetClient::new(&sync).to_delegate()); + server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); + server.add_delegate(PersonalClient::new(&secret_store).to_delegate()); Some(server.start_http(url, ::num_cpus::get())) } @@ -327,6 +335,10 @@ fn setup_rpc_server( #[cfg(not(feature = "webapp"))] fn setup_webapp_server( + _client: Arc, + _sync: Arc, + _secret_store: Arc, + _miner: Arc, _url: &str ) -> Option> { None @@ -637,6 +649,10 @@ impl Configuration { if self.args.flag_webapp { let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); setup_webapp_server( + service.client(), + sync.clone(), + account_service.clone(), + miner.clone(), &url, ).map(|handler| { panic_handler.forward_from(handler.deref()); From 1e9e0c32faf5987717a34a875fd778218592860e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:13:06 +0200 Subject: [PATCH 05/14] Disabling webapp server by default --- Cargo.toml | 2 +- parity/main.rs | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3fe923db7..276159f84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ version = "0.8" default-features = false [features] -default = ["rpc", "webapp"] +default = ["rpc"] rpc = ["ethcore-rpc"] webapp = ["ethcore-webapp"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev", diff --git a/parity/main.rs b/parity/main.rs index 0e82ea4d3..088a61550 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -281,7 +281,7 @@ fn setup_rpc_server( url: &str, cors_domain: &str, apis: Vec<&str> -) -> Option> { +) -> Arc { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -299,7 +299,7 @@ fn setup_rpc_server( } } } - Some(server.start_http(url, cors_domain, ::num_cpus::get())) + server.start_http(url, cors_domain, ::num_cpus::get()) } #[cfg(feature = "webapp")] fn setup_webapp_server( @@ -308,7 +308,7 @@ fn setup_webapp_server( secret_store: Arc, miner: Arc, url: &str -) -> Option> { +) -> Arc { use rpc::v1::*; let server = webapp::WebappServer::new(); @@ -317,7 +317,7 @@ fn setup_webapp_server( server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); server.add_delegate(PersonalClient::new(&secret_store).to_delegate()); - Some(server.start_http(url, ::num_cpus::get())) + server.start_http(url, ::num_cpus::get()) } #[cfg(not(feature = "rpc"))] @@ -329,8 +329,8 @@ fn setup_rpc_server( _url: &str, _cors_domain: &str, _apis: Vec<&str> -) -> Option> { - None +) -> Arc { + die!("Your Parity version has been compiled without JSON-RPC support.") } #[cfg(not(feature = "webapp"))] @@ -340,8 +340,8 @@ fn setup_webapp_server( _secret_store: Arc, _miner: Arc, _url: &str -) -> Option> { - None +) -> Arc { + die!("Your Parity version has been compiled without WebApps support.") } fn print_version() { @@ -632,7 +632,7 @@ impl Configuration { let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - let server_handler = setup_rpc_server( + let handler = setup_rpc_server( service.client(), sync.clone(), account_service.clone(), @@ -641,22 +641,19 @@ impl Configuration { cors, apis.split(',').collect() ); - if let Some(handler) = server_handler { - panic_handler.forward_from(handler.deref()); - } + panic_handler.forward_from(handler.deref()); } if self.args.flag_webapp { let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); - setup_webapp_server( + let handler = setup_webapp_server( service.client(), sync.clone(), account_service.clone(), miner.clone(), &url, - ).map(|handler| { - panic_handler.forward_from(handler.deref()); - }); + ); + panic_handler.forward_from(handler.deref()); } // Register IO handler From 91f1f4c174ab3216f4ec77bdfb64d47c2eff9611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:20:35 +0200 Subject: [PATCH 06/14] Changing default setup to be safer for now --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 088a61550..c047e5eb3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -645,7 +645,7 @@ impl Configuration { } if self.args.flag_webapp { - let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); + let url = format!("127.0.0.1:{}", self.args.flag_webapp_port); let handler = setup_webapp_server( service.client(), sync.clone(), From 6279237c86abe721da278f189da7c32d5ae48f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 13:15:59 +0200 Subject: [PATCH 07/14] Adding documentation --- webapp/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 6150a2b39..104a8ce45 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -83,7 +83,9 @@ impl Drop for Listening { /// Webapp Server startup error #[derive(Debug)] pub enum WebappServerError { + /// Wrapped `std::io::Error` IoError(std::io::Error), + /// Other `hyper` error Other(hyper::error::Error), } From ed633bd0b701412129f471c5fd433f83cff0dc8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 15:14:39 +0200 Subject: [PATCH 08/14] Adding StatusPage and main page support --- Cargo.lock | 9 +++++++++ webapp/Cargo.toml | 1 + webapp/src/apps.rs | 10 +++++++--- webapp/src/lib.rs | 2 +- webapp/src/router/mod.rs | 19 +++++++++++++++---- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af361da49..feda5db77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,7 @@ dependencies = [ "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] @@ -693,6 +694,14 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-status" +version = "0.1.1" +source = "git+https://github.com/tomusdrw/parity-status.git#31cdfd631af970b58c4ddb4e7d7e927af2e07ce3" +dependencies = [ + "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", +] + [[package]] name = "parity-wallet" version = "0.1.0" diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index 377b0b556..b377bb991 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -17,6 +17,7 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } # List of apps +parity-status = { git = "https://github.com/tomusdrw/parity-status.git" } parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true } clippy = { version = "0.0.61", optional = true} diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs index 6a43decab..364186d04 100644 --- a/webapp/src/apps.rs +++ b/webapp/src/apps.rs @@ -17,21 +17,25 @@ use std::collections::HashMap; use page::{Page, PageHandler}; +extern crate parity_status; extern crate parity_wallet; pub type Pages = HashMap>; +pub fn main_page() -> Box { + Box::new(PageHandler { app: parity_status::App::default() }) +} + pub fn all_pages() -> Pages { let mut pages = Pages::new(); wallet_page(&mut pages); pages } -#[cfg(feature="parity-wallet")] +#[cfg(feature = "parity-wallet")] fn wallet_page(pages: &mut Pages) { pages.insert("wallet".to_owned(), Box::new(PageHandler { app: parity_wallet::App::default() })); } -#[cfg(not(feature="parity-wallet"))] +#[cfg(not(feature = "parity-wallet"))] fn wallet_page(_pages: &mut Pages) {} - diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 104a8ce45..d8e524be8 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -60,7 +60,7 @@ impl WebappServer { let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; let rpc = ServerHandler::new(handler, cors_domain); - let router = router::Router::new(rpc, apps::all_pages()); + let router = router::Router::new(rpc, apps::main_page(), apps::all_pages()); try!(hyper::Server::http(addr.as_ref() as &str)) .handle_threads(router, threads) diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 4ed32fab9..fad8593b9 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -17,12 +17,14 @@ //! Router implementation use hyper; +use page::Page; use apps::Pages; use iron::request::Url; use jsonrpc_http_server::ServerHandler; pub struct Router { rpc: ServerHandler, + main_page: Box, pages: Pages, } @@ -33,15 +35,19 @@ impl hyper::server::Handler for Router { Some(ref url) if self.pages.contains_key(url) => { self.pages.get(url).unwrap().handle(req, res); } - _ => self.rpc.handle(req, res), + _ if req.method == hyper::method::Method::Post => { + self.rpc.handle(req, res) + }, + _ => self.main_page.handle(req, res), } } } impl Router { - pub fn new(rpc: ServerHandler, pages: Pages) -> Self { + pub fn new(rpc: ServerHandler, main_page: Box, pages: Pages) -> Self { Router { rpc: rpc, + main_page: main_page, pages: pages, } } @@ -75,13 +81,18 @@ impl Router { fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { let url = Router::extract_url(&req); match url { - Some(url) => { + Some(ref url) if url.path.len() > 1 => { let part = url.path[0].clone(); let url = url.path[1..].join("/"); req.uri = hyper::uri::RequestUri::AbsolutePath(url); (Some(part), req) }, - None => { + Some(url) => { + let url = url.path.join("/"); + req.uri = hyper::uri::RequestUri::AbsolutePath(url); + (None, req) + }, + _ => { (None, req) } } From 4569c251275e8858bf56c109c5be68d24be95260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 15:59:45 +0200 Subject: [PATCH 09/14] Specifying webapp interface --- parity/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 062d62244..945e0bdad 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -136,6 +136,9 @@ API and Console Options: -w --webapp Enable the web applications server (e.g. status page). --webapp-port PORT Specify the port portion of the WebApps server [default: 8080]. + --webapp-interface IP Specify the hostname portion of the WebApps + server, IP should be an interface's IP address, or + all (all interfaces) or local [default: local]. Sealing/Mining Options: @@ -223,6 +226,7 @@ struct Args { flag_jsonrpc_apis: String, flag_webapp: bool, flag_webapp_port: u16, + flag_webapp_interface: String, flag_author: String, flag_usd_per_tx: String, flag_usd_per_eth: String, @@ -662,7 +666,14 @@ impl Configuration { }; let webapp_server = if self.args.flag_webapp { - let url = format!("127.0.0.1:{}", self.args.flag_webapp_port); + let url = format!("{}:{}", + match self.args.flag_webapp_interface.as_str() { + "all" => "0.0.0.0", + "local" => "127.0.0.1", + x => x, + }, + self.args.flag_webapp_port + ); Some(setup_webapp_server( service.client(), sync.clone(), From b7c790d7410ccfebaece73e4f1b29f7c7d43d66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 16:22:02 +0200 Subject: [PATCH 10/14] Disabling rpc until we switch to async hyper --- Cargo.lock | 2 +- parity/main.rs | 6 +++--- webapp/Cargo.toml | 2 +- webapp/src/router/mod.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4c4f5970..f6ce8941d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,7 +319,7 @@ dependencies = [ "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", + "jsonrpc-http-server 5.0.0 (git+https://github.com/debris/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", diff --git a/parity/main.rs b/parity/main.rs index 8dcd0c067..7ea8282f3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -67,7 +67,7 @@ use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; #[cfg(feature = "rpc")] use rpc::Server as RpcServer; -use webapp::WebappServer; +use webapp::Listening as WebappServer; mod price_info; @@ -324,7 +324,7 @@ fn setup_webapp_server( ) -> WebappServer { use rpc::v1::*; - let server = WebappServer::new(); + let server = webapp::WebappServer::new(); server.add_delegate(Web3Client::new().to_delegate()); server.add_delegate(NetClient::new(&sync).to_delegate()); server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); @@ -334,7 +334,7 @@ fn setup_webapp_server( match start_result { Err(webapp::WebappServerError::IoError(err)) => die_with_io_error(err), Err(e) => die!("{:?}", e), - Ok(handle) => Box::new(handle), + Ok(handle) => handle, } } diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index b377bb991..28df2b8f8 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore { - self.rpc.handle(req, res) + // self.rpc.handle(req, res) }, _ => self.main_page.handle(req, res), } From 9bd41761fcd8750d64029b757661ce7a5734b590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 16:30:49 +0200 Subject: [PATCH 11/14] Reverting back to old-hyper version of rpc --- Cargo.lock | 12 +++++++++++- parity/main.rs | 1 + webapp/Cargo.toml | 2 +- webapp/src/router/mod.rs | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6ce8941d..d702bd4fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,7 +319,7 @@ dependencies = [ "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 5.0.0 (git+https://github.com/debris/jsonrpc-http-server.git)", + "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", @@ -524,6 +524,16 @@ dependencies = [ "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-http-server" +version = "4.0.0" +source = "git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper#46bd4e7cf8352e0efc940cf76d3dff99f1a3da15" +dependencies = [ + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "jsonrpc-http-server" version = "5.0.0" diff --git a/parity/main.rs b/parity/main.rs index 7ea8282f3..b9f95eee3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -67,6 +67,7 @@ use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; #[cfg(feature = "rpc")] use rpc::Server as RpcServer; +#[cfg(feature = "webapp")] use webapp::Listening as WebappServer; mod price_info; diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index 28df2b8f8..b63c04bf5 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore { - // self.rpc.handle(req, res) + self.rpc.handle(req, res) }, _ => self.main_page.handle(req, res), } From 1852f1b462657995157a1598a72346ff31fe2ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 18:22:53 +0200 Subject: [PATCH 12/14] REST-API PoC --- webapp/src/router/api.rs | 53 ++++++++++++++++++++++++++++++++++++++++ webapp/src/router/mod.rs | 13 ++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 webapp/src/router/api.rs diff --git a/webapp/src/router/api.rs b/webapp/src/router/api.rs new file mode 100644 index 000000000..1044af407 --- /dev/null +++ b/webapp/src/router/api.rs @@ -0,0 +1,53 @@ +// 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 . + +//! Simple REST API + +use std::sync::Arc; +use hyper; +use hyper::status::StatusCode; +use hyper::header; +use hyper::uri::RequestUri::AbsolutePath as Path; +use apps::Pages; + +pub struct RestApi { + pub pages: Arc, +} + +impl RestApi { + fn list_pages(&self) -> String { + let mut s = "[".to_owned(); + for name in self.pages.keys() { + s.push_str(&format!("\"{}\",", name)); + } + s.push_str("\"rpc\""); + s.push_str("]"); + s + } +} + +impl hyper::server::Handler for RestApi { + fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, mut res: hyper::server::Response<'a>) { + match req.uri { + Path(ref path) if path == "apps" => { + *res.status_mut() = StatusCode::Ok; + res.headers_mut().set(header::ContentType("application/json".parse().unwrap())); + let _ = res.send(self.list_pages().as_bytes()); + }, + _ => () + } + } +} diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index fad8593b9..f0399aba8 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -16,16 +16,20 @@ //! Router implementation +use std::sync::Arc; use hyper; use page::Page; use apps::Pages; use iron::request::Url; use jsonrpc_http_server::ServerHandler; +mod api; + pub struct Router { rpc: ServerHandler, + api: api::RestApi, main_page: Box, - pages: Pages, + pages: Arc, } impl hyper::server::Handler for Router { @@ -34,7 +38,10 @@ impl hyper::server::Handler for Router { match path { Some(ref url) if self.pages.contains_key(url) => { self.pages.get(url).unwrap().handle(req, res); - } + }, + Some(ref url) if url == "api" => { + self.api.handle(req, res); + }, _ if req.method == hyper::method::Method::Post => { self.rpc.handle(req, res) }, @@ -45,8 +52,10 @@ impl hyper::server::Handler for Router { impl Router { pub fn new(rpc: ServerHandler, main_page: Box, pages: Pages) -> Self { + let pages = Arc::new(pages); Router { rpc: rpc, + api: api::RestApi { pages: pages.clone() }, main_page: main_page, pages: pages, } From 6395095659e88a26c3bc2c58e6d80e44b18a36be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 18:42:51 +0200 Subject: [PATCH 13/14] Updating version of parity-status --- Cargo.lock | 6 +++--- webapp/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d702bd4fc..210b23666 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,7 +321,7 @@ dependencies = [ "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", + "parity-status 0.1.4 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] @@ -727,8 +727,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-status" -version = "0.1.1" -source = "git+https://github.com/tomusdrw/parity-status.git#31cdfd631af970b58c4ddb4e7d7e927af2e07ce3" +version = "0.1.4" +source = "git+https://github.com/tomusdrw/parity-status.git#380d13c8aafc3847a731968a6532edb09c78f2cf" dependencies = [ "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index b63c04bf5..59452f32d 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -17,7 +17,7 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } # List of apps -parity-status = { git = "https://github.com/tomusdrw/parity-status.git" } +parity-status = { git = "https://github.com/tomusdrw/parity-status.git", version = "0.1.4" } parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true } clippy = { version = "0.0.61", optional = true} From f129126a8216a1804e697c6467500fa9db516dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 8 Apr 2016 10:13:42 +0200 Subject: [PATCH 14/14] Adding couple of missing commas --- webapp/src/lib.rs | 2 +- webapp/src/page/mod.rs | 4 ++-- webapp/src/router/api.rs | 2 +- webapp/src/router/mod.rs | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index d8e524be8..35ebb4a44 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -93,7 +93,7 @@ impl From for WebappServerError { fn from(err: hyper::error::Error) -> Self { match err { hyper::error::Error::Io(e) => WebappServerError::IoError(e), - e => WebappServerError::Other(e) + e => WebappServerError::Other(e), } } } diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs index 94a25769e..ce7b32947 100644 --- a/webapp/src/page/mod.rs +++ b/webapp/src/page/mod.rs @@ -26,7 +26,7 @@ pub trait Page : Send + Sync { } pub struct PageHandler { - pub app: T + pub app: T, } impl Page for PageHandler { @@ -50,7 +50,7 @@ impl Page for PageHandler { Err(_) => { println!("Error while writing response."); Ok(()) - } + }, }; } } diff --git a/webapp/src/router/api.rs b/webapp/src/router/api.rs index 1044af407..046b75957 100644 --- a/webapp/src/router/api.rs +++ b/webapp/src/router/api.rs @@ -47,7 +47,7 @@ impl hyper::server::Handler for RestApi { res.headers_mut().set(header::ContentType("application/json".parse().unwrap())); let _ = res.send(self.list_pages().as_bytes()); }, - _ => () + _ => (), } } } diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index f0399aba8..bd0d2ff18 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -75,14 +75,14 @@ impl Router { Some(ref host) => { format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) }, - None => return None + None => return None, }; match Url::parse(&url_string) { Ok(url) => Some(url), _ => None, } - } + }, _ => None, } } @@ -103,7 +103,7 @@ impl Router { }, _ => { (None, req) - } + }, } } }