diff --git a/README.md b/README.md index 22eaa72..b62c84f 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,38 @@ # Telegram Bots -Control Telegram bots easily. +Create and control [Telegram bots](https://core.telegram.org/bots) easily +using the new [Telegram API](https://core.telegram.org/bots/api). ``` -npm install telegram-bots +npm install telegram-api ``` # Example ```javascript -let Bot = require('telegram-bots'); +var Bot = require('./index'); -let smartBot = new Bot({ - token: 'YOUR_TOKEN' +var smartBot = new Bot({ + token: 'YOUR_KEY' }); -// update is an Update object as described in Telegram Bots API documentation -smartBot.on('Hi', update => { - const message = update.message, - id = message.chat.id; +smartBot.start(); + +// You can use regular expressions, too +smartBot.get('Hi', function(update) { + const message = update.message; + const id = message.chat.id; const question = 'How should I greet you?', answers = ['Hi', 'Hello, Sir', 'Yo bro']; smartBot.askQuestion(id, question, answers) .then(answer => { - smartBot.message(id, `Your answer: ${answer}`); + smartBot.message(id, 'Your answer: ' + answer); }, () => { smartBot.message(id, 'Invalid answer'); }); }); +// Commands are in format `/command` or `/command@botusername` in groups smartBot.command('test', update => { const message = update.message; const id = message.chat.id; @@ -39,6 +43,10 @@ smartBot.command('test', update => { smartBot.command('start', update => { smartBot.message(update.message.chat.id, 'Hello!'); }); + +// You can access all API methods through the api property until we implement +// easier methods +smartBot.api.getUserProfilePhotos ``` This will result in: diff --git a/lib/fetch.js b/lib/fetch.js index 913b326..07ab18b 100644 --- a/lib/fetch.js +++ b/lib/fetch.js @@ -7,6 +7,7 @@ export default function(path, data) { return new Promise((resolve, reject) => { let res = ''; + console.log('sending request for', path); const req = https.request({ hostname: 'api.telegram.org', method: data ? 'POST' : 'GET', @@ -15,6 +16,7 @@ export default function(path, data) { 'Content-Type': 'application/x-www-form-urlencoded' } }, response => { + console.log('response'); response.on('data', chunk => { res += chunk; }); diff --git a/lib/index.js b/lib/index.js index 99ba524..1497f1e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -20,14 +20,17 @@ export default class Bot { this.api = new API(this.token); + this.msg = {}; + // EventEmitter this._events = {}; + this._userEvents = []; } start() { - (function poll() { + let poll = function() { this.api.getUpdates(this.update).then(response => { - setTimeout(poll.bind(this), this.update.timeout * 1000); + setTimeout(poll, this.update.timeout * 1000); const result = response.result; if (!result.length) { @@ -44,37 +47,68 @@ export default class Bot { this.emit('update', response.result); result.forEach(res => { - const text = res.message.text; + let text = res.message.text; if (text.indexOf('/') === 0) { - this.emit('command:' + text.slice(1), res); - } else { - this.emit(text, res); + // Commands are sent in format /command@botusername format + const regex = new RegExp(`@${this.info.username}$`); + text = text.replace(regex, ''); } + + let ev = this._userEvents.find(({message}) => message.test(text)); + ev.listener(res); }); }); - }.bind(this)()); + }.bind(this); + + this.api.getMe().then(response => { + this.info = response.result; + poll(); + }); + } + + get(message, listener) { + if (typeof message === 'string') { + message = new RegExp(`^${message}`); + } + + this._userEvents.push({ + message, listener + }); } command(cmd, listener) { - return this.on(`command:${cmd}`, listener); + this._userEvents.push({ + message: new RegExp(`/${cmd}`), + listener + }); } - message(chat, text, options) { + message(chat, text, options = {}) { return new Promise(resolve => { - console.log(this.keyboard); - this.api.sendMessage(Object.assign({ + let messageId; + + const params = Object.assign({ chat_id: chat, text, - reply_markup: this.keyboard - }, options)); + reply_markup: this._replyMarkup + }, this.msg, options); - if (JSON.parse(this.keyboard).one_time_keyboard) { - this.keyboard = ''; + this.api.sendMessage(params).then(response => { + messageId = response.result.message_id; + }); + + this.msg = {}; + + if (this.replyMarkup.one_time_keyboard) { + this.replyMarkup = ''; } this.on('update', function listener(result) { + console.log(result); + console.log(messageId); const update = result.find(({message}) => { - return message.chat.id === chat; + return message.chat.id === chat && + message.reply_to_message.message_id === messageId; }); if (update) { @@ -86,15 +120,17 @@ export default class Bot { }); } - askQuestion(chat, title, answers = []) { - const text = title + '\n\n' + answers.reduce((a, b, i) => { - return a + `${i}. ${b}\n`; - }, ''); + replyTo(reply) { + this.msg.reply_to_message_id = reply; + return this; + } + + askQuestion(chat, title, answers = []) { return new Promise((resolve, reject) => { const rows = [answers]; this.keyboard(rows, false, true).force() - .message(chat, text).then(update => { + .message(chat, title).then(update => { const message = update.message; let answer; @@ -113,35 +149,43 @@ export default class Bot { }); } - keyboard(rows, resize = false, oneTime = false, selective) { - this.keyboard = JSON.stringify({ + keyboard(rows, resize = false, oneTime = false, selective = true) { + this.replyMarkup = { keyboard: rows, resize_keyboard: resize, one_time_keyboard: oneTime, selective - }); + }; return this; } - hideKeyboard(selective) { - this.keyboard = JSON.stringify({ + hideKeyboard(selective = true) { + this.replyMarkup = { hide_keyboard: true, selective - }); + }; return this; } force(enable = true, selective) { - const keyboard = JSON.parse(this.keyboard); - keyboard.force_reply = enable; - keyboard.selective = selective; + this.replyMarkup.force_reply = enable; + if (selective) { + this.replyMarkup.selective = selective; + } - this.keyboard = JSON.stringify(keyboard); return this; } + set replyMarkup(json) { + this._replyMarkup = JSON.stringify(json); + } + + get replyMarkup() { + return JSON.parse(this._replyMarkup); + } + wait(miliseconds) { const self = this;