Add support for WebHooks

This commit is contained in:
Mahdi Dibaiee
2015-06-30 02:50:34 +04:30
parent 4ac725ea58
commit b55fb3c7d6
12 changed files with 278 additions and 126 deletions

View File

@ -39,7 +39,7 @@ API.prototype.request = function request(method, data) {
return (0, _fetch2['default'])(this.token + '/' + method, data);
};
var methods = ['getMe', 'sendMessage', 'forwardMessage', 'sendPhoto', 'sendAudio', 'sendDocument', 'sendSticker', 'sendVideo', 'sendLocation', 'sendChatAction', 'getUserProfilePhotos', 'getUpdates'];
var methods = ['getMe', 'sendMessage', 'forwardMessage', 'sendPhoto', 'sendAudio', 'sendDocument', 'sendSticker', 'sendVideo', 'sendLocation', 'sendChatAction', 'getUserProfilePhotos', 'getUpdates', 'setWebhook'];
methods.forEach(function (method) {
API.prototype[method] = function (data) {

View File

@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', {
value: true
});
exports['default'] = fetch;
exports.getBody = getBody;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
@ -19,8 +20,6 @@ function fetch(path, data) {
var post = _qs2['default'].stringify(data);
return new Promise(function (resolve, reject) {
var res = '';
var req = _https2['default'].request({
hostname: 'api.telegram.org',
method: data ? 'POST' : 'GET',
@ -29,19 +28,15 @@ function fetch(path, data) {
'Content-Type': 'application/x-www-form-urlencoded'
}
}, function (response) {
response.on('data', function (chunk) {
res += chunk;
});
response.on('end', function () {
return getBody(response).then(function (res) {
try {
var json = JSON.parse(res);
resolve(json);
} catch (e) {
reject(e);
}
});
}).on('error', reject);
})['catch'](reject);
});
if (post) {
req.write(post);
@ -52,4 +47,18 @@ function fetch(path, data) {
});
}
module.exports = exports['default'];
function getBody(stream) {
var data = '';
return new Promise(function (resolve, reject) {
stream.on('data', function (chunk) {
data += chunk;
});
stream.on('end', function () {
resolve(data);
});
stream.on('error', reject);
});
}

View File

@ -20,6 +20,14 @@ var _api = require('./api');
var _api2 = _interopRequireDefault(_api);
var _webhook = require('./webhook');
var _webhook2 = _interopRequireDefault(_webhook);
var _poll = require('./poll');
var _poll2 = _interopRequireDefault(_poll);
var _events = require('events');
var DEFAULTS = {
@ -75,62 +83,38 @@ var Bot = (function (_EventEmitter) {
key: 'start',
/**
* Gets information about the bot and then starts polling updates from API
* Gets information about the bot and then
* 1) starts polling updates from API
* 2) sets a webhook as defined by the first parameter and listens for updates
* Emits an `update` event after polling with the response from server
* Returns a promise which is resolved after the bot information is received
* and set to it's `info` property i.e. bot.info
*
* @param {object} hook An object containg options passed to webhook
* properties:
* - url: HTTPS url to listen on POST requests coming
* from the Telegram API
* - port: the port to listen to, defaults to 443
* - server: An object passed to https.createServer
*
* @return {promise} A promise which is resolved with the response of getMe
*/
value: function start() {
var _this2 = this;
var poll = (function () {
var _this = this;
return this.api.getUpdates(this.update).then(function (response) {
var again = wait(_this.update.timeout * 1000).then(poll);
var result = response.result;
if (!result.length) {
return again;
}
if (!_this.update.offset) {
var updateId = result[result.length - 1].update_id;
_this.update.offset = updateId;
}
if (_this.update) {
_this.update.offset += 1;
}
_this.emit('update', result);
result.forEach(function (res) {
var text = res.message.text;
if (text.startsWith('/')) {
// Commands are sent in /command@botusername format in groups
var regex = new RegExp('@' + _this.info.username + '$');
text = text.replace(regex, '');
}
var ev = _this._userEvents.find(function (_ref) {
var pattern = _ref.pattern;
return pattern.test(text);
});
if (!ev) {
return;
}
ev.listener(res.message);
});
return again;
});
}).bind(this);
value: function start(hook) {
var _this = this;
if (hook) {
return (0, _webhook2['default'])(hook, this);
}
return this.api.getMe().then(function (response) {
_this2.info = response.result;
return poll();
_this.info = response.result;
_this.on('update', _this._update);
if (hook) {
return (0, _webhook2['default'])(hook, _this);
} else {
return (0, _poll2['default'])(_this);
}
});
}
}, {
@ -186,16 +170,42 @@ var Bot = (function (_EventEmitter) {
value: function send(message) {
return message.send(this)['catch'](console.error);
}
}, {
key: '_update',
value: function _update(update) {
var _this2 = this;
if (!this.update.offset) {
var updateId = update[update.length - 1].update_id;
this.update.offset = updateId;
}
if (this.update) {
this.update.offset += 1;
}
update.forEach(function (res) {
var text = res.message.text;
if (text.startsWith('/')) {
// Commands are sent in /command@thisusername format in groups
var regex = new RegExp('@' + _this2.info.username + '$');
text = text.replace(regex, '');
}
var ev = _this2._userEvents.find(function (_ref) {
var pattern = _ref.pattern;
return pattern.test(text);
});
if (!ev) {
return;
}
ev.listener(res.message);
});
}
}]);
return Bot;
})(_events.EventEmitter);
exports['default'] = Bot;
var wait = function wait(miliseconds) {
return new Promise(function (resolve) {
setTimeout(resolve, miliseconds);
});
};
module.exports = exports['default'];

27
build/poll.js Normal file
View File

@ -0,0 +1,27 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports['default'] = poll;
function poll(bot) {
return bot.api.getUpdates(bot.update).then(function (response) {
var again = wait(bot.update.timeout * 1000, bot).then(poll);
if (!response.result.length) {
return again;
}
bot.emit('update', response.result);
return again;
});
}
var wait = function wait(miliseconds, value) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(value);
}, miliseconds);
});
};
module.exports = exports['default'];

42
build/webhook.js Normal file
View File

@ -0,0 +1,42 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports['default'] = webhook;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _http = require('http');
var _http2 = _interopRequireDefault(_http);
var _qs = require('qs');
var _qs2 = _interopRequireDefault(_qs);
var _fetch = require('./fetch');
var DEFAULTS = {
server: {},
port: 443
};
function webhook(options, bot) {
if (options === undefined) options = {};
options = Object.assign(DEFAULTS, options);
return bot.api.setWebhook(options.url).then(function () {
_http2['default'].createServer(options.server, function (req, res) {
return (0, _fetch.getBody)(req).then(function (data) {
bot.emit('update', _qs2['default'].parse(data).result);
res.end('OK');
});
}).listen(options.port);
});
}
module.exports = exports['default'];