[webhook,polling] Improve starting, stopping of webhook, polling

Feature:

  The different mechanisms of fetching updates, i.e. polling
  and webhook, have had their implementations improved:

  * the TelegramBot instance needs to create the polling and
    webhook instances once, and when necessary
  * returning promises from TelegramBot#openWebHook() and
    TelegramBot#startPolling() allows more precise control

  Also,

  * TelegramBot#initPolling() is being deprecated in favor of
    TelegramBot#startPolling() to ensure consistency (as the
    opposite action of TelegramBot#stopPolling())
experimental
GochoMugo 9 years ago
parent 4735518116
commit 97c8130d93
No known key found for this signature in database
GPG Key ID: 7B6A01CB57AA39E4
  1. 41
      README.md
  2. 63
      src/telegram.js
  3. 49
      src/telegramPolling.js
  4. 53
      src/telegramWebHook.js
  5. 12
      test/telegram.js

@ -71,10 +71,11 @@ TelegramBot
* [TelegramBot](#TelegramBot)
* [new TelegramBot(token, [options])](#new_TelegramBot_new)
* [.initPolling()](#TelegramBot+initPolling)
* [.startPolling([options])](#TelegramBot+startPolling) ⇒ <code>Promise</code>
* ~~[.initPolling([options])](#TelegramBot+initPolling) ⇒ <code>Promise</code>~~
* [.stopPolling()](#TelegramBot+stopPolling) ⇒ <code>Promise</code>
* [.isPolling()](#TelegramBot+isPolling) ⇒ <code>Boolean</code>
* [.openWebHook()](#TelegramBot+openWebHook)
* [.openWebHook()](#TelegramBot+openWebHook)<code>Promise</code>
* [.closeWebHook()](#TelegramBot+closeWebHook) ⇒ <code>Promise</code>
* [.hasOpenWebHook()](#TelegramBot+hasOpenWebHook) ⇒ <code>Boolean</code>
* [.getMe()](#TelegramBot+getMe) ⇒ <code>Promise</code>
@ -144,19 +145,39 @@ Emits `message` when a message arrives.
| [options.request] | <code>Object</code> | | Options which will be added for all requests to telegram api. See https://github.com/request/request#requestoptions-callback for more information. |
| [options.baseApiUrl] | <code>String</code> | <code>https://api.telegram.org</code> | API Base URl; useful for proxying and testing |
<a name="TelegramBot+startPolling"></a>
### telegramBot.startPolling([options]) ⇒ <code>Promise</code>
Start polling.
**Kind**: instance method of <code>[TelegramBot](#TelegramBot)</code>
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [options] | <code>Object</code> | | |
| [options.restart] | <code>Boolean</code> | <code>true</code> | Consecutive calls to this method causes polling to be restarted |
<a name="TelegramBot+initPolling"></a>
### telegramBot.initPolling()
Start polling
### ~~telegramBot.initPolling([options]) ⇒ <code>Promise</code>~~
***Deprecated***
Alias of `TelegramBot#startPolling()`. This is **deprecated**.
**Kind**: instance method of <code>[TelegramBot](#TelegramBot)</code>
| Param | Type |
| --- | --- |
| [options] | <code>Object</code> |
<a name="TelegramBot+stopPolling"></a>
### telegramBot.stopPolling() ⇒ <code>Promise</code>
Stops polling after the last polling request resolves
Stops polling after the last polling request resolves.
Multiple invocations do nothing if polling is already stopped.
Returning the promise of the last polling request is **deprecated**.
**Kind**: instance method of <code>[TelegramBot](#TelegramBot)</code>
**Returns**: <code>Promise</code> - promise Promise, of last polling request
<a name="TelegramBot+isPolling"></a>
### telegramBot.isPolling() ⇒ <code>Boolean</code>
@ -165,14 +186,16 @@ Return true if polling. Otherwise, false.
**Kind**: instance method of <code>[TelegramBot](#TelegramBot)</code>
<a name="TelegramBot+openWebHook"></a>
### telegramBot.openWebHook()
Open webhook
### telegramBot.openWebHook() ⇒ <code>Promise</code>
Open webhook.
Multiple invocations do nothing if webhook is already open.
**Kind**: instance method of <code>[TelegramBot](#TelegramBot)</code>
<a name="TelegramBot+closeWebHook"></a>
### telegramBot.closeWebHook() ⇒ <code>Promise</code>
Close webhook after closing all current connections
Close webhook after closing all current connections.
Multiple invocations do nothing if webhook is already closed.
**Kind**: instance method of <code>[TelegramBot](#TelegramBot)</code>
**Returns**: <code>Promise</code> - promise

@ -72,11 +72,13 @@ class TelegramBot extends EventEmitter {
this.options.baseApiUrl = options.baseApiUrl || 'https://api.telegram.org';
this._textRegexpCallbacks = [];
this._onReplyToMessages = [];
this._polling = null;
this._webHook = null;
if (options.polling) {
const autoStart = options.polling.autoStart;
if (typeof autoStart === 'undefined' || autoStart === true) {
this.initPolling();
this.startPolling();
}
}
@ -223,29 +225,41 @@ class TelegramBot extends EventEmitter {
}
/**
* Start polling
* Start polling.
* @param {Object} [options]
* @param {Boolean} [options.restart=true] Consecutive calls to this method causes polling to be restarted
* @return {Promise}
*/
initPolling() {
if (this._polling) {
this._polling.stopPolling({
cancel: true,
reason: 'Polling restart',
});
startPolling(options = {}) {
options.restart = typeof options.restart === 'undefined' ? true : options.restart;
if (!this._polling) {
this._polling = new TelegramBotPolling(this._request.bind(this), this.options.polling, this.processUpdate.bind(this));
}
this._polling = new TelegramBotPolling(this._request.bind(this), this.options.polling, this.processUpdate.bind(this));
return this._polling.start(options);
}
/**
* Stops polling after the last polling request resolves
* @return {Promise} promise Promise, of last polling request
* Alias of `TelegramBot#startPolling()`. This is **deprecated**.
* @param {Object} [options]
* @return {Promise}
* @deprecated
*/
initPolling() {
deprecate('TelegramBot#initPolling() is deprecated');
return this.startPolling();
}
/**
* Stops polling after the last polling request resolves.
* Multiple invocations do nothing if polling is already stopped.
* Returning the promise of the last polling request is **deprecated**.
* @return {Promise}
*/
stopPolling() {
if (!this._polling) {
return Promise.resolve();
}
const polling = this._polling;
delete this._polling;
return polling.stopPolling();
return this._polling.stop();
}
/**
@ -253,30 +267,31 @@ class TelegramBot extends EventEmitter {
* @return {Boolean}
*/
isPolling() {
return !!this._polling;
return this._polling ? this._polling.isPolling() : false;
}
/**
* Open webhook
* Open webhook.
* Multiple invocations do nothing if webhook is already open.
* @return {Promise}
*/
openWebHook() {
if (this._webHook) {
return;
if (!this._webHook) {
this._webHook = new TelegramBotWebHook(this.token, this.options.webHook, this.processUpdate.bind(this));
}
this._webHook = new TelegramBotWebHook(this.token, this.options.webHook, this.processUpdate.bind(this));
return this._webHook.open();
}
/**
* Close webhook after closing all current connections
* Close webhook after closing all current connections.
* Multiple invocations do nothing if webhook is already closed.
* @return {Promise} promise
*/
closeWebHook() {
if (!this._webHook) {
return Promise.resolve();
}
const webHook = this._webHook;
delete this._webHook;
return webHook.close();
return this._webHook.close();
}
/**
@ -285,7 +300,7 @@ class TelegramBot extends EventEmitter {
* @return {Boolean}
*/
hasOpenWebHook() {
return !!this._webHook;
return this._webHook ? this._webHook.isOpen() : false;
}
/**

@ -33,7 +33,27 @@ class TelegramBotPolling {
this._lastRequest = null;
this._abort = false;
this._pollingTimeout = null;
this._polling();
}
/**
* Start polling
* @param {Object} [options]
* @param {Object} [options.restart]
* @return {Promise}
*/
start(options = {}) {
if (this._lastRequest) {
if (!options.restart) {
return Promise.resolve();
}
return this.stop({
cancel: true,
reason: 'Polling restart',
}).then(() => {
return this._polling();
});
}
return this._polling();
}
/**
@ -41,20 +61,36 @@ class TelegramBotPolling {
* @param {Object} [options]
* @param {Boolean} [options.cancel] Cancel current request
* @param {String} [options.reason] Reason for stopping polling
* @return {Promise}
*/
stopPolling(options = {}) {
this._abort = true;
stop(options = {}) {
if (!this._lastRequest) {
return Promise.resolve();
}
const lastRequest = this._lastRequest;
this._lastRequest = null;
clearTimeout(this._pollingTimeout);
if (options.cancel) {
const reason = options.reason || 'Polling stop';
return this._lastRequest.cancel(reason);
lastRequest.cancel(reason);
return Promise.resolve();
}
// wait until the last request is fulfilled
return this._lastRequest;
this._abort = true;
return lastRequest.finally(() => {
this._abort = false;
});
}
/**
* Return `true` if is polling. Otherwise, `false`.
*/
isPolling() {
return !!this._lastRequest;
}
/**
* Invokes polling (with recursion!)
* @return {Promise} promise of the current request
* @private
*/
_polling() {
@ -81,6 +117,7 @@ class TelegramBotPolling {
this._pollingTimeout = setTimeout(() => this._polling(), this.options.interval);
}
});
return this._lastRequest;
}
/**

@ -47,12 +47,47 @@ class TelegramBotWebHook {
debug('HTTP WebHook enabled');
this._webServer = http.createServer(this._requestListener);
}
}
this._webServer.listen(this.options.port, this.options.host, () => {
debug('WebHook listening on port %s', this.options.port);
/**
* Open WebHook by listening on the port
* @return {Promise}
*/
open() {
if (this._webServer.listening) {
return Promise.resolve();
}
return new Promise(resolve => {
this._webServer.listen(this.options.port, this.options.host, () => {
debug('WebHook listening on port %s', this.options.port);
return resolve();
});
});
}
/**
* Close the webHook
* @return {Promise}
*/
close() {
if (!this._webServer.listening) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
this._webServer.close(error => {
if (error) return reject(error);
return resolve();
});
});
}
/**
* Return `true` if server is listening. Otherwise, `false`.
*/
isOpen() {
return this._webServer.listening;
}
// used so that other funcs are not non-optimizable
_safeParse(json) {
try {
@ -106,20 +141,6 @@ class TelegramBotWebHook {
res.end();
}
}
/**
* Close the webHook
* @return {Promise}
*/
close() {
const self = this;
return new Promise(function closePromise(resolve, reject) {
self._webServer.close(function closeCb(error) {
if (error) return reject(error);
return resolve();
});
});
}
}
module.exports = TelegramBotWebHook;

@ -178,10 +178,11 @@ describe('TelegramBot', function telegramSuite() {
});
});
describe('#initPolling', function initPollingSuite() {
describe('#startPolling', function initPollingSuite() {
it('initiates polling', function test() {
testbot.initPolling();
return utils.isPollingMockServer(pollingPort);
return testbot.startPolling().then(() => {
return utils.isPollingMockServer(pollingPort);
});
});
});
@ -213,8 +214,9 @@ describe('TelegramBot', function telegramSuite() {
describe('#openWebHook', function openWebHookSuite() {
it('opens webhook', function test() {
testbot.openWebHook();
return utils.hasOpenWebHook(webHookPort);
return testbot.openWebHook().then(() => {
return utils.hasOpenWebHook(webHookPort);
});
});
});

Loading…
Cancel
Save