1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-26 12:29:06 +01:00
metamask-extension/app/scripts/lib/metaRPCClientFactory.js
Shane abba7f4159
fix metaRPCClientFactory id handling (#11116)
* fix metaRPCClientFactory id handling
2021-05-17 14:46:00 -07:00

96 lines
2.5 KiB
JavaScript

import { EthereumRpcError } from 'eth-rpc-errors';
import SafeEventEmitter from 'safe-event-emitter';
import createRandomId from '../../../shared/modules/random-id';
class MetaRPCClient {
constructor(connectionStream) {
this.connectionStream = connectionStream;
this.notificationChannel = new SafeEventEmitter();
this.uncaughtErrorChannel = new SafeEventEmitter();
this.requests = new Map();
this.connectionStream.on('data', this.handleResponse.bind(this));
this.connectionStream.on('end', this.close.bind(this));
}
onNotification(handler) {
this.notificationChannel.addListener('notification', (data) => {
handler(data);
});
}
onUncaughtError(handler) {
this.uncaughtErrorChannel.addListener('error', (error) => {
handler(error);
});
}
close() {
this.notificationChannel.removeAllListeners();
this.uncaughtErrorChannel.removeAllListeners();
}
handleResponse(data) {
const { id, result, error, method, params } = data;
const isNotification = id === undefined && error === undefined;
const cb = this.requests.get(id);
if (method && params && !isNotification) {
// dont handle server-side to client-side requests
return;
}
if (method && params && isNotification) {
// handle servier-side to client-side notification
this.notificationChannel.emit('notification', data);
return;
}
if (error) {
const e = new EthereumRpcError(error.code, error.message, error.data);
// preserve the stack from serializeError
e.stack = error.stack;
if (cb) {
this.requests.delete(id);
cb(e);
return;
}
this.uncaughtErrorChannel.emit('error', e);
return;
}
if (!cb) {
// not found in request list
return;
}
this.requests.delete(id);
cb(null, result);
}
}
const metaRPCClientFactory = (connectionStream) => {
const metaRPCClient = new MetaRPCClient(connectionStream);
return new Proxy(metaRPCClient, {
get: (object, property) => {
if (object[property]) {
return object[property];
}
return (...p) => {
const cb = p[p.length - 1];
const params = p.slice(0, -1);
const id = createRandomId();
object.requests.set(id, cb);
object.connectionStream.write({
jsonrpc: '2.0',
method: property,
params,
id,
});
};
},
});
};
export default metaRPCClientFactory;