bot18
Version:
A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f
131 lines • 6.12 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require("./");
const EventEmitter = require("eventemitter3"); // tslint:disable-line:import-name no-require-imports
const logger_1 = require("./logger");
const errors_1 = require("./errors");
const pkg = require('../package.json'); // tslint:disable-line:no-require-imports no-var-requires
/**
* An object that monitors activity in an RTMClient and generates ping events in an effort to keep its websocket
* connection alive. In cases where the websocket connection seems unresponsive, this object emits a
* `recommend_reconnect` event. That event should be handled by tearing down the websocket connection and
* opening a new one.
*/
class KeepAlive extends EventEmitter {
constructor({ clientPingTimeout = 6000, serverPongTimeout = 4000, logger = undefined, logLevel = logger_1.LogLevel.INFO, } = {}) {
super();
this.clientPingTimeout = clientPingTimeout;
this.serverPongTimeout = serverPongTimeout;
if (this.serverPongTimeout >= this.clientPingTimeout) {
throw errors_1.errorWithCode(new Error('client ping timeout must be less than server pong timeout'), _1.ErrorCode.KeepAliveConfigError);
}
// Logging
if (logger !== undefined) {
this.logger = logger_1.loggerFromLoggingFunc(KeepAlive.loggerName, logger);
}
else {
this.logger = logger_1.getLogger(KeepAlive.loggerName);
}
this.logger.setLevel(logLevel);
}
/**
* Start monitoring the RTMClient. This method should only be called after the client's websocket is already open.
* @param client
*/
start(client) {
if (!client.connected) {
throw errors_1.errorWithCode(new Error(), _1.ErrorCode.KeepAliveClientNotConnected);
}
this.client = client;
this.isMonitoring = true;
this.client.on('outgoing_message', this.setPingTimer, this);
this.setPingTimer();
}
/**
* Stop monitoring the RTMClient. This method should be called after the `recommend_reconnect` event is emitted and
* the client's weboscket is closed. In order to start monitoring the client again, start() needs to be called again
* after that.
*/
stop() {
this.clearPreviousPingTimer();
this.lastPing = this.client = undefined;
this.recommendReconnect = this.isMonitoring = false;
}
/**
* Clears the ping timer if its set, otherwise this is a noop.
*/
clearPreviousPingTimer() {
if (this.pingTimer !== undefined) {
clearTimeout(this.pingTimer);
delete this.pingTimer;
}
}
/**
* Sets the ping timer (including clearing any previous one).
*/
setPingTimer() {
// if there's already an unacknowledged ping, we don't need to set up a timer for another to be sent
if (this.lastPing !== undefined) {
return;
}
this.logger.debug('setting ping timer');
this.clearPreviousPingTimer();
this.pingTimer = setTimeout(this.sendPing.bind(this), this.clientPingTimeout);
}
/**
* Sends a ping and manages the timer to wait for a pong.
*/
sendPing() {
try {
if (this.client === undefined) {
throw errors_1.errorWithCode(new Error('no client found'), _1.ErrorCode.KeepAliveInconsistentState);
}
this.logger.debug('ping timer expired, sending ping');
this.client.send('ping')
.then((messageId) => {
if (this.client === undefined) {
throw errors_1.errorWithCode(new Error('no client found'), _1.ErrorCode.KeepAliveInconsistentState);
}
this.lastPing = messageId;
const attemptAcknowledgePong = function (_type, event) {
if (this.client === undefined) {
throw errors_1.errorWithCode(new Error('no client found'), _1.ErrorCode.KeepAliveInconsistentState);
}
if (this.lastPing !== undefined && event.reply_to !== undefined && event.reply_to >= this.lastPing) {
// this message is a reply that acks the previous ping, clear the last ping
this.logger.debug('received pong, clearing pong timer');
delete this.lastPing;
// signal that this pong is done being handled
clearTimeout(pongTimer);
this.client.off('slack_event', attemptAcknowledgePong);
}
};
this.logger.debug('setting pong timer');
const pongTimer = setTimeout(() => {
if (this.client === undefined) {
throw errors_1.errorWithCode(new Error('no client found'), _1.ErrorCode.KeepAliveInconsistentState);
}
// signal that this pong is done being handled
this.client.off('slack_event', attemptAcknowledgePong);
// no pong received to acknowledge the last ping within the serverPongTimeout
this.logger.debug('pong timer expired, recommend reconnect');
this.recommendReconnect = true;
this.emit('recommend_reconnect');
}, this.serverPongTimeout);
this.client.on('slack_event', attemptAcknowledgePong, this);
})
.catch((error) => {
this.logger.error(`Unhandled error: ${error.message}. Please report to /client package maintainers.`);
});
}
catch (error) {
this.logger.error(`Unhandled error: ${error.message}. Please report to /client package maintainers.`);
}
}
}
/**
* The name used to prefix all logging generated from this object
*/
KeepAlive.loggerName = `${pkg.name}:KeepAlive`;
exports.KeepAlive = KeepAlive;
//# sourceMappingURL=KeepAlive.js.map