245 lines
8.4 KiB
JavaScript
245 lines
8.4 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
||
|
|
||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||
|
|
||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||
|
|
||
|
var errors = require('./errors');
|
||
|
var debug = require('debug')('node-telegram-bot-api');
|
||
|
var deprecate = require('depd')('node-telegram-bot-api');
|
||
|
var ANOTHER_WEB_HOOK_USED = 409;
|
||
|
|
||
|
var TelegramBotPolling = function () {
|
||
|
/**
|
||
|
* Handles polling against the Telegram servers.
|
||
|
* @param {TelegramBot} bot
|
||
|
* @see https://core.telegram.org/bots/api#getting-updates
|
||
|
*/
|
||
|
function TelegramBotPolling(bot) {
|
||
|
_classCallCheck(this, TelegramBotPolling);
|
||
|
|
||
|
this.bot = bot;
|
||
|
this.options = typeof bot.options.polling === 'boolean' ? {} : bot.options.polling;
|
||
|
this.options.interval = typeof this.options.interval === 'number' ? this.options.interval : 300;
|
||
|
this.options.params = _typeof(this.options.params) === 'object' ? this.options.params : {};
|
||
|
this.options.params.offset = typeof this.options.params.offset === 'number' ? this.options.params.offset : 0;
|
||
|
this.options.params.timeout = typeof this.options.params.timeout === 'number' ? this.options.params.timeout : 10;
|
||
|
if (typeof this.options.timeout === 'number') {
|
||
|
deprecate('`options.polling.timeout` is deprecated. Use `options.polling.params` instead.');
|
||
|
this.options.params.timeout = this.options.timeout;
|
||
|
}
|
||
|
this._lastUpdate = 0;
|
||
|
this._lastRequest = null;
|
||
|
this._abort = false;
|
||
|
this._pollingTimeout = null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Start polling
|
||
|
* @param {Object} [options]
|
||
|
* @param {Object} [options.restart]
|
||
|
* @return {Promise}
|
||
|
*/
|
||
|
|
||
|
|
||
|
_createClass(TelegramBotPolling, [{
|
||
|
key: 'start',
|
||
|
value: function start() {
|
||
|
var _this = this;
|
||
|
|
||
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||
|
|
||
|
if (this._lastRequest) {
|
||
|
if (!options.restart) {
|
||
|
return Promise.resolve();
|
||
|
}
|
||
|
return this.stop({
|
||
|
cancel: true,
|
||
|
reason: 'Polling restart'
|
||
|
}).then(function () {
|
||
|
return _this._polling();
|
||
|
});
|
||
|
}
|
||
|
return this._polling();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Stop polling
|
||
|
* @param {Object} [options] Options
|
||
|
* @param {Boolean} [options.cancel] Cancel current request
|
||
|
* @param {String} [options.reason] Reason for stopping polling
|
||
|
* @return {Promise}
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: 'stop',
|
||
|
value: function stop() {
|
||
|
var _this2 = this;
|
||
|
|
||
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||
|
|
||
|
if (!this._lastRequest) {
|
||
|
return Promise.resolve();
|
||
|
}
|
||
|
var lastRequest = this._lastRequest;
|
||
|
this._lastRequest = null;
|
||
|
clearTimeout(this._pollingTimeout);
|
||
|
if (options.cancel) {
|
||
|
var reason = options.reason || 'Polling stop';
|
||
|
lastRequest.cancel(reason);
|
||
|
return Promise.resolve();
|
||
|
}
|
||
|
this._abort = true;
|
||
|
return lastRequest.finally(function () {
|
||
|
_this2._abort = false;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return `true` if is polling. Otherwise, `false`.
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: 'isPolling',
|
||
|
value: function isPolling() {
|
||
|
return !!this._lastRequest;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle error thrown during polling.
|
||
|
* @private
|
||
|
* @param {Error} error
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: '_error',
|
||
|
value: function _error(error) {
|
||
|
if (!this.bot.listeners('polling_error').length) {
|
||
|
return console.error('error: [polling_error] %j', error); // eslint-disable-line no-console
|
||
|
}
|
||
|
return this.bot.emit('polling_error', error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Invokes polling (with recursion!)
|
||
|
* @return {Promise} promise of the current request
|
||
|
* @private
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: '_polling',
|
||
|
value: function _polling() {
|
||
|
var _this3 = this;
|
||
|
|
||
|
this._lastRequest = this._getUpdates().then(function (updates) {
|
||
|
_this3._lastUpdate = Date.now();
|
||
|
debug('polling data %j', updates);
|
||
|
updates.forEach(function (update) {
|
||
|
_this3.options.params.offset = update.update_id + 1;
|
||
|
debug('updated offset: %s', _this3.options.params.offset);
|
||
|
try {
|
||
|
_this3.bot.processUpdate(update);
|
||
|
} catch (err) {
|
||
|
err._processing = true;
|
||
|
throw err;
|
||
|
}
|
||
|
});
|
||
|
return null;
|
||
|
}).catch(function (err) {
|
||
|
debug('polling error: %s', err.message);
|
||
|
if (!err._processing) {
|
||
|
return _this3._error(err);
|
||
|
}
|
||
|
delete err._processing;
|
||
|
/*
|
||
|
* An error occured while processing the items,
|
||
|
* i.e. in `this.bot.processUpdate()` above.
|
||
|
* We need to mark the already-processed items
|
||
|
* to avoid fetching them again once the application
|
||
|
* is restarted, or moves to next polling interval
|
||
|
* (in cases where unhandled rejections do not terminate
|
||
|
* the process).
|
||
|
* See https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067
|
||
|
*/
|
||
|
if (!_this3.bot.options.badRejection) {
|
||
|
return _this3._error(err);
|
||
|
}
|
||
|
var opts = {
|
||
|
offset: _this3.options.params.offset,
|
||
|
limit: 1,
|
||
|
timeout: 0
|
||
|
};
|
||
|
return _this3.bot.getUpdates(opts).then(function () {
|
||
|
return _this3._error(err);
|
||
|
}).catch(function (requestErr) {
|
||
|
/*
|
||
|
* We have been unable to handle this error.
|
||
|
* We have to log this to stderr to ensure devops
|
||
|
* understands that they may receive already-processed items
|
||
|
* on app restart.
|
||
|
* We simply can not rescue this situation, emit "error"
|
||
|
* event, with the hope that the application exits.
|
||
|
*/
|
||
|
/* eslint-disable no-console */
|
||
|
var bugUrl = 'https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067';
|
||
|
console.error('error: Internal handling of The Offset Infinite Loop failed');
|
||
|
console.error('error: Due to error \'' + requestErr + '\'');
|
||
|
console.error('error: You may receive already-processed updates on app restart');
|
||
|
console.error('error: Please see ' + bugUrl + ' for more information');
|
||
|
/* eslint-enable no-console */
|
||
|
return _this3.bot.emit('error', new errors.FatalError(err));
|
||
|
});
|
||
|
}).finally(function () {
|
||
|
if (_this3._abort) {
|
||
|
debug('Polling is aborted!');
|
||
|
} else {
|
||
|
debug('setTimeout for %s miliseconds', _this3.options.interval);
|
||
|
_this3._pollingTimeout = setTimeout(function () {
|
||
|
return _this3._polling();
|
||
|
}, _this3.options.interval);
|
||
|
}
|
||
|
});
|
||
|
return this._lastRequest;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unset current webhook. Used when we detect that a webhook has been set
|
||
|
* and we are trying to poll. Polling and WebHook are mutually exclusive.
|
||
|
* @see https://core.telegram.org/bots/api#getting-updates
|
||
|
* @private
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: '_unsetWebHook',
|
||
|
value: function _unsetWebHook() {
|
||
|
debug('unsetting webhook');
|
||
|
return this.bot._request('setWebHook');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve updates
|
||
|
*/
|
||
|
|
||
|
}, {
|
||
|
key: '_getUpdates',
|
||
|
value: function _getUpdates() {
|
||
|
var _this4 = this;
|
||
|
|
||
|
debug('polling with options: %j', this.options.params);
|
||
|
return this.bot.getUpdates(this.options.params).catch(function (err) {
|
||
|
if (err.response && err.response.statusCode === ANOTHER_WEB_HOOK_USED) {
|
||
|
return _this4._unsetWebHook().then(function () {
|
||
|
return _this4.bot.getUpdates(_this4.options.params);
|
||
|
});
|
||
|
}
|
||
|
throw err;
|
||
|
});
|
||
|
}
|
||
|
}]);
|
||
|
|
||
|
return TelegramBotPolling;
|
||
|
}();
|
||
|
|
||
|
module.exports = TelegramBotPolling;
|