Displaying special page when syncing. 404 instead of redirection
This commit is contained in:
parent
9c4d31f548
commit
89f1444c51
@ -30,6 +30,7 @@ use hyper::Control;
|
|||||||
use hyper::status::StatusCode;
|
use hyper::status::StatusCode;
|
||||||
|
|
||||||
use random_filename;
|
use random_filename;
|
||||||
|
use SyncStatus;
|
||||||
use util::{Mutex, H256};
|
use util::{Mutex, H256};
|
||||||
use util::sha3::sha3;
|
use util::sha3::sha3;
|
||||||
use page::LocalPageEndpoint;
|
use page::LocalPageEndpoint;
|
||||||
@ -44,6 +45,7 @@ const MAX_CACHED_DAPPS: usize = 10;
|
|||||||
pub struct AppFetcher<R: URLHint = URLHintContract> {
|
pub struct AppFetcher<R: URLHint = URLHintContract> {
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
resolver: R,
|
resolver: R,
|
||||||
|
sync: Arc<SyncStatus>,
|
||||||
dapps: Arc<Mutex<ContentCache>>,
|
dapps: Arc<Mutex<ContentCache>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,13 +58,14 @@ impl<R: URLHint> Drop for AppFetcher<R> {
|
|||||||
|
|
||||||
impl<R: URLHint> AppFetcher<R> {
|
impl<R: URLHint> AppFetcher<R> {
|
||||||
|
|
||||||
pub fn new(resolver: R) -> Self {
|
pub fn new(resolver: R, sync_status: Arc<SyncStatus>) -> Self {
|
||||||
let mut dapps_path = env::temp_dir();
|
let mut dapps_path = env::temp_dir();
|
||||||
dapps_path.push(random_filename());
|
dapps_path.push(random_filename());
|
||||||
|
|
||||||
AppFetcher {
|
AppFetcher {
|
||||||
dapps_path: dapps_path,
|
dapps_path: dapps_path,
|
||||||
resolver: resolver,
|
resolver: resolver,
|
||||||
|
sync: sync_status,
|
||||||
dapps: Arc::new(Mutex::new(ContentCache::default())),
|
dapps: Arc::new(Mutex::new(ContentCache::default())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,14 +77,20 @@ impl<R: URLHint> AppFetcher<R> {
|
|||||||
|
|
||||||
pub fn contains(&self, app_id: &str) -> bool {
|
pub fn contains(&self, app_id: &str) -> bool {
|
||||||
let mut dapps = self.dapps.lock();
|
let mut dapps = self.dapps.lock();
|
||||||
match dapps.get(app_id) {
|
|
||||||
// Check if we already have the app
|
// Check if we already have the app
|
||||||
Some(_) => true,
|
if dapps.get(app_id).is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// fallback to resolver
|
// fallback to resolver
|
||||||
None => match app_id.from_hex() {
|
if let Ok(app_id) = app_id.from_hex() {
|
||||||
Ok(app_id) => self.resolver.resolve(app_id).is_some(),
|
// if app_id is valid, but we are syncing always return true.
|
||||||
_ => false,
|
if self.sync.is_major_syncing() {
|
||||||
},
|
return true;
|
||||||
|
}
|
||||||
|
// else try to resolve the app_id
|
||||||
|
self.resolver.resolve(app_id).is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +98,15 @@ impl<R: URLHint> AppFetcher<R> {
|
|||||||
let mut dapps = self.dapps.lock();
|
let mut dapps = self.dapps.lock();
|
||||||
let app_id = path.app_id.clone();
|
let app_id = path.app_id.clone();
|
||||||
|
|
||||||
|
if self.sync.is_major_syncing() {
|
||||||
|
return Box::new(ContentHandler::error(
|
||||||
|
StatusCode::ServiceUnavailable,
|
||||||
|
"Sync in progress",
|
||||||
|
"Your node is still syncing. We cannot resolve any content before it's fully synced.",
|
||||||
|
None
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let (new_status, handler) = {
|
let (new_status, handler) = {
|
||||||
let status = dapps.get(&app_id);
|
let status = dapps.get(&app_id);
|
||||||
match status {
|
match status {
|
||||||
@ -108,7 +126,9 @@ impl<R: URLHint> AppFetcher<R> {
|
|||||||
// We need to start fetching app
|
// We need to start fetching app
|
||||||
None => {
|
None => {
|
||||||
let app_hex = app_id.from_hex().expect("to_handler is called only when `contains` returns true.");
|
let app_hex = app_id.from_hex().expect("to_handler is called only when `contains` returns true.");
|
||||||
let app = self.resolver.resolve(app_hex).expect("to_handler is called only when `contains` returns true.");
|
let app = self.resolver.resolve(app_hex);
|
||||||
|
|
||||||
|
if let Some(app) = app {
|
||||||
let abort = Arc::new(AtomicBool::new(false));
|
let abort = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
(Some(ContentStatus::Fetching(abort.clone())), Box::new(ContentFetcherHandler::new(
|
(Some(ContentStatus::Fetching(abort.clone())), Box::new(ContentFetcherHandler::new(
|
||||||
@ -122,6 +142,16 @@ impl<R: URLHint> AppFetcher<R> {
|
|||||||
dapps: self.dapps.clone(),
|
dapps: self.dapps.clone(),
|
||||||
}
|
}
|
||||||
)) as Box<Handler>)
|
)) as Box<Handler>)
|
||||||
|
} else {
|
||||||
|
// This may happen when sync status changes in between
|
||||||
|
// `contains` and `to_handler`
|
||||||
|
(None, Box::new(ContentHandler::error(
|
||||||
|
StatusCode::NotFound,
|
||||||
|
"Resource Not Found",
|
||||||
|
"Requested resource was not found.",
|
||||||
|
None
|
||||||
|
)) as Box<Handler>)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -274,6 +304,7 @@ impl ContentValidator for DappInstaller {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::sync::Arc;
|
||||||
use util::Bytes;
|
use util::Bytes;
|
||||||
use endpoint::EndpointInfo;
|
use endpoint::EndpointInfo;
|
||||||
use page::LocalPageEndpoint;
|
use page::LocalPageEndpoint;
|
||||||
@ -292,7 +323,7 @@ mod tests {
|
|||||||
fn should_true_if_contains_the_app() {
|
fn should_true_if_contains_the_app() {
|
||||||
// given
|
// given
|
||||||
let path = env::temp_dir();
|
let path = env::temp_dir();
|
||||||
let fetcher = AppFetcher::new(FakeResolver);
|
let fetcher = AppFetcher::new(FakeResolver, Arc::new(|| false));
|
||||||
let handler = LocalPageEndpoint::new(path, EndpointInfo {
|
let handler = LocalPageEndpoint::new(path, EndpointInfo {
|
||||||
name: "fake".into(),
|
name: "fake".into(),
|
||||||
description: "".into(),
|
description: "".into(),
|
||||||
|
@ -88,11 +88,22 @@ use ethcore_rpc::Extendable;
|
|||||||
|
|
||||||
static DAPPS_DOMAIN : &'static str = ".parity";
|
static DAPPS_DOMAIN : &'static str = ".parity";
|
||||||
|
|
||||||
|
/// Indicates sync status
|
||||||
|
pub trait SyncStatus: Send + Sync {
|
||||||
|
/// Returns true if there is a major sync happening.
|
||||||
|
fn is_major_syncing(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> SyncStatus for F where F: Fn() -> bool + Send + Sync {
|
||||||
|
fn is_major_syncing(&self) -> bool { self() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Webapps HTTP+RPC server build.
|
/// Webapps HTTP+RPC server build.
|
||||||
pub struct ServerBuilder {
|
pub struct ServerBuilder {
|
||||||
dapps_path: String,
|
dapps_path: String,
|
||||||
handler: Arc<IoHandler>,
|
handler: Arc<IoHandler>,
|
||||||
registrar: Arc<ContractClient>,
|
registrar: Arc<ContractClient>,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Extendable for ServerBuilder {
|
impl Extendable for ServerBuilder {
|
||||||
@ -108,9 +119,15 @@ impl ServerBuilder {
|
|||||||
dapps_path: dapps_path,
|
dapps_path: dapps_path,
|
||||||
handler: Arc::new(IoHandler::new()),
|
handler: Arc::new(IoHandler::new()),
|
||||||
registrar: registrar,
|
registrar: registrar,
|
||||||
|
sync_status: Arc::new(|| false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change default sync status.
|
||||||
|
pub fn with_sync_status(&mut self, status: Arc<SyncStatus>) {
|
||||||
|
self.sync_status = status;
|
||||||
|
}
|
||||||
|
|
||||||
/// Asynchronously start server with no authentication,
|
/// Asynchronously start server with no authentication,
|
||||||
/// returns result with `Server` handle on success or an error.
|
/// returns result with `Server` handle on success or an error.
|
||||||
pub fn start_unsecured_http(&self, addr: &SocketAddr, hosts: Option<Vec<String>>) -> Result<Server, ServerError> {
|
pub fn start_unsecured_http(&self, addr: &SocketAddr, hosts: Option<Vec<String>>) -> Result<Server, ServerError> {
|
||||||
@ -120,7 +137,8 @@ impl ServerBuilder {
|
|||||||
NoAuth,
|
NoAuth,
|
||||||
self.handler.clone(),
|
self.handler.clone(),
|
||||||
self.dapps_path.clone(),
|
self.dapps_path.clone(),
|
||||||
self.registrar.clone()
|
self.registrar.clone(),
|
||||||
|
self.sync_status.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +151,8 @@ impl ServerBuilder {
|
|||||||
HttpBasicAuth::single_user(username, password),
|
HttpBasicAuth::single_user(username, password),
|
||||||
self.handler.clone(),
|
self.handler.clone(),
|
||||||
self.dapps_path.clone(),
|
self.dapps_path.clone(),
|
||||||
self.registrar.clone()
|
self.registrar.clone(),
|
||||||
|
self.sync_status.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,10 +186,11 @@ impl Server {
|
|||||||
handler: Arc<IoHandler>,
|
handler: Arc<IoHandler>,
|
||||||
dapps_path: String,
|
dapps_path: String,
|
||||||
registrar: Arc<ContractClient>,
|
registrar: Arc<ContractClient>,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
) -> Result<Server, ServerError> {
|
) -> Result<Server, ServerError> {
|
||||||
let panic_handler = Arc::new(Mutex::new(None));
|
let panic_handler = Arc::new(Mutex::new(None));
|
||||||
let authorization = Arc::new(authorization);
|
let authorization = Arc::new(authorization);
|
||||||
let apps_fetcher = Arc::new(apps::fetcher::AppFetcher::new(apps::urlhint::URLHintContract::new(registrar)));
|
let apps_fetcher = Arc::new(apps::fetcher::AppFetcher::new(apps::urlhint::URLHintContract::new(registrar), sync_status));
|
||||||
let endpoints = Arc::new(apps::all_endpoints(dapps_path));
|
let endpoints = Arc::new(apps::all_endpoints(dapps_path));
|
||||||
let special = Arc::new({
|
let special = Arc::new({
|
||||||
let mut special = HashMap::new();
|
let mut special = HashMap::new();
|
||||||
|
@ -24,12 +24,12 @@ use DAPPS_DOMAIN;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use url::{Url, Host};
|
use url::{Url, Host};
|
||||||
use hyper::{self, server, Next, Encoder, Decoder, Control};
|
use hyper::{self, server, Next, Encoder, Decoder, Control, StatusCode};
|
||||||
use hyper::net::HttpStream;
|
use hyper::net::HttpStream;
|
||||||
use apps;
|
use apps;
|
||||||
use apps::fetcher::AppFetcher;
|
use apps::fetcher::AppFetcher;
|
||||||
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
||||||
use handlers::{Redirection, extract_url};
|
use handlers::{Redirection, extract_url, ContentHandler};
|
||||||
use self::auth::{Authorization, Authorized};
|
use self::auth::{Authorization, Authorized};
|
||||||
|
|
||||||
/// Special endpoints are accessible on every domain (every dapp)
|
/// Special endpoints are accessible on every domain (every dapp)
|
||||||
@ -94,7 +94,12 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
|||||||
// Redirection to main page (maybe 404 instead?)
|
// Redirection to main page (maybe 404 instead?)
|
||||||
(Some(ref path), _) if *req.method() == hyper::method::Method::Get => {
|
(Some(ref path), _) if *req.method() == hyper::method::Method::Get => {
|
||||||
let address = apps::redirection_address(path.using_dapps_domains, self.main_page);
|
let address = apps::redirection_address(path.using_dapps_domains, self.main_page);
|
||||||
Redirection::new(address.as_str())
|
Box::new(ContentHandler::error(
|
||||||
|
StatusCode::NotFound,
|
||||||
|
"404 Not Found",
|
||||||
|
"Requested content was not found on a server.",
|
||||||
|
Some(&format!("Go back to the <a href=\"{}\">Home Page</a>.", address))
|
||||||
|
))
|
||||||
},
|
},
|
||||||
// Redirect any GET request to home.
|
// Redirect any GET request to home.
|
||||||
_ if *req.method() == hyper::method::Method::Get => {
|
_ if *req.method() == hyper::method::Method::Get => {
|
||||||
|
38
dapps/src/tests/fetch.rs
Normal file
38
dapps/src/tests/fetch.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use tests::helpers::{serve_with_registrar, request};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_resolve_dapp() {
|
||||||
|
// given
|
||||||
|
let (server, registrar) = serve_with_registrar();
|
||||||
|
|
||||||
|
// when
|
||||||
|
let response = request(server,
|
||||||
|
"\
|
||||||
|
GET / HTTP/1.1\r\n\
|
||||||
|
Host: 1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d.parity\r\n\
|
||||||
|
Connection: close\r\n\
|
||||||
|
\r\n\
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
|
||||||
|
assert_eq!(registrar.calls.lock().len(), 2);
|
||||||
|
}
|
||||||
|
|
@ -58,22 +58,35 @@ impl ContractClient for FakeRegistrar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_hosts(hosts: Option<Vec<String>>) -> Server {
|
pub fn init_server(hosts: Option<Vec<String>>) -> (Server, Arc<FakeRegistrar>) {
|
||||||
let registrar = Arc::new(FakeRegistrar::new());
|
let registrar = Arc::new(FakeRegistrar::new());
|
||||||
let mut dapps_path = env::temp_dir();
|
let mut dapps_path = env::temp_dir();
|
||||||
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
||||||
let builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar);
|
let builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar.clone());
|
||||||
builder.start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), hosts).unwrap()
|
(
|
||||||
|
builder.start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), hosts).unwrap(),
|
||||||
|
registrar,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_with_auth(user: &str, pass: &str) -> Server {
|
pub fn serve_with_auth(user: &str, pass: &str) -> Server {
|
||||||
let registrar = Arc::new(FakeRegistrar::new());
|
let registrar = Arc::new(FakeRegistrar::new());
|
||||||
let builder = ServerBuilder::new(env::temp_dir().to_str().unwrap().into(), registrar);
|
let mut dapps_path = env::temp_dir();
|
||||||
|
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
||||||
|
let builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar);
|
||||||
builder.start_basic_auth_http(&"127.0.0.1:0".parse().unwrap(), None, user, pass).unwrap()
|
builder.start_basic_auth_http(&"127.0.0.1:0".parse().unwrap(), None, user, pass).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serve_hosts(hosts: Option<Vec<String>>) -> Server {
|
||||||
|
init_server(hosts).0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serve_with_registrar() -> (Server, Arc<FakeRegistrar>) {
|
||||||
|
init_server(None)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serve() -> Server {
|
pub fn serve() -> Server {
|
||||||
serve_hosts(None)
|
init_server(None).0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(server: Server, request: &str) -> http_client::Response {
|
pub fn request(server: Server, request: &str) -> http_client::Response {
|
||||||
|
@ -20,6 +20,7 @@ mod helpers;
|
|||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod authorization;
|
mod authorization;
|
||||||
|
mod fetch;
|
||||||
mod redirection;
|
mod redirection;
|
||||||
mod validation;
|
mod validation;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ fn should_redirect_to_home_when_trailing_slash_is_missing() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_redirect_to_home_on_invalid_dapp() {
|
fn should_display_404_on_invalid_dapp() {
|
||||||
// given
|
// given
|
||||||
let server = serve();
|
let server = serve();
|
||||||
|
|
||||||
@ -72,12 +72,12 @@ fn should_redirect_to_home_on_invalid_dapp() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(response.status, "HTTP/1.1 302 Found".to_owned());
|
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
|
||||||
assert_eq!(response.headers.get(0).unwrap(), "Location: /home/");
|
assert!(response.body.contains("href=\"/home/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_redirect_to_home_on_invalid_dapp_with_domain() {
|
fn should_display_404_on_invalid_dapp_with_domain() {
|
||||||
// given
|
// given
|
||||||
let server = serve();
|
let server = serve();
|
||||||
|
|
||||||
@ -92,8 +92,8 @@ fn should_redirect_to_home_on_invalid_dapp_with_domain() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(response.status, "HTTP/1.1 302 Found".to_owned());
|
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
|
||||||
assert_eq!(response.headers.get(0).unwrap(), "Location: http://home.parity/");
|
assert!(response.body.contains("href=\"http://home.parity/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -18,6 +18,7 @@ use std::sync::Arc;
|
|||||||
use io::PanicHandler;
|
use io::PanicHandler;
|
||||||
use rpc_apis;
|
use rpc_apis;
|
||||||
use ethcore::client::Client;
|
use ethcore::client::Client;
|
||||||
|
use ethsync::SyncProvider;
|
||||||
use helpers::replace_home;
|
use helpers::replace_home;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -49,6 +50,7 @@ pub struct Dependencies {
|
|||||||
pub panic_handler: Arc<PanicHandler>,
|
pub panic_handler: Arc<PanicHandler>,
|
||||||
pub apis: Arc<rpc_apis::Dependencies>,
|
pub apis: Arc<rpc_apis::Dependencies>,
|
||||||
pub client: Arc<Client>,
|
pub client: Arc<Client>,
|
||||||
|
pub sync: Arc<SyncProvider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<WebappServer>, String> {
|
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<WebappServer>, String> {
|
||||||
@ -117,9 +119,12 @@ mod server {
|
|||||||
) -> Result<WebappServer, String> {
|
) -> Result<WebappServer, String> {
|
||||||
use ethcore_dapps as dapps;
|
use ethcore_dapps as dapps;
|
||||||
|
|
||||||
let server = dapps::ServerBuilder::new(dapps_path, Arc::new(Registrar {
|
let mut server = dapps::ServerBuilder::new(
|
||||||
client: deps.client.clone(),
|
dapps_path,
|
||||||
}));
|
Arc::new(Registrar { client: deps.client.clone() })
|
||||||
|
);
|
||||||
|
let sync = deps.sync.clone();
|
||||||
|
server.with_sync_status(Arc::new(move || sync.status().is_major_syncing()));
|
||||||
let server = rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::UnsafeContext);
|
let server = rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::UnsafeContext);
|
||||||
let start_result = match auth {
|
let start_result = match auth {
|
||||||
None => {
|
None => {
|
||||||
|
@ -224,6 +224,7 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
|
|||||||
panic_handler: panic_handler.clone(),
|
panic_handler: panic_handler.clone(),
|
||||||
apis: deps_for_rpc_apis.clone(),
|
apis: deps_for_rpc_apis.clone(),
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
|
sync: sync_provider.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// start dapps server
|
// start dapps server
|
||||||
|
Loading…
Reference in New Issue
Block a user