lisk-framework
Version:
Lisk blockchain application platform
206 lines • 8.48 kB
JavaScript
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
;