Dapp refresh (#5752)
* RwLock * getting there * argh * parking_lot * rpc * wax on wax off * almost there * remove lock * write over read * works * linting * small updates * dissapearing act * router update * complete * one m * grumbles1 * grumbles part II * parking_lot->util * missed test case * fied package-lock.json * small fixes * 404 tests failing * cleanup * cleanup 2 * updates and the likes * play * simplify filter * f-ing bugs * read->write * Address own grumbles. * Fix test.
This commit is contained in:
parent
d6eb053826
commit
7d17d77254
@ -14,7 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -30,8 +29,8 @@ use {WebProxyTokens, ParentFrameSettings};
|
|||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod cache;
|
mod cache;
|
||||||
mod fs;
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
pub mod fs;
|
||||||
pub mod fetcher;
|
pub mod fetcher;
|
||||||
pub mod manifest;
|
pub mod manifest;
|
||||||
|
|
||||||
@ -64,9 +63,10 @@ pub fn all_endpoints<F: Fetch>(
|
|||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
remote: Remote,
|
remote: Remote,
|
||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Endpoints {
|
) -> (Vec<String>, Endpoints) {
|
||||||
// fetch fs dapps at first to avoid overwriting builtins
|
// fetch fs dapps at first to avoid overwriting builtins
|
||||||
let mut pages = fs::local_endpoints(dapps_path, embeddable.clone());
|
let mut pages = fs::local_endpoints(dapps_path.clone(), embeddable.clone());
|
||||||
|
let local_endpoints: Vec<String> = pages.keys().cloned().collect();
|
||||||
for path in extra_dapps {
|
for path in extra_dapps {
|
||||||
if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone()) {
|
if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone()) {
|
||||||
pages.insert(id, endpoint);
|
pages.insert(id, endpoint);
|
||||||
@ -80,10 +80,10 @@ pub fn all_endpoints<F: Fetch>(
|
|||||||
pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()));
|
pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()));
|
||||||
pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone()));
|
pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone()));
|
||||||
|
|
||||||
Arc::new(pages)
|
(local_endpoints, pages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert<T : WebApp + Default + 'static>(pages: &mut BTreeMap<String, Box<Endpoint>>, id: &str, embed_at: Embeddable) {
|
fn insert<T : WebApp + Default + 'static>(pages: &mut Endpoints, id: &str, embed_at: Embeddable) {
|
||||||
pages.insert(id.to_owned(), Box::new(match embed_at {
|
pages.insert(id.to_owned(), Box::new(match embed_at {
|
||||||
Embeddable::Yes(address) => PageEndpoint::new_safe_to_embed(T::default(), address),
|
Embeddable::Yes(address) => PageEndpoint::new_safe_to_embed(T::default(), address),
|
||||||
Embeddable::No => PageEndpoint::new(T::default()),
|
Embeddable::No => PageEndpoint::new(T::default()),
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
//! URL Endpoint traits
|
//! URL Endpoint traits
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use hyper::{self, server, net};
|
use hyper::{self, server, net};
|
||||||
@ -39,7 +38,7 @@ pub struct EndpointInfo {
|
|||||||
pub icon_url: String,
|
pub icon_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Endpoints = Arc<BTreeMap<String, Box<Endpoint>>>;
|
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
|
||||||
pub type Handler = server::Handler<net::HttpStream> + Send;
|
pub type Handler = server::Handler<net::HttpStream> + Send;
|
||||||
|
|
||||||
pub trait Endpoint : Send + Sync {
|
pub trait Endpoint : Send + Sync {
|
||||||
|
@ -69,9 +69,11 @@ mod web;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use util::RwLock;
|
||||||
|
|
||||||
use jsonrpc_http_server::{self as http, hyper, Origin};
|
use jsonrpc_http_server::{self as http, hyper, Origin};
|
||||||
|
|
||||||
@ -101,31 +103,54 @@ impl<F> WebProxyTokens for F where F: Fn(String) -> Option<Origin> + Send + Sync
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Current supported endpoints.
|
/// Current supported endpoints.
|
||||||
|
#[derive(Default, Clone)]
|
||||||
pub struct Endpoints {
|
pub struct Endpoints {
|
||||||
endpoints: endpoint::Endpoints,
|
local_endpoints: Arc<RwLock<Vec<String>>>,
|
||||||
|
endpoints: Arc<RwLock<endpoint::Endpoints>>,
|
||||||
|
dapps_path: PathBuf,
|
||||||
|
embeddable: Option<ParentFrameSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Endpoints {
|
impl Endpoints {
|
||||||
/// Returns a current list of app endpoints.
|
/// Returns a current list of app endpoints.
|
||||||
pub fn list(&self) -> Vec<apps::App> {
|
pub fn list(&self) -> Vec<apps::App> {
|
||||||
self.endpoints.iter().filter_map(|(ref k, ref e)| {
|
self.endpoints.read().iter().filter_map(|(ref k, ref e)| {
|
||||||
e.info().map(|ref info| apps::App::from_info(k, info))
|
e.info().map(|ref info| apps::App::from_info(k, info))
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check for any changes in the local dapps folder and update.
|
||||||
|
pub fn refresh_local_dapps(&self) {
|
||||||
|
let new_local = apps::fs::local_endpoints(&self.dapps_path, self.embeddable.clone());
|
||||||
|
let old_local = mem::replace(&mut *self.local_endpoints.write(), new_local.keys().cloned().collect());
|
||||||
|
let (_, to_remove): (_, Vec<_>) = old_local
|
||||||
|
.into_iter()
|
||||||
|
.partition(|k| new_local.contains_key(&k.clone()));
|
||||||
|
|
||||||
|
let mut endpoints = self.endpoints.write();
|
||||||
|
// remove the dead dapps
|
||||||
|
for k in to_remove {
|
||||||
|
endpoints.remove(&k);
|
||||||
|
}
|
||||||
|
// new dapps to be added
|
||||||
|
for (k, v) in new_local {
|
||||||
|
if !endpoints.contains_key(&k) {
|
||||||
|
endpoints.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dapps server as `jsonrpc-http-server` request middleware.
|
/// Dapps server as `jsonrpc-http-server` request middleware.
|
||||||
pub struct Middleware {
|
pub struct Middleware {
|
||||||
|
endpoints: Endpoints,
|
||||||
router: router::Router,
|
router: router::Router,
|
||||||
endpoints: endpoint::Endpoints,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Middleware {
|
impl Middleware {
|
||||||
/// Get local endpoints handle.
|
/// Get local endpoints handle.
|
||||||
pub fn endpoints(&self) -> Endpoints {
|
pub fn endpoints(&self) -> &Endpoints {
|
||||||
Endpoints {
|
&self.endpoints
|
||||||
endpoints: self.endpoints.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new middleware for UI server.
|
/// Creates new middleware for UI server.
|
||||||
@ -164,8 +189,8 @@ impl Middleware {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Middleware {
|
Middleware {
|
||||||
router: router,
|
|
||||||
endpoints: Default::default(),
|
endpoints: Default::default(),
|
||||||
|
router: router,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,8 +216,8 @@ impl Middleware {
|
|||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
).embeddable_on(embeddable.clone()).allow_dapps(true));
|
).embeddable_on(embeddable.clone()).allow_dapps(true));
|
||||||
let endpoints = apps::all_endpoints(
|
let (local_endpoints, endpoints) = apps::all_endpoints(
|
||||||
dapps_path,
|
dapps_path.clone(),
|
||||||
extra_dapps,
|
extra_dapps,
|
||||||
dapps_domain,
|
dapps_domain,
|
||||||
embeddable.clone(),
|
embeddable.clone(),
|
||||||
@ -200,6 +225,12 @@ impl Middleware {
|
|||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
);
|
);
|
||||||
|
let endpoints = Endpoints {
|
||||||
|
endpoints: Arc::new(RwLock::new(endpoints)),
|
||||||
|
dapps_path,
|
||||||
|
local_endpoints: Arc::new(RwLock::new(local_endpoints)),
|
||||||
|
embeddable: embeddable.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
let special = {
|
let special = {
|
||||||
let mut special = special_endpoints(
|
let mut special = special_endpoints(
|
||||||
@ -225,8 +256,8 @@ impl Middleware {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Middleware {
|
Middleware {
|
||||||
router: router,
|
endpoints,
|
||||||
endpoints: endpoints,
|
router,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ use jsonrpc_http_server as http;
|
|||||||
|
|
||||||
use apps;
|
use apps;
|
||||||
use apps::fetcher::Fetcher;
|
use apps::fetcher::Fetcher;
|
||||||
use endpoint::{Endpoint, Endpoints, EndpointPath, Handler};
|
use endpoint::{Endpoint, EndpointPath, Handler};
|
||||||
|
use Endpoints;
|
||||||
use handlers;
|
use handlers;
|
||||||
use Embeddable;
|
use Embeddable;
|
||||||
|
|
||||||
@ -50,26 +51,27 @@ pub struct Router {
|
|||||||
dapps_domain: String,
|
dapps_domain: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl http::RequestMiddleware for Router {
|
impl Router {
|
||||||
fn on_request(&self, req: &server::Request<HttpStream>, control: &Control) -> http::RequestMiddlewareAction {
|
fn resolve_request(&self, req: &server::Request<HttpStream>, control: Control, refresh_dapps: bool) -> (bool, Option<Box<Handler>>) {
|
||||||
// Choose proper handler depending on path / domain
|
// Choose proper handler depending on path / domain
|
||||||
let url = handlers::extract_url(req);
|
let url = handlers::extract_url(req);
|
||||||
let endpoint = extract_endpoint(&url, &self.dapps_domain);
|
let endpoint = extract_endpoint(&url, &self.dapps_domain);
|
||||||
let referer = extract_referer_endpoint(req, &self.dapps_domain);
|
let referer = extract_referer_endpoint(req, &self.dapps_domain);
|
||||||
let is_utils = endpoint.1 == SpecialEndpoint::Utils;
|
let is_utils = endpoint.1 == SpecialEndpoint::Utils;
|
||||||
let is_origin_set = req.headers().get::<header::Origin>().is_some();
|
|
||||||
let is_get_request = *req.method() == hyper::Method::Get;
|
let is_get_request = *req.method() == hyper::Method::Get;
|
||||||
let is_head_request = *req.method() == hyper::Method::Head;
|
let is_head_request = *req.method() == hyper::Method::Head;
|
||||||
|
let has_dapp = |dapp: &str| self.endpoints
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |endpoints| endpoints.endpoints.read().contains_key(dapp));
|
||||||
|
|
||||||
trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", url, req);
|
trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", url, req);
|
||||||
|
|
||||||
let control = control.clone();
|
|
||||||
debug!(target: "dapps", "Handling endpoint request: {:?}", endpoint);
|
debug!(target: "dapps", "Handling endpoint request: {:?}", endpoint);
|
||||||
let handler: Option<Box<Handler>> = match (endpoint.0, endpoint.1, referer) {
|
|
||||||
|
(is_utils, match (endpoint.0, endpoint.1, referer) {
|
||||||
// Handle invalid web requests that we can recover from
|
// Handle invalid web requests that we can recover from
|
||||||
(ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url)))
|
(ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url)))
|
||||||
if referer.app_id == apps::WEB_PATH
|
if referer.app_id == apps::WEB_PATH
|
||||||
&& self.endpoints.as_ref().map(|ep| ep.contains_key(apps::WEB_PATH)).unwrap_or(false)
|
&& has_dapp(apps::WEB_PATH)
|
||||||
&& !is_web_endpoint(path)
|
&& !is_web_endpoint(path)
|
||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
@ -88,11 +90,13 @@ impl http::RequestMiddleware for Router {
|
|||||||
.map(|special| special.to_async_handler(path.clone().unwrap_or_default(), control))
|
.map(|special| special.to_async_handler(path.clone().unwrap_or_default(), control))
|
||||||
},
|
},
|
||||||
// Then delegate to dapp
|
// Then delegate to dapp
|
||||||
(Some(ref path), _, _) if self.endpoints.as_ref().map(|ep| ep.contains_key(&path.app_id)).unwrap_or(false) => {
|
(Some(ref path), _, _) if has_dapp(&path.app_id) => {
|
||||||
trace!(target: "dapps", "Resolving to local/builtin dapp.");
|
trace!(target: "dapps", "Resolving to local/builtin dapp.");
|
||||||
Some(self.endpoints
|
Some(self.endpoints
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("endpoints known to be set; qed")
|
.expect("endpoints known to be set; qed")
|
||||||
|
.endpoints
|
||||||
|
.read()
|
||||||
.get(&path.app_id)
|
.get(&path.app_id)
|
||||||
.expect("endpoints known to contain key; qed")
|
.expect("endpoints known to contain key; qed")
|
||||||
.to_async_handler(path.clone(), control))
|
.to_async_handler(path.clone(), control))
|
||||||
@ -110,13 +114,19 @@ impl http::RequestMiddleware for Router {
|
|||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
trace!(target: "dapps", "Resolving to 404.");
|
trace!(target: "dapps", "Resolving to 404.");
|
||||||
Some(Box::new(handlers::ContentHandler::error(
|
if refresh_dapps {
|
||||||
hyper::StatusCode::NotFound,
|
debug!(target: "dapps", "Refreshing dapps and re-trying.");
|
||||||
"404 Not Found",
|
self.endpoints.as_ref().map(|endpoints| endpoints.refresh_local_dapps());
|
||||||
"Requested content was not found.",
|
return self.resolve_request(req, control, false)
|
||||||
None,
|
} else {
|
||||||
self.embeddable_on.clone(),
|
Some(Box::new(handlers::ContentHandler::error(
|
||||||
)))
|
hyper::StatusCode::NotFound,
|
||||||
|
"404 Not Found",
|
||||||
|
"Requested content was not found.",
|
||||||
|
None,
|
||||||
|
self.embeddable_on.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Any other GET|HEAD requests to home page.
|
// Any other GET|HEAD requests to home page.
|
||||||
_ if (is_get_request || is_head_request) && self.special.contains_key(&SpecialEndpoint::Home) => {
|
_ if (is_get_request || is_head_request) && self.special.contains_key(&SpecialEndpoint::Home) => {
|
||||||
@ -130,8 +140,15 @@ impl http::RequestMiddleware for Router {
|
|||||||
trace!(target: "dapps", "Resolving to RPC call.");
|
trace!(target: "dapps", "Resolving to RPC call.");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl http::RequestMiddleware for Router {
|
||||||
|
fn on_request(&self, req: &server::Request<HttpStream>, control: &Control) -> http::RequestMiddlewareAction {
|
||||||
|
let control = control.clone();
|
||||||
|
let is_origin_set = req.headers().get::<header::Origin>().is_some();
|
||||||
|
let (is_utils, handler) = self.resolve_request(req, control, self.endpoints.is_some());
|
||||||
match handler {
|
match handler {
|
||||||
Some(handler) => http::RequestMiddlewareAction::Respond {
|
Some(handler) => http::RequestMiddlewareAction::Respond {
|
||||||
should_validate_hosts: !is_utils,
|
should_validate_hosts: !is_utils,
|
||||||
|
@ -39,7 +39,7 @@ fn should_resolve_dapp() {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
response.assert_status("HTTP/1.1 404 Not Found");
|
response.assert_status("HTTP/1.1 404 Not Found");
|
||||||
assert_eq!(registrar.calls.lock().len(), 2);
|
assert_eq!(registrar.calls.lock().len(), 4);
|
||||||
assert_security_headers_for_embed(&response.headers);
|
assert_security_headers_for_embed(&response.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,4 +204,3 @@ fn should_serve_utils() {
|
|||||||
assert_eq!(response.body.contains("function(){"), true);
|
assert_eq!(response.body.contains("function(){"), true);
|
||||||
assert_security_headers(&response.headers);
|
assert_security_headers(&response.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,5 +241,3 @@ impl<F: Fetch> server::Handler<net::HttpStream> for WebHandler<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
4
js/package-lock.json
generated
4
js/package-lock.json
generated
@ -7722,7 +7722,7 @@
|
|||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "1.1.8"
|
"brace-expansion": "1.1.8"
|
||||||
}
|
}
|
||||||
@ -10081,7 +10081,7 @@
|
|||||||
"react-qr-reader": {
|
"react-qr-reader": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-qr-reader/-/react-qr-reader-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-qr-reader/-/react-qr-reader-1.1.3.tgz",
|
||||||
"integrity": "sha512-ruBF8KaSwUW9nbzjO4rA7/HOCGYZuNUz9od7uBRy8SRBi24nwxWWmwa2z8R6vPGDRglA0y2Qk1aVBuC1olTnHw==",
|
"integrity": "sha1-dDmnZvyZPLj17u/HLCnblh1AswI=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"jsqr": "git+https://github.com/JodusNodus/jsQR.git#5ba1acefa1cbb9b2bc92b49f503f2674e2ec212b",
|
"jsqr": "git+https://github.com/JodusNodus/jsQR.git#5ba1acefa1cbb9b2bc92b49f503f2674e2ec212b",
|
||||||
"prop-types": "15.5.10",
|
"prop-types": "15.5.10",
|
||||||
|
@ -95,6 +95,11 @@ export default class Parity {
|
|||||||
.execute('parity_dappsList');
|
.execute('parity_dappsList');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dappsRefresh () {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_dappsRefresh');
|
||||||
|
}
|
||||||
|
|
||||||
dappsUrl () {
|
dappsUrl () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_dappsUrl');
|
.execute('parity_dappsUrl');
|
||||||
|
@ -164,6 +164,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
dappsRefresh: {
|
||||||
|
subdoc: SUBDOC_SET,
|
||||||
|
desc: 'Returns a boolean value upon success and error upon failure',
|
||||||
|
params: [],
|
||||||
|
returns: {
|
||||||
|
type: Boolean,
|
||||||
|
desc: 'True for success. error details for failure',
|
||||||
|
example: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
dappsUrl: {
|
dappsUrl: {
|
||||||
section: SECTION_NODE,
|
section: SECTION_NODE,
|
||||||
desc: 'Returns the hostname and the port of dapps/rpc server, error if not enabled.',
|
desc: 'Returns the hostname and the port of dapps/rpc server, error if not enabled.',
|
||||||
|
@ -24,7 +24,7 @@ import { connect } from 'react-redux';
|
|||||||
import { DappPermissions, DappsVisible } from '~/modals';
|
import { DappPermissions, DappsVisible } from '~/modals';
|
||||||
import PermissionStore from '~/modals/DappPermissions/store';
|
import PermissionStore from '~/modals/DappPermissions/store';
|
||||||
import { Actionbar, Button, DappCard, Page, SectionList } from '~/ui';
|
import { Actionbar, Button, DappCard, Page, SectionList } from '~/ui';
|
||||||
import { LockedIcon, VisibleIcon } from '~/ui/Icons';
|
import { LockedIcon, RefreshIcon, VisibleIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
import DappsStore from './dappsStore';
|
import DappsStore from './dappsStore';
|
||||||
|
|
||||||
@ -90,6 +90,17 @@ class Dapps extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
buttons={ [
|
buttons={ [
|
||||||
|
<Button
|
||||||
|
icon={ <RefreshIcon /> }
|
||||||
|
key='refresh'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='dapps.button.dapp.refresh'
|
||||||
|
defaultMessage='refresh'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.store.refreshDapps }
|
||||||
|
/>,
|
||||||
<Button
|
<Button
|
||||||
icon={ <VisibleIcon /> }
|
icon={ <VisibleIcon /> }
|
||||||
key='edit'
|
key='edit'
|
||||||
|
@ -89,7 +89,7 @@ export default class DappsStore extends EventEmitter {
|
|||||||
return Promise
|
return Promise
|
||||||
.all([
|
.all([
|
||||||
this.fetchBuiltinApps().then((apps) => this.addApps(apps)),
|
this.fetchBuiltinApps().then((apps) => this.addApps(apps)),
|
||||||
this.fetchLocalApps().then((apps) => this.addApps(apps))
|
this.fetchLocalApps().then((apps) => this.addApps(apps, true))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +227,20 @@ export default class DappsStore extends EventEmitter {
|
|||||||
return this.visibleApps.filter((app) => app.type === 'network');
|
return this.visibleApps.filter((app) => app.type === 'network');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action refreshDapps = () => {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
self._api.parity.dappsRefresh()
|
||||||
|
.then((res) => {
|
||||||
|
if (res === true) {
|
||||||
|
self.loadAllApps();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@action openModal = () => {
|
@action openModal = () => {
|
||||||
this.modalOpen = true;
|
this.modalOpen = true;
|
||||||
}
|
}
|
||||||
@ -266,7 +280,7 @@ export default class DappsStore extends EventEmitter {
|
|||||||
this.displayApps = Object.assign({}, this.displayApps, displayApps);
|
this.displayApps = Object.assign({}, this.displayApps, displayApps);
|
||||||
};
|
};
|
||||||
|
|
||||||
@action addApps = (_apps = []) => {
|
@action addApps = (_apps = [], _local = false) => {
|
||||||
transaction(() => {
|
transaction(() => {
|
||||||
const apps = _apps.filter((app) => app);
|
const apps = _apps.filter((app) => app);
|
||||||
|
|
||||||
@ -277,6 +291,7 @@ export default class DappsStore extends EventEmitter {
|
|||||||
|
|
||||||
this.apps = this.apps
|
this.apps = this.apps
|
||||||
.filter((app) => !app.id || !newAppsIds.includes(app.id))
|
.filter((app) => !app.id || !newAppsIds.includes(app.id))
|
||||||
|
.filter((app) => !(app.type === 'local' && _local && apps.indexOf(app) === -1))
|
||||||
.concat(apps || [])
|
.concat(apps || [])
|
||||||
.sort((a, b) => a.name.localeCompare(b.name));
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ mod server {
|
|||||||
|
|
||||||
pub fn service(middleware: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> {
|
pub fn service(middleware: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> {
|
||||||
middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper {
|
middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper {
|
||||||
endpoints: m.endpoints()
|
endpoints: m.endpoints().clone(),
|
||||||
}) as Arc<rpc_apis::DappsService>)
|
}) as Arc<rpc_apis::DappsService>)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,5 +313,10 @@ mod server {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refresh_local_dapps(&self) -> bool {
|
||||||
|
self.endpoints.refresh_local_dapps();
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,6 @@ use v1::types::LocalDapp;
|
|||||||
pub trait DappsService: Send + Sync + 'static {
|
pub trait DappsService: Send + Sync + 'static {
|
||||||
/// List available local dapps.
|
/// List available local dapps.
|
||||||
fn list_dapps(&self) -> Vec<LocalDapp>;
|
fn list_dapps(&self) -> Vec<LocalDapp>;
|
||||||
}
|
/// Refresh local dapps list
|
||||||
|
fn refresh_local_dapps(&self) -> bool;
|
||||||
impl<F> DappsService for F where
|
|
||||||
F: Fn() -> Vec<LocalDapp> + Send + Sync + 'static
|
|
||||||
{
|
|
||||||
fn list_dapps(&self) -> Vec<LocalDapp> {
|
|
||||||
(*self)()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,10 @@ impl<F: Fetch> ParitySet for ParitySetClient<F> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dapps_refresh(&self) -> Result<bool, Error> {
|
||||||
|
self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled)
|
||||||
|
}
|
||||||
|
|
||||||
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error> {
|
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error> {
|
||||||
self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled)
|
self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled)
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,10 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dapps_refresh(&self) -> Result<bool, Error> {
|
||||||
|
self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled)
|
||||||
|
}
|
||||||
|
|
||||||
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error> {
|
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error> {
|
||||||
self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled)
|
self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled)
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,8 @@ impl DappsService for TestDappsService {
|
|||||||
icon_url: "title.png".into(),
|
icon_url: "title.png".into(),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refresh_local_dapps(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,10 @@ build_rpc_trait! {
|
|||||||
#[rpc(async, name = "parity_hashContent")]
|
#[rpc(async, name = "parity_hashContent")]
|
||||||
fn hash_content(&self, String) -> BoxFuture<H256, Error>;
|
fn hash_content(&self, String) -> BoxFuture<H256, Error>;
|
||||||
|
|
||||||
|
/// Returns true if refresh successful, error if unsuccessful or server is disabled.
|
||||||
|
#[rpc(name = "parity_dappsRefresh")]
|
||||||
|
fn dapps_refresh(&self) -> Result<bool, Error>;
|
||||||
|
|
||||||
/// Returns a list of local dapps
|
/// Returns a list of local dapps
|
||||||
#[rpc(name = "parity_dappsList")]
|
#[rpc(name = "parity_dappsList")]
|
||||||
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error>;
|
fn dapps_list(&self) -> Result<Vec<LocalDapp>, Error>;
|
||||||
|
Loading…
Reference in New Issue
Block a user