From 72b1b41748938ab4c6f2303d1dc1c88af4922b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 13 May 2016 18:40:20 +0200 Subject: [PATCH] Supporting topbar injection --- Cargo.lock | 21 +++++++++++----- webapp/Cargo.toml | 5 ++-- webapp/src/apps.rs | 12 ++++++++- webapp/src/lib.rs | 17 +++++++------ webapp/src/page/mod.rs | 17 +++++++++++-- webapp/src/proxypac.rs | 2 +- webapp/src/router/mod.rs | 53 +++++++++++++++++++++++----------------- 7 files changed, 85 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b3fbd44a..d87c4fdbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,8 +358,9 @@ dependencies = [ "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-status 0.3.7 (git+https://github.com/ethcore/parity-status.git)", - "parity-wallet 0.2.0 (git+https://github.com/ethcore/parity-wallet.git)", + "parity-idmanager 0.1.1 (git+https://github.com/ethcore/parity-idmanager-rs.git)", + "parity-status 0.4.0 (git+https://github.com/ethcore/parity-status.git)", + "parity-wallet 0.3.0 (git+https://github.com/ethcore/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", "url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -820,18 +821,26 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-idmanager" +version = "0.1.1" +source = "git+https://github.com/ethcore/parity-idmanager-rs.git#5adf8da35e3d3605a6109c53715b867071a0cf57" +dependencies = [ + "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", +] + [[package]] name = "parity-status" -version = "0.3.7" -source = "git+https://github.com/ethcore/parity-status.git#b0ae32a7fe2f843e4e22dc38903fd2c3e7fb0763" +version = "0.4.0" +source = "git+https://github.com/ethcore/parity-status.git#d104bcdbcc84aa8b51e6c194924893e83690b5ce" dependencies = [ "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", ] [[package]] name = "parity-wallet" -version = "0.2.0" -source = "git+https://github.com/ethcore/parity-wallet.git#18a602fd25f3e9bcdbc5528bf61ba627665d962c" +version = "0.3.0" +source = "git+https://github.com/ethcore/parity-wallet.git#664fd2b85dd94ca184868bd3965e14a4ba68c03f" dependencies = [ "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", ] diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index 51f54f02d..583d679e9 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -17,8 +17,9 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/ethcore/parity-webapp.git" } # List of apps -parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.3.7" } -parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.2.0", optional = true } +parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.4.0" } +parity-idmanager = { git = "https://github.com/ethcore/parity-idmanager-rs.git", version = "0.1.1" } +parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.3.0", optional = true } clippy = { version = "0.0.64", optional = true} [features] diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs index c07e9919c..951994d1d 100644 --- a/webapp/src/apps.rs +++ b/webapp/src/apps.rs @@ -14,19 +14,29 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use endpoint::Endpoints; +use endpoint::{Endpoints, Endpoint}; use page::PageEndpoint; use proxypac::ProxyPac; use parity_webapp::WebApp; extern crate parity_status; +extern crate parity_idmanager; #[cfg(feature = "parity-wallet")] extern crate parity_wallet; +pub const DAPPS_DOMAIN : &'static str = ".dapp"; +pub const RPC_PATH : &'static str = "rpc"; +pub const API_PATH : &'static str = "api"; +pub const UTILS_PATH : &'static str = "parity-utils"; + pub fn main_page() -> &'static str { "/status/" } +pub fn utils() -> Box { + Box::new(PageEndpoint::with_prefix(parity_idmanager::App::default(), UTILS_PATH.to_owned())) +} + pub fn all_endpoints() -> Endpoints { let mut pages = Endpoints::new(); pages.insert("proxy".to_owned(), ProxyPac::boxed()); diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 45157f076..80be6fd37 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -61,11 +61,10 @@ mod proxypac; use std::sync::{Arc, Mutex}; use std::net::SocketAddr; +use std::collections::HashMap; use jsonrpc_core::{IoHandler, IoDelegate}; use router::auth::{Authorization, NoAuth, HttpBasicAuth}; -static DAPPS_DOMAIN : &'static str = ".dapp"; - /// Webapps HTTP+RPC server build. pub struct ServerBuilder { handler: Arc, @@ -106,17 +105,21 @@ pub struct Server { impl Server { fn start_http(addr: &SocketAddr, authorization: A, handler: Arc) -> Result { let panic_handler = Arc::new(Mutex::new(None)); - let endpoints = Arc::new(apps::all_endpoints()); let authorization = Arc::new(authorization); - let rpc_endpoint = Arc::new(rpc::rpc(handler, panic_handler.clone())); - let api = Arc::new(api::RestApi::new(endpoints.clone())); + let endpoints = Arc::new(apps::all_endpoints()); + let special = Arc::new({ + let mut special = HashMap::new(); + special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone())); + special.insert(router::SpecialEndpoint::Api, api::RestApi::new(endpoints.clone())); + special.insert(router::SpecialEndpoint::Utils, apps::utils()); + special + }); try!(hyper::Server::http(addr)) .handle(move |_| router::Router::new( apps::main_page(), endpoints.clone(), - rpc_endpoint.clone(), - api.clone(), + special.clone(), authorization.clone(), )) .map(|l| Server { diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs index abcd1930b..1d987c393 100644 --- a/webapp/src/page/mod.rs +++ b/webapp/src/page/mod.rs @@ -26,13 +26,23 @@ use endpoint::{Endpoint, EndpointPath}; use parity_webapp::WebApp; pub struct PageEndpoint { + /// Content of the files pub app: Arc, + /// Prefix to strip from the path (when `None` deducted from `app_id`) + pub prefix: Option, } impl PageEndpoint { pub fn new(app: T) -> Self { PageEndpoint { - app: Arc::new(app) + app: Arc::new(app), + prefix: None, + } + } + pub fn with_prefix(app: T, prefix: String) -> Self { + PageEndpoint { + app: Arc::new(app), + prefix: Some(prefix), } } } @@ -41,6 +51,7 @@ impl Endpoint for PageEndpoint { fn to_handler(&self, path: EndpointPath) -> Box> { Box::new(PageHandler { app: self.app.clone(), + prefix: self.prefix.clone(), path: path, file: None, write_pos: 0, @@ -50,6 +61,7 @@ impl Endpoint for PageEndpoint { struct PageHandler { app: Arc, + prefix: Option, path: EndpointPath, file: Option, write_pos: usize, @@ -57,7 +69,8 @@ struct PageHandler { impl PageHandler { fn extract_path(&self, path: &str) -> String { - let prefix = "/".to_owned() + &self.path.app_id; + let app_id = &self.path.app_id; + let prefix = "/".to_owned() + self.prefix.as_ref().unwrap_or(app_id); let prefix_with_slash = prefix.clone() + "/"; // Index file support diff --git a/webapp/src/proxypac.rs b/webapp/src/proxypac.rs index da2cab916..9d91d58f0 100644 --- a/webapp/src/proxypac.rs +++ b/webapp/src/proxypac.rs @@ -17,7 +17,7 @@ //! Serving ProxyPac file use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath}; -use DAPPS_DOMAIN; +use apps::DAPPS_DOMAIN; pub struct ProxyPac; diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 11205068a..211c9f5eb 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -21,30 +21,32 @@ mod url; mod redirect; pub mod auth; -use DAPPS_DOMAIN; use std::sync::Arc; +use std::collections::HashMap; use url::Host; use hyper; use hyper::{server, uri, header}; use hyper::{Next, Encoder, Decoder}; use hyper::net::HttpStream; +use apps; use endpoint::{Endpoint, Endpoints, EndpointPath}; use self::url::Url; use self::auth::{Authorization, Authorized}; use self::redirect::Redirection; -#[derive(Debug, PartialEq)] -enum SpecialEndpoint { +/// Special endpoints are accessible on every domain (every dapp) +#[derive(Debug, PartialEq, Hash, Eq)] +pub enum SpecialEndpoint { Rpc, Api, + Utils, None } pub struct Router { main_page: &'static str, endpoints: Arc, - rpc: Arc>, - api: Arc>, + special: Arc>>, authorization: Arc, handler: Box>, } @@ -63,13 +65,9 @@ impl server::Handler for Router { let endpoint = extract_endpoint(&url); match endpoint { - // First check RPC requests - (ref path, SpecialEndpoint::Rpc) if *req.method() != hyper::method::Method::Get => { - self.rpc.to_handler(path.clone().unwrap_or_default()) - }, - // Check API requests - (ref path, SpecialEndpoint::Api) => { - self.api.to_handler(path.clone().unwrap_or_default()) + // First check special endpoints + (ref path, ref endpoint) if self.special.contains_key(endpoint) => { + self.special.get(endpoint).unwrap().to_handler(path.clone().unwrap_or_default()) }, // Then delegate to dapp (Some(ref path), _) if self.endpoints.contains_key(&path.app_id) => { @@ -81,7 +79,7 @@ impl server::Handler for Router { }, // RPC by default _ => { - self.rpc.to_handler(EndpointPath::default()) + self.special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()) } } } @@ -111,16 +109,14 @@ impl Router { pub fn new( main_page: &'static str, endpoints: Arc, - rpc: Arc>, - api: Arc>, + special: Arc>>, authorization: Arc) -> Self { - let handler = rpc.to_handler(EndpointPath::default()); + let handler = special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()); Router { main_page: main_page, endpoints: endpoints, - rpc: rpc, - api: api, + special: special, authorization: authorization, handler: handler, } @@ -158,17 +154,19 @@ fn extract_endpoint(url: &Option) -> (Option, SpecialEndpoint if url.path.len() <= 1 { return SpecialEndpoint::None; } + match url.path[0].as_ref() { - "rpc" => SpecialEndpoint::Rpc, - "api" => SpecialEndpoint::Api, + apps::RPC_PATH => SpecialEndpoint::Rpc, + apps::API_PATH => SpecialEndpoint::Api, + apps::UTILS_PATH => SpecialEndpoint::Utils, _ => SpecialEndpoint::None, } } match *url { Some(ref url) => match url.host { - Host::Domain(ref domain) if domain.ends_with(DAPPS_DOMAIN) => { - let len = domain.len() - DAPPS_DOMAIN.len(); + Host::Domain(ref domain) if domain.ends_with(apps::DAPPS_DOMAIN) => { + let len = domain.len() - apps::DAPPS_DOMAIN.len(); let id = domain[0..len].to_owned(); (Some(EndpointPath { @@ -215,6 +213,15 @@ fn should_extract_endpoint() { }), SpecialEndpoint::Rpc) ); + assert_eq!( + extract_endpoint(&Url::parse("http://my.status.dapp/parity-utils/inject.js").ok()), + (Some(EndpointPath { + app_id: "my.status".to_owned(), + host: "my.status.dapp".to_owned(), + port: 80, + }), SpecialEndpoint::Utils) + ); + // By Subdomain assert_eq!( extract_endpoint(&Url::parse("http://my.status.dapp/test.html").ok()), @@ -237,7 +244,7 @@ fn should_extract_endpoint() { // API by subdomain assert_eq!( - extract_endpoint(&Url::parse("http://my.status.dapp/rpc/").ok()), + extract_endpoint(&Url::parse("http://my.status.dapp/api/").ok()), (Some(EndpointPath { app_id: "my.status".to_owned(), host: "my.status.dapp".to_owned(),