UNPKG

lisk-framework

Version:

Lisk blockchain application platform

206 lines 8.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IPCChannel = void 0; const eventemitter2_1 = require("eventemitter2"); const path_1 = require("path"); const request_1 = require("../request"); const event_1 = require("../event"); const base_channel_1 = require("./base_channel"); const ipc_client_1 = require("../ipc/ipc_client"); const types_1 = require("../../types"); const constants_1 = require("../constants"); class IPCChannel extends base_channel_1.BaseChannel { constructor(logger, namespace, events, endpoints, chainID, options) { super(logger, namespace, events, endpoints); this._chainID = chainID; this._ipcClient = new ipc_client_1.IPCClient({ socketsDir: options.socketsPath, name: namespace, rpcServerSocketPath: `ipc://${(0, path_1.join)(options.socketsPath, 'bus.internal.rpc.ipc')}`, }); this._rpcRequestIds = new Set(); this._emitter = new eventemitter2_1.EventEmitter2({ wildcard: true, delimiter: ':', maxListeners: 1000, }); } async startAndListen() { await this._ipcClient.start(); this._subSocket.subscribe(constants_1.IPC_EVENTS.RPC_EVENT); const listenToMessages = async () => { for await (const [_event, eventData] of this._subSocket) { const eventDataJSON = event_1.Event.fromJSONRPCNotification(JSON.parse(eventData.toString())); this._emitter.emit(eventDataJSON.key(), eventDataJSON.toJSONRPCNotification()); } }; listenToMessages().catch(error => { throw error; }); const listenToRPC = async () => { for await (const [sender, event, eventData] of this._rpcServer) { if (event.toString() === constants_1.IPC_EVENTS.RPC_EVENT) { const request = request_1.Request.fromJSONRPCRequest(JSON.parse(eventData.toString())); if (request.namespace === this.namespace) { this.invoke({ methodName: request.key(), context: {}, params: request.params, }) .then(result => { this._rpcServer .send([ sender, String(request.id), JSON.stringify(request.buildJSONRPCResponse({ result })), ]) .catch(error => { this._logger.error({ err: error }, 'Fail to send success response'); }); }) .catch(error => { this._rpcServer .send([ sender, String(request.id), JSON.stringify(request.buildJSONRPCResponse({ error: { code: -32600, message: error.message }, })), ]) .catch(err => { this._logger.error({ err: err }, 'Fail to send error response'); }); }); } continue; } } }; listenToRPC().catch(error => { throw error; }); const listenToRPCResponse = async () => { for await (const [requestId, result] of this._rpcClient) { if (this._rpcRequestIds.has(requestId.toString())) { this._emitter.emit(requestId.toString(), JSON.parse(result.toString())); continue; } } }; listenToRPCResponse().catch(error => { throw error; }); } async registerToBus() { await this.startAndListen(); let endpointInfo = {}; endpointInfo = Array.from(this.endpointHandlers.keys()).reduce((accumulator, value) => { accumulator[value] = { method: value, namespace: this.namespace, }; return accumulator; }, endpointInfo); const registerObj = { moduleName: this.namespace, eventsList: this.eventsList.map((event) => event), endpointInfo, options: { type: types_1.ChannelType.ChildProcess, socketPath: this._ipcClient.socketPaths.rpcServer, }, }; this._rpcClient .send([constants_1.IPC_EVENTS.REGISTER_CHANNEL, JSON.stringify(registerObj)]) .catch(error => { throw error; }); } subscribe(eventName, cb) { const event = new event_1.Event(eventName); this._subSocket.subscribe(eventName); this._emitter.on(event.key(), (notification) => setImmediate(cb, event_1.Event.fromJSONRPCNotification(notification).data)); } unsubscribe(eventName, cb) { this._subSocket.unsubscribe(eventName); this._emitter.off(eventName, cb); } once(eventName, cb) { const event = new event_1.Event(eventName); this._subSocket.subscribe(eventName); this._emitter.once(event.key(), (notification) => { setImmediate(cb, event_1.Event.fromJSONRPCNotification(notification).data); }); } publish(eventName, data) { const event = new event_1.Event(eventName, data); if (event.module !== this.namespace || !this.eventsList.includes(event.name)) { throw new Error(`Event "${eventName}" not registered in "${this.namespace}" module.`); } this._pubSocket .send([event.key(), JSON.stringify(event.toJSONRPCNotification())]) .catch(error => { throw error; }); } async invoke(req) { var _a; const request = new request_1.Request(this._getNextRequestId(), req.methodName, req.params); if (request.namespace === this.namespace) { const handler = this.endpointHandlers.get(request.name); if (!handler) { throw new Error(`The action '${request.name}' on module '${this.namespace}' does not exist.`); } return handler({ getStore: () => { throw new Error('getStore cannot be called on IPC channel'); }, getImmutableMethodContext: () => { throw new Error('getImmutableMethodContext cannot be called on IPC channel'); }, header: req.context.header, params: (_a = request.params) !== null && _a !== void 0 ? _a : {}, getOffchainStore: () => { throw new Error('getOffchainStore cannot be called on IPC channel'); }, chainID: this._chainID, logger: this._logger, }); } return new Promise((resolve, reject) => { this._rpcRequestIds.add(request.id); this._rpcClient .send(['invoke', JSON.stringify(request.toJSONRPCRequest())]) .then(_ => { const requestTimeout = setTimeout(() => { reject(new Error('Request timed out on invoke.')); }, constants_1.IPC_EVENTS.RPC_REQUEST_TIMEOUT); this._emitter.once(request.id, (response) => { clearTimeout(requestTimeout); this._rpcRequestIds.delete(request.id); return resolve(response.result); }); }) .catch(error => { throw error; }); }); } cleanup(_status, _message) { this._ipcClient.stop(); } get _pubSocket() { return this._ipcClient.pubSocket; } get _subSocket() { return this._ipcClient.subSocket; } get _rpcServer() { return this._ipcClient.rpcServer; } get _rpcClient() { return this._ipcClient.rpcClient; } } exports.IPCChannel = IPCChannel; //# sourceMappingURL=ipc_channel.js.map