fix metaRPCClientFactory id handling (#11116)

* fix metaRPCClientFactory id handling
feature/default_network_editable
Shane 4 years ago committed by Dan Miller
parent ce67e1bfcd
commit 0cb0f7c2c2
  1. 26
      app/scripts/lib/metaRPCClientFactory.js
  2. 54
      app/scripts/lib/metaRPCClientFactory.test.js

@ -6,6 +6,7 @@ class MetaRPCClient {
constructor(connectionStream) { constructor(connectionStream) {
this.connectionStream = connectionStream; this.connectionStream = connectionStream;
this.notificationChannel = new SafeEventEmitter(); this.notificationChannel = new SafeEventEmitter();
this.uncaughtErrorChannel = new SafeEventEmitter();
this.requests = new Map(); this.requests = new Map();
this.connectionStream.on('data', this.handleResponse.bind(this)); this.connectionStream.on('data', this.handleResponse.bind(this));
this.connectionStream.on('end', this.close.bind(this)); this.connectionStream.on('end', this.close.bind(this));
@ -17,36 +18,49 @@ class MetaRPCClient {
}); });
} }
onUncaughtError(handler) {
this.uncaughtErrorChannel.addListener('error', (error) => {
handler(error);
});
}
close() { close() {
this.notificationChannel.removeAllListeners(); this.notificationChannel.removeAllListeners();
this.uncaughtErrorChannel.removeAllListeners();
} }
handleResponse(data) { handleResponse(data) {
const { id, result, error, method, params } = data; const { id, result, error, method, params } = data;
const isNotification = id === undefined && error === undefined;
const cb = this.requests.get(id); const cb = this.requests.get(id);
if (method && params && id) { if (method && params && !isNotification) {
// dont handle server-side to client-side requests // dont handle server-side to client-side requests
return; return;
} }
if (method && params && !id) { if (method && params && isNotification) {
// handle servier-side to client-side notification // handle servier-side to client-side notification
this.notificationChannel.emit('notification', data); this.notificationChannel.emit('notification', data);
return; return;
} }
if (!cb) {
// not found in request list
return;
}
if (error) { if (error) {
const e = new EthereumRpcError(error.code, error.message, error.data); const e = new EthereumRpcError(error.code, error.message, error.data);
// preserve the stack from serializeError // preserve the stack from serializeError
e.stack = error.stack; e.stack = error.stack;
if (cb) {
this.requests.delete(id); this.requests.delete(id);
cb(e); cb(e);
return; return;
} }
this.uncaughtErrorChannel.emit('error', e);
return;
}
if (!cb) {
// not found in request list
return;
}
this.requests.delete(id); this.requests.delete(id);

@ -85,4 +85,58 @@ describe('metaRPCClientFactory', function () {
}); });
}); });
}); });
it('should be able to handle notifications', function (done) {
const streamTest = createThoughStream();
const metaRPCClient = metaRPCClientFactory(streamTest);
metaRPCClient.onNotification((notification) => {
assert(notification.method, 'foobarbaz');
done();
});
// send a notification
streamTest.write({
jsonrpc: '2.0',
method: 'foobarbaz',
params: ['bar'],
});
});
it('should be able to handle errors with no id', function (done) {
const streamTest = createThoughStream();
const metaRPCClient = metaRPCClientFactory(streamTest);
metaRPCClient.onUncaughtError((error) => {
assert(error.code, 1);
done();
});
streamTest.write({
jsonrpc: '2.0',
error: {
code: 1,
message: 'error msg',
},
});
});
it('should be able to handle errors with null id', function (done) {
const streamTest = createThoughStream();
const metaRPCClient = metaRPCClientFactory(streamTest);
metaRPCClient.onUncaughtError((error) => {
assert(error.code, 1);
done();
});
streamTest.write({
jsonrpc: '2.0',
id: null,
error: {
code: 1,
message: 'error msg',
},
});
});
}); });

Loading…
Cancel
Save