diff --git a/js/src/api/api.js b/js/src/api/api.js
index cb86cde66..28dae19d1 100644
--- a/js/src/api/api.js
+++ b/js/src/api/api.js
@@ -17,8 +17,8 @@
import EventEmitter from 'eventemitter3';
import Contract from './contract';
-import { PromiseProvider, Http as HttpProvider, PostMessage as PostMessageProvider, WsSecure as WsSecureProvider } from './provider';
-import { Http as HttpTransport, WsSecure as WsSecureTransport } from './transport';
+import { PromiseProvider, Http as HttpProvider, PostMessage as PostMessageProvider, Ws as WsProvider } from './provider';
+import { Http as HttpTransport, Ws as WsTransport } from './transport';
import { Db, Eth, Parity, Net, Personal, Shell, Shh, Signer, Trace, Web3 } from './rpc';
import Subscriptions from './subscriptions';
@@ -36,7 +36,6 @@ export default class Api extends EventEmitter {
console.log(provider);
console.warn(new Error('deprecated: Api needs provider with send() function, old-style Transport found instead'));
}
-
// does use new provider interface (not promiseProvider)
if (provider && isFunction(provider.subscribe)) {
this._pubsub = new Pubsub(provider);
@@ -187,12 +186,12 @@ export default class Api extends EventEmitter {
static Provider = {
Http: HttpProvider,
PostMessage: PostMessageProvider,
- WsSecure: WsSecureProvider
+ Ws: WsProvider
}
// NOTE: kept for backwards compatibility
static Transport = {
Http: HttpTransport,
- WsSecure: WsSecureTransport
+ Ws: WsTransport
}
}
diff --git a/js/src/api/provider/index.js b/js/src/api/provider/index.js
index acad6b14f..06de8cd70 100644
--- a/js/src/api/provider/index.js
+++ b/js/src/api/provider/index.js
@@ -18,4 +18,4 @@ export PromiseProvider from './promise';
export Http from './http';
export PostMessage from './postMessage';
-export WsSecure from './wsSecure';
+export Ws from './ws';
diff --git a/js/src/api/provider/postMessage.js b/js/src/api/provider/postMessage.js
index 3d7eec1ea..86d2d031f 100644
--- a/js/src/api/provider/postMessage.js
+++ b/js/src/api/provider/postMessage.js
@@ -16,7 +16,7 @@
export default class PostMessage {
id = 0;
- _callbacks = {};
+ _messages = {};
constructor (token, destination) {
this._token = token;
@@ -28,17 +28,55 @@ export default class PostMessage {
addMiddleware () {
}
+ _send (data) {
+ this._destination.postMessage(data, '*');
+ }
+
send = (method, params, callback) => {
const id = ++this.id;
- this._callbacks[id] = callback;
- this._destination.postMessage({
+ this._messages[id] = { callback };
+ this._send({
id,
from: this._token,
method,
params,
token: this._token
- }, '*');
+ });
+ }
+
+ subscribe = (api, callback, params) => {
+ console.log('paritySubscribe', JSON.stringify(params), api, callback);
+ return new Promise((resolve, reject) => {
+ const id = ++this.id;
+
+ this._messages[id] = { callback, resolve, reject, subscription: true, initial: true };
+ this._send({
+ id,
+ from: this._token,
+ api,
+ params,
+ token: this._token
+ });
+ });
+ }
+
+ unsubscribe = (subId) => {
+ return new Promise((resolve, reject) => {
+ const id = ++this.id;
+
+ this._messages[id] = { callback: (e, v) => e ? reject(e) : resolve(v) };
+ this._send({
+ id,
+ from: this._token,
+ subId,
+ token: this._token
+ });
+ });
+ }
+
+ unsubscribeAll () {
+ return this.unsubscribe('*');
}
receiveMessage = ({ data: { id, error, from, token, result }, origin, source }) => {
@@ -50,7 +88,13 @@ export default class PostMessage {
console.error(from, error);
}
- this._callbacks[id](error && new Error(error), result);
- this._callbacks[id] = null;
+ if (this._messages[id].subscription) {
+ console.log('subscription', result, 'initial?', this._messages[id].initial);
+ this._messages[id].initial ? this._messages[id].resolve(result) : this._messages[id].callback(error && new Error(error), result);
+ this._messages[id].initial = false;
+ } else {
+ this._messages[id].callback(error && new Error(error), result);
+ this._messages[id] = null;
+ }
}
}
diff --git a/js/src/api/provider/wsSecure.js b/js/src/api/provider/ws.js
similarity index 89%
rename from js/src/api/provider/wsSecure.js
rename to js/src/api/provider/ws.js
index 91b9e932f..2a399d309 100644
--- a/js/src/api/provider/wsSecure.js
+++ b/js/src/api/provider/ws.js
@@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-import { WsSecure as Transport } from '../transport';
+import { Ws as Transport } from '../transport';
-export default class WsSecure extends Transport {
+export default class Ws extends Transport {
send = (method, params, callback) => {
this
._execute(method, params)
diff --git a/js/src/api/pubsub/pubsubBase.js b/js/src/api/pubsub/pubsubBase.js
index 75e56a0ff..e2a43e4c0 100644
--- a/js/src/api/pubsub/pubsubBase.js
+++ b/js/src/api/pubsub/pubsubBase.js
@@ -20,11 +20,11 @@ export default class PubsubBase {
this._provider = provider;
}
- addListener (module, eventName, callback, eventParams) {
+ addListener (module, eventName, handler, eventParams) {
return eventParams
- ? this._provider.subscribe(module, callback, [eventName, eventParams])
- : this._provider.subscribe(module, callback, [eventName, []]);
- // this._transport.subscribe(module, callback, eventName); After Patch from tomac is merged to master! => eth_subscribe does not support empty array as params
+ ? this._provider.subscribe(module, handler, [eventName, eventParams])
+ : this._provider.subscribe(module, handler, [eventName, []]);
+ // this._transport.subscribe(module, handler, eventName); After Patch from tomac is merged to master! => eth_subscribe does not support empty array as params
}
removeListener (subscriptionIds) {
diff --git a/js/src/api/rpc/trace/trace.js b/js/src/api/rpc/trace/trace.js
index 95e6b4efe..f9c4d2757 100644
--- a/js/src/api/rpc/trace/trace.js
+++ b/js/src/api/rpc/trace/trace.js
@@ -29,8 +29,8 @@ export default class Trace {
}
call (options, whatTrace = ['trace'], blockNumber = 'latest') {
- return this._transport
- .execute('trace_call', inOptions(options), inTraceType(whatTrace), inBlockNumber(blockNumber))
+ return this._provider
+ .send('trace_call', inOptions(options), inTraceType(whatTrace), inBlockNumber(blockNumber))
.then(outTraceReplay);
}
diff --git a/js/src/api/transport/index.js b/js/src/api/transport/index.js
index d9a91ab77..fdd3861a8 100644
--- a/js/src/api/transport/index.js
+++ b/js/src/api/transport/index.js
@@ -15,6 +15,6 @@
// along with Parity. If not, see .
export Http from './http';
-export WsSecure from './wsSecure';
+export Ws from './ws';
export TransportError from './error';
export Middleware from './middleware';
diff --git a/js/src/api/transport/wsSecure/index.js b/js/src/api/transport/ws/index.js
similarity index 95%
rename from js/src/api/transport/wsSecure/index.js
rename to js/src/api/transport/ws/index.js
index 427c76dc8..7ab0be131 100644
--- a/js/src/api/transport/wsSecure/index.js
+++ b/js/src/api/transport/ws/index.js
@@ -14,4 +14,4 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-export default from './wsSecure';
+export default from './ws';
diff --git a/js/src/api/transport/wsSecure/wsSecure.e2e.js b/js/src/api/transport/ws/ws.e2e.js
similarity index 92%
rename from js/src/api/transport/wsSecure/wsSecure.e2e.js
rename to js/src/api/transport/ws/ws.e2e.js
index 537afa5f9..92e06d915 100644
--- a/js/src/api/transport/wsSecure/wsSecure.e2e.js
+++ b/js/src/api/transport/ws/ws.e2e.js
@@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-import WsSecure from './wsSecure';
+import Ws from './ws';
-const ws = new WsSecure('ws://localhost:8546/');
+const ws = new Ws('ws://localhost:8546/');
describe('transport/WsSecure', () => {
it('connects and makes a call to web3_clientVersion', () => {
diff --git a/js/src/api/transport/wsSecure/wsSecure.js b/js/src/api/transport/ws/ws.js
similarity index 96%
rename from js/src/api/transport/wsSecure/wsSecure.js
rename to js/src/api/transport/ws/ws.js
index 1e1d64d6b..b93adc54f 100644
--- a/js/src/api/transport/wsSecure/wsSecure.js
+++ b/js/src/api/transport/ws/ws.js
@@ -21,7 +21,7 @@ import JsonRpcBase from '../jsonRpcBase';
import TransportError from '../error';
/* global WebSocket */
-export default class WsSecure extends JsonRpcBase {
+export default class Ws extends JsonRpcBase {
// token is optional (secure API)
constructor (url, token = null, autoconnect = true) {
super();
@@ -321,6 +321,16 @@ export default class WsSecure extends JsonRpcBase {
});
}
+ unsubscribeAll () {
+ return new Promise((resolve, reject) => {
+ var unsubscribed = 0;
+ let keys = Object.keys(this._messages);
+
+ keys.forEach(i => this._messages[i].subscription ? this.unsubscribe(this._messages[i].subId).then(_ => unsubscribed++, reject) : null);
+ resolve(unsubscribed);
+ });
+ }
+
unsubscribe (messageId) {
return new Promise((resolve, reject) => {
const id = this.id;
diff --git a/js/src/api/transport/wsSecure/wsSecure.spec.js b/js/src/api/transport/ws/ws.spec.js
similarity index 92%
rename from js/src/api/transport/wsSecure/wsSecure.spec.js
rename to js/src/api/transport/ws/ws.spec.js
index 40a2212fa..603c16c58 100644
--- a/js/src/api/transport/wsSecure/wsSecure.spec.js
+++ b/js/src/api/transport/ws/ws.spec.js
@@ -15,16 +15,16 @@
// along with Parity. If not, see .
import { TEST_WS_URL, mockWs } from '../../../../test/mockRpc';
-import WsSecure from './wsSecure';
+import Ws from './ws';
-describe('api/transport/WsSecure', () => {
+describe('api/transport/ws', () => {
let transport;
let scope;
describe('transport emitter', () => {
const connect = () => {
const scope = mockWs();
- const transport = new WsSecure(TEST_WS_URL);
+ const transport = new Ws(TEST_WS_URL);
return { transport, scope };
};
@@ -57,7 +57,7 @@ describe('api/transport/WsSecure', () => {
beforeEach(() => {
scope = mockWs([{ method: 'test_anyCall', reply: 'TestResult' }]);
- transport = new WsSecure(TEST_WS_URL);
+ transport = new Ws(TEST_WS_URL);
return transport
.execute('test_anyCall', [1, 2, 3])
@@ -98,7 +98,7 @@ describe('api/transport/WsSecure', () => {
describe('errors', () => {
beforeEach(() => {
scope = mockWs([{ method: 'test_anyCall', reply: { error: { code: 1, message: 'TestError' } } }]);
- transport = new WsSecure(TEST_WS_URL);
+ transport = new Ws(TEST_WS_URL);
});
afterEach(() => {
diff --git a/js/src/secureApi.js b/js/src/secureApi.js
index 976d5e5fd..b16217779 100644
--- a/js/src/secureApi.js
+++ b/js/src/secureApi.js
@@ -35,7 +35,7 @@ export default class SecureApi extends Api {
static getTransport (url, sysuiToken, protocol) {
const transportUrl = SecureApi.transportUrl(url, protocol);
- return new Api.Provider.WsSecure(transportUrl, sysuiToken, false);
+ return new Api.Provider.Ws(transportUrl, sysuiToken, false);
}
static transportUrl (url, protocol) {
diff --git a/js/src/shell/DappRequests/store.js b/js/src/shell/DappRequests/store.js
index 272ed3f1b..e6082dd52 100644
--- a/js/src/shell/DappRequests/store.js
+++ b/js/src/shell/DappRequests/store.js
@@ -91,16 +91,20 @@ export default class Store {
@action approveSingleRequest = ({ queueId, request: { data, source } }) => {
this.removeRequest(queueId);
- this.executeMethodCall(data, source);
+ if (data.api) {
+ this.executePubsubCall(data, source);
+ } else {
+ this.executeMethodCall(data, source);
+ }
}
@action approveRequest = (queueId, approveAll) => {
const queued = this.findRequest(queueId);
if (approveAll) {
- const { request: { data: { method, token } } } = queued;
+ const { request: { data: { method, token, params } } } = queued;
- this.getFilteredSection(method).methods.forEach((m) => {
+ this.getFilteredSection(method || params[0]).methods.forEach((m) => {
this.addTokenPermission(m, token);
this.findMatchingRequests(m, token).forEach(this.approveSingleRequest);
});
@@ -152,7 +156,7 @@ export default class Store {
}
findMatchingRequests (_method, _token) {
- return this.requests.filter(({ request: { data: { method, token } } }) => method === _method && token === _token);
+ return this.requests.filter(({ request: { data: { method, token, params } } }) => (method === _method || (params && params[0] === _method)) && token === _token);
}
_methodCallbackPost = (id, source, token) => {
@@ -169,6 +173,16 @@ export default class Store {
};
}
+ executePubsubCall = ({ api, id, token, params }, source) => {
+ const callback = this._methodCallbackPost(id, source, token);
+
+ // TODO: enable security pubsub
+ this.provider.subscribe(api, callback, params).then((v, e) => {
+ console.log('Error and result', v, e);
+ this._methodCallbackPost(id, source, token)(null, v);
+ });
+ }
+
executeMethodCall = ({ id, from, method, params, token }, source) => {
const visibleStore = VisibleStore.get();
const callback = this._methodCallbackPost(id, source, token);
@@ -225,18 +239,27 @@ export default class Store {
return;
}
- const { from, method, token } = data;
+ const { from, method, token, params, api, subId, id } = data;
if (!from || from === 'shell' || from !== token) {
return;
}
- if (this.getFilteredSection(method) && !this.hasTokenPermission(method, token)) {
+ if ((method && this.getFilteredSection(method) && !this.hasTokenPermission(method, token)) ||
+ (api && this.getFilteredSection(params[0]) && !this.hasTokenPermission(method, token))) {
this.queueRequest({ data, origin, source });
return;
}
-
- this.executeMethodCall(data, source);
+ if (api) {
+ console.log('apiCall', data);
+ this.executePubsubCall(data, source);
+ } else if (subId) {
+ subId === '*'
+ ? this.provider.unsubscribeAll().then(v => this._methodCallbackPost(id, source, token)(null, v))
+ : this.provider.unsubscribe(subId).then(v => this._methodCallbackPost(id, source, token)(null, v));
+ } else {
+ this.executeMethodCall(data, source);
+ }
}
static instance = null;
diff --git a/js/src/shell/index.js b/js/src/shell/index.js
index fca92633c..54fba1507 100644
--- a/js/src/shell/index.js
+++ b/js/src/shell/index.js
@@ -27,6 +27,7 @@ import { IndexRoute, Redirect, Route, Router, hashHistory } from 'react-router';
import qs from 'querystring';
import Api from '@parity/api';
+import Abi from '@parity/abi';
import builtinDapps from '@parity/shared/config/dappsBuiltin.json';
import viewsDapps from '@parity/shared/config/dappsViews.json';
import ContractInstances from '@parity/shared/contracts';
@@ -80,6 +81,13 @@ const dappsHistory = HistoryStore.get('dapps');
function onEnterDapp ({ params: { id } }) {
const token = DappRequestsStore.get().createToken(id);
+ // on app switch unsubscribe all subscriptions
+ if (window.ethereum) {
+ window.ethereum.unsubscribeAll();
+ }
+ // old API uses window.parity
+ window.parity = { Api, Abi };
+
window.ethereum = new Api.Provider.PostMessage(token, window);
if (!dapps[id] || !dapps[id].skipHistory) {