Skip to content

Commit

Permalink
src/webhook: Add health-check endpoint (#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
passion-27 committed Jan 30, 2017
2 parents 37de9e0 + 600b063 commit 3cd6c17
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 15 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased][Unreleased]

Added:

1. Add health-check endpoint (by @mironov)


* * *
Expand Down
1 change: 1 addition & 0 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
1 change: 1 addition & 0 deletions src/telegram.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
28 changes: 17 additions & 11 deletions src/telegramWebHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -133,20 +135,24 @@ 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') {
debug('WebHook request isn\'t a POST');
res.statusCode = 418; // I'm a teabot!
res.end();
} else {
req
.pipe(bl(this._parseBody))
.on('finish', () => res.end('OK'));
}
} else if (this._healthRegex.test(req.url)) {
debug('WebHook health check passed');
res.statusCode = 200;
res.end('OK');
} else {
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();
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions test/telegram.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ describe('TelegramBot', function telegramSuite() {
});

describe('WebHook', function webHookSuite() {
it('returns 200 OK for health 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);
Expand Down
27 changes: 23 additions & 4 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -134,23 +145,31 @@ 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',
body: {
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];
Expand Down

0 comments on commit 3cd6c17

Please sign in to comment.