@liskhq/lisk-api-client
Version:
An API client for the Lisk network
144 lines • 5.38 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WSChannel = exports.RESPONSE_TIMEOUT = exports.CONNECTION_TIMEOUT = void 0;
const WebSocket = require("isomorphic-ws");
const events_1 = require("events");
const utils_1 = require("./utils");
exports.CONNECTION_TIMEOUT = 5000;
exports.RESPONSE_TIMEOUT = 10000;
class WSChannel {
constructor(url) {
this.isAlive = false;
this._requestCounter = 0;
this._pendingRequests = {};
this._url = url;
this._emitter = new events_1.EventEmitter();
}
async connect() {
this._ws = new WebSocket(this._url);
this._ws.onclose = this._handleClose.bind(this);
this._ws.onmessage = this._handleMessage.bind(this);
this._ws.addEventListener('ping', this._handlePing.bind(this));
const connectHandler = new Promise(resolve => {
var _a;
const onOpen = () => {
var _a;
this.isAlive = true;
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.removeEventListener('open', onOpen);
resolve();
};
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.addEventListener('open', onOpen);
});
const errorHandler = new Promise((_, reject) => {
var _a;
const onError = (error) => {
var _a;
this.isAlive = false;
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.removeEventListener('error', onError);
reject(error.error);
};
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.addEventListener('error', onError);
});
try {
await (0, utils_1.promiseWithTimeout)([connectHandler, errorHandler], exports.CONNECTION_TIMEOUT, `Could not connect in ${exports.CONNECTION_TIMEOUT}ms`);
}
catch (err) {
this._ws.close();
throw err;
}
}
async disconnect() {
this._requestCounter = 0;
this._pendingRequests = {};
if (!this._ws) {
return;
}
if (this._ws.readyState === WebSocket.CLOSED) {
this.isAlive = false;
this._ws = undefined;
return;
}
const closeHandler = new Promise(resolve => {
var _a;
const onClose = () => {
var _a;
this.isAlive = false;
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.removeEventListener('close', onClose);
resolve();
};
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.addEventListener('close', onClose);
});
this._ws.close();
await (0, utils_1.promiseWithTimeout)([closeHandler], exports.CONNECTION_TIMEOUT, `Could not disconnect in ${exports.CONNECTION_TIMEOUT}ms`);
}
async invoke(actionName, params) {
var _a;
if (!this.isAlive) {
throw new Error('Websocket client is not connected.');
}
const request = {
jsonrpc: '2.0',
id: this._requestCounter,
method: actionName,
params: params !== null && params !== void 0 ? params : {},
};
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(request));
const response = (0, utils_1.defer)();
this._pendingRequests[this._requestCounter] = response;
this._requestCounter += 1;
return (0, utils_1.promiseWithTimeout)([response.promise], exports.RESPONSE_TIMEOUT, `Response not received in ${exports.RESPONSE_TIMEOUT}ms`);
}
subscribe(eventName, cb) {
var _a;
const request = {
jsonrpc: '2.0',
id: this._requestCounter,
method: 'subscribe',
params: {
topics: [eventName],
},
};
this._requestCounter += 1;
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(request));
this._emitter.on(eventName, cb);
}
unsubscribe(eventName) {
var _a;
const request = {
jsonrpc: '2.0',
id: this._requestCounter,
method: 'unsubscribe',
params: {
topics: [eventName],
},
};
this._requestCounter += 1;
(_a = this._ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(request));
}
_handleClose() {
this.isAlive = false;
}
_handlePing() {
this.isAlive = true;
}
_handleMessage(event) {
const res = JSON.parse(event.data);
if ((0, utils_1.messageIsNotification)(res)) {
this._emitter.emit(res.method, res.params);
}
else {
const id = typeof res.id === 'number' ? res.id : parseInt(res.id, 10);
if (this._pendingRequests[id]) {
if (res.error) {
this._pendingRequests[id].reject((0, utils_1.convertRPCError)(res.error));
}
else {
this._pendingRequests[id].resolve(res.result);
}
delete this._pendingRequests[id];
}
}
}
}
exports.WSChannel = WSChannel;
//# sourceMappingURL=ws_channel.js.map