diff --git a/demo.js b/demo.js index 613a79f..03c9ce7 100644 --- a/demo.js +++ b/demo.js @@ -1,7 +1,15 @@ var Bot = require('./index'); +var Message = require('./lib/classes/Message'); +var Question = require('./lib/classes/Question'); + +process.on('uncaughtException', function (err) { + console.error((new Date()).toUTCString() + ' uncaughtException:', err.message); + console.error(err.stack); + process.exit(1); +}); var smartBot = new Bot({ - token: 'YOUR_KEY' + token: '121143906:AAE6pcpBoARNZZjr3fUpvKuLInJ5Eee5Ajk' }); // getMe is called before polling starts, setting info property of bot @@ -14,16 +22,17 @@ smartBot.get('Hi', function(update) { const message = update.message; const id = message.chat.id; - // answers is in format of keyboard rows - const question = 'How should I greet you?', - answers = [['Hi'], ['Hello, Sir'], ['Yo bro']]; + var question = new Question().to(id) + .text('How should I greet you?') + .answers([['Hi'], ['Hello, Sir'], ['Yo bro']]) + .reply(message.message_id); - smartBot.replyTo(message.message_id) - .askQuestion(id, question, answers) - .then(answer => { - smartBot.message(id, 'Your answer: ' + answer); + smartBot.send(question).then(answer => { + const msg = new Message().to(id).text('Your answer: ' + answer); + smartBot.send(msg); }, () => { - smartBot.message(id, 'Invalid answer'); + const msg = new Message().to(id).text('Invalid answer'); + smartBot.send(msg); }); }); @@ -32,9 +41,14 @@ smartBot.command('test', update => { const message = update.message; const id = message.chat.id; - smartBot.message(id, 'Test command'); + // options object => Telegram API + smartBot.send(new Message({ + chat_id: id, + text: 'Test Command' + })); }); smartBot.command('start', update => { - smartBot.message(update.message.chat.id, 'Hello!'); + // chainable methods => easier + smartBot.send(new Message().to(update.message.chat.id).text('Hello')); }); diff --git a/lib/classes/Keyboard.js b/lib/classes/Keyboard.js new file mode 100644 index 0000000..e7b9590 --- /dev/null +++ b/lib/classes/Keyboard.js @@ -0,0 +1,61 @@ +export default class Keyboard { + constructor(message, options = {}) { + this.message = message; + this.replyMarkup = options; + } + + keys(keys) { + this.setProperties({ + keyboard: keys, + hide_keyboard: false + }); + return this; + } + + force(enable = true) { + this.setProperties({ + force_keyboard: enable + }); + return this; + } + + resize(enable = true) { + this.setProperties({ + resize: enable + }); + return this; + } + + oneTime(enable = true) { + this.setProperties({ + one_time_keyboard: enable + }); + return this; + } + + selective(enable = true) { + this.setProperties({ + selective: enable + }); + return this; + } + + hide() { + this.replyMarkup = { + hide_keyboard: true + }; + + return this; + } + + get replyMarkup() { + return JSON.parse(this.message.params.reply_markup); + } + set replyMarkup(json) { + this.message.params.reply_markup = JSON.stringify(json); + } + + setProperties(object) { + this.replyMarkup = Object.assign(this.replyMarkup, object); + } +} diff --git a/lib/classes/Message.js b/lib/classes/Message.js new file mode 100644 index 0000000..6b75e16 --- /dev/null +++ b/lib/classes/Message.js @@ -0,0 +1,77 @@ +import {EventEmitter} from 'events'; +import Keyboard from './Keyboard'; + +export default class Message extends EventEmitter { + constructor(options = {}) { + super(); + + this.params = options; + } + + to(chat) { + this.params.chat_id = chat; + return this; + } + + text(text) { + this.params.text = text; + return this; + } + + reply(chat) { + this.params.reply_to_message_id = chat; + return this; + } + + keyboard(options) { + let params; + + if (this._keyboard && !options) { + return this._keyboard; + } + + if (this._keyboard) { + params = Object.assign(this._keyboard.replyMarkup, options); + } else { + params = options; + } + + this._keyboard = new Keyboard(this, params); + return this._keyboard; + } + + send(bot) { + let messageId; + + return new Promise(resolve => { + bot.api.sendMessage(this.params).then(response => { + messageId = response.result.message_id; + this.emit('message:sent', response); + }); + + if (this.keyboard().replyMarkup.one_time_keyboard) { + this.keyboard().replyMarkup = ''; + } + + const chat = this.params.chat_id; + bot.on('update', function listener(result) { + const update = result.find(({message}) => { + // if in a group, there will be a reply to this message + if (chat < 0) { + return message.chat.id === chat && + message.reply_to_message.message_id === messageId; + } else { + return message.chat.id === chat; + } + }); + + if (update) { + resolve(update); + this.emit('message:answer', update); + + bot.removeListener('update', listener); + } + }); + }); + } +} diff --git a/lib/classes/Question.js b/lib/classes/Question.js new file mode 100644 index 0000000..a982dbe --- /dev/null +++ b/lib/classes/Question.js @@ -0,0 +1,43 @@ +import Message from './Message'; + +export default class Question extends Message { + constructor(options = {}) { + super(options); + + this.keyboard().force().oneTime().selective(); + } + + answers(answers) { + this.answers = answers; + this.keyboard().keys(answers); + return this; + } + + send(bot) { + const answers = this.answers; + + return new Promise((resolve, reject) => { + super.send(bot).then(update => { + const message = update.message; + let answer; + + answers.forEach(function find(a) { + if (Array.isArray(a)) { + a.forEach(find); + } + if (a === message.text) { + answer = a; + } + }); + + if (answer) { + resolve(answer, update); + this.emit('question:answer', answer, update); + } else { + reject(update); + this.emit('question:invalid', update); + } + }); + }); + } +} diff --git a/lib/fetch.js b/lib/fetch.js index 07ab18b..913b326 100644 --- a/lib/fetch.js +++ b/lib/fetch.js @@ -7,7 +7,6 @@ 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', @@ -16,7 +15,6 @@ 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 1de847c..fa02acd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -82,125 +82,8 @@ export default class Bot { }); } - message(chat, text, options = {}) { - return new Promise(resolve => { - let messageId; - - const params = Object.assign({ - chat_id: chat, - text, - reply_markup: this._replyMarkup - }, this.msg, options); - - 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) { - const update = result.find(({message}) => { - // if in a group, there will be a reply to this message - console.log(message.chat.id, chat); - if (chat < 0) { - return message.chat.id === chat && - message.reply_to_message.message_id === messageId; - } else { - return message.chat.id === chat; - } - }); - - console.log(text, '=>', update); - - if (update) { - resolve(update); - - this.removeListener('update', listener); - } - }); - }); - } - - replyTo(reply) { - this.msg.reply_to_message_id = reply; - - return this; - } - - askQuestion(chat, title, answers = []) { - return new Promise((resolve, reject) => { - this.keyboard(answers, false, true).force() - .message(chat, title).then(update => { - const message = update.message; - let answer; - - console.log(message); - answers.forEach(function find(a) { - if (Array.isArray(a)) { - a.forEach(find); - } - if (a === message.text) { - answer = a; - } - }); - console.log(title, '=', answer); - - if (answer) { - resolve(answer, update); - } else { - reject(update); - } - }); - }); - } - - keyboard(rows, resize = false, oneTime = false, selective = true) { - this.replyMarkup = { - keyboard: rows, - resize_keyboard: resize, - one_time_keyboard: oneTime, - selective - }; - - return this; - } - - hideKeyboard(selective = true) { - this.replyMarkup = { - hide_keyboard: true, - selective - }; - - return this; - } - - force(enable = true, selective) { - this.replyMarkup.force_reply = enable; - if (selective) { - this.replyMarkup.selective = selective; - } - - return this; - } - - set replyMarkup(json) { - this._replyMarkup = JSON.stringify(json); - } - - get replyMarkup() { - return JSON.parse(this._replyMarkup); - } - - wait(miliseconds) { - const self = this; - - return function(resolve) { - setTimeout(resolve.bind(self), miliseconds); - }; + send(message) { + return message.send(this); } }