2
0
mirror of https://github.com/yagop/node-telegram-bot-api synced 2025-08-22 09:57:10 +00:00

Webhook health check endpoint

This commit is contained in:
Anton Mironov 2017-01-29 21:59:40 +03:00
parent 24a3f6dade
commit 3263c6c253
5 changed files with 51 additions and 15 deletions

View File

@ -80,6 +80,7 @@ Emits `message` when a message arrives.
| [options.webHook.pfx] | <code>String</code> | | Path to file with PFX private key and certificate chain for webHook server. The file is read **synchronously**! |
| [options.webHook.autoOpen] | <code>Boolean</code> | <code>true</code> | Open webHook immediately |
| [options.webHook.https] | <code>Object</code> | | Options to be passed to `https.createServer()`. Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be used to override `key`, `cert` and `pfx` in this object, respectively. See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information. |
| [options.webHook.healthEndpoint] | <code>String</code> | <code>/healthz</code> | An endpoint for health checks that always responds with 200 OK |
| [options.onlyFirstMatch] | <code>Boolean</code> | <code>false</code> | Set to true to stop after first match. Otherwise, all regexps are executed |
| [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 |

View File

@ -59,6 +59,7 @@ class TelegramBot extends EventEmitter {
* Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be
* used to override `key`, `cert` and `pfx` in this object, respectively.
* See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information.
* @param {String} [options.webHook.healthEndpoint=/healthz] An endpoint for health checks that always responds with 200 OK
* @param {Boolean} [options.onlyFirstMatch=false] Set to true to stop after first match. Otherwise, all regexps are executed
* @param {Object} [options.request] Options which will be added for all requests to telegram api.
* See https://github.com/request/request#requestoptions-callback for more information.

View File

@ -13,6 +13,7 @@ class TelegramBotWebHook {
* @param {String} token Telegram API token
* @param {Boolean|Object} options WebHook options
* @param {Number} [options.port=8443] Port to bind to
* @param {String} [options.healthEndpoint=/healthz] An endpoint for health checks that always responds with 200 OK
* @param {Function} callback Function for process a new update
*/
constructor(token, options, callback) {
@ -27,6 +28,7 @@ class TelegramBotWebHook {
this.options.https = options.https || {};
this.callback = callback;
this._regex = new RegExp(this.token);
this._healthRegex = new RegExp(options.healthEndpoint || '/healthz');
this._webServer = null;
this._open = false;
this._requestListener = this._requestListener.bind(this);
@ -133,20 +135,27 @@ class TelegramBotWebHook {
debug('WebHook request URL: %s', req.url);
debug('WebHook request headers: %j', req.headers);
// If there isn't token on URL
if (!this._regex.test(req.url)) {
if (this._regex.test(req.url)) {
if (req.method === 'POST') {
req
.pipe(bl(this._parseBody))
.on('finish', () => res.end('OK'));
} else {
// Authorized but not a POST
debug('WebHook request isn\'t a POST');
res.statusCode = 418; // I'm a teabot!
res.end();
}
} else if (this._healthRegex.test(req.url)) {
// If this is a health check
debug('WebHook health check passed');
res.statusCode = 200;
res.end('OK');
} else if (!this._regex.test(req.url)) {
// If there isn't token on URL
debug('WebHook request unauthorized');
res.statusCode = 401;
res.end();
} else if (req.method === 'POST') {
req
.pipe(bl(this._parseBody))
.on('finish', () => res.end('OK'));
} else {
// Authorized but not a POST
debug('WebHook request isn\'t a POST');
res.statusCode = 418; // I'm a teabot!
res.end();
}
}
}

View File

@ -133,6 +133,12 @@ describe('TelegramBot', function telegramSuite() {
});
describe('WebHook', function webHookSuite() {
it('returns OK for healthz endpoint', function test(done) {
utils.sendWebHookRequest(webHookPort2, '/healthz', { json: false }).then(resp => {
assert.equal(resp, 'OK');
return done();
});
});
it('returns 401 error if token is wrong', function test(done) {
utils.sendWebHookMessage(webHookPort2, 'wrong-token').catch(resp => {
assert.equal(resp.statusCode, 401);

View File

@ -30,6 +30,17 @@ exports = module.exports = {
* @return {Promise}
*/
isPollingMockServer,
/**
* Send a message to the webhook at the specified port and path.
* @param {Number} port
* @param {String} path
* @param {Object} [options]
* @param {String} [options.method=POST] Method to use
* @param {Object} [options.message] Message to send. Default to a generic text message
* @param {Boolean} [options.https=false] Use https
* @return {Promise}
*/
sendWebHookRequest,
/**
* Send a message to the webhook at the specified port.
* @param {Number} port
@ -134,11 +145,11 @@ function hasOpenWebHook(port, reverse) {
}
function sendWebHookMessage(port, token, options = {}) {
function sendWebHookRequest(port, path, options = {}) {
assert.ok(port);
assert.ok(token);
assert.ok(path);
const protocol = options.https ? 'https' : 'http';
const url = `${protocol}://127.0.0.1:${port}/bot${token}`;
const url = `${protocol}://127.0.0.1:${port}${path}`;
return request({
url,
method: options.method || 'POST',
@ -146,11 +157,19 @@ function sendWebHookMessage(port, token, options = {}) {
update_id: 1,
message: options.message || { text: 'test' }
},
json: true,
json: options.json || true,
});
}
function sendWebHookMessage(port, token, options = {}) {
assert.ok(port);
assert.ok(token);
const path = `/bot${token}`;
return sendWebHookRequest(port, path, options);
}
function handleRatelimit(bot, methodName, suite) {
const backupMethodName = `__${methodName}`;
if (!bot[backupMethodName]) bot[backupMethodName] = bot[methodName];