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] 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), + } + } +}