diff --git a/README.md b/README.md new file mode 100644 index 0000000..0091ce5 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +## Telegram bot platform +This is a simple framework to create scalable & powerful bots for [Telegram messenger](https://telegram.org). + +## Installation +Just run the following code and every thing is done :) +``` +npm install tg-bot-platfrom +``` + +## Docs +TODO: write documentations \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..449919f --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "tg-bot-platform", + "version": "0.1.0", + "description": "This is a simple framework for creating Telegram bots based on `node-telegram-bot-api` and `redis`", + "main": "platform.js", + "scripts": { + "install": "cat src/classes/*.js src/index.js > platform.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/slye-team/tg-bot-platform.git" + }, + "keywords": [ + "telegram", + "bot", + "node", + "api", + "telegram", + "api" + ], + "author": "Alireza Ghadimi (Qti3e)", + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/qti3e/bot-platform/issues" + }, + "homepage": "https://github.com/qti3e/bot-platform#readme", + "dependencies": { + "fs": "0.0.1-security", + "handlebars": "^4.0.10", + "node-telegram-bot-api": "", + "redis": "" + } +} diff --git a/src/classes/Bot.js b/src/classes/Bot.js new file mode 100644 index 0000000..580e5e1 --- /dev/null +++ b/src/classes/Bot.js @@ -0,0 +1,460 @@ +/***************************************************************************** + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + *___________________________________________________________________________* + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + *___________________________________________________________________________* + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *___________________________________________________________________________* + * Created by Qti3e * + * LO-VE * + *****************************************************************************/ + +/** + * + */ +class Bot { + /** + * + * @param token + * @param channel + */ + constructor(token, channel) { + // Initial Values + this._pages = {}; + this._links = {}; + this._forms = {}; + this._token = token; + this._resolveForms = {}; + this._rejectForms = {}; + this._actions = {}; + this.channel = channel; + } + + /** + * + */ + start(){ + var options = arguments.length > 0 ? arguments[0] : {}; + // Create a bot with given token + global.TgBotApi = new TelegramBot(this._token, options); + + global.TgBotApi.on('inline_query', (msg) => { + // console.log(msg) + }); + // Listen for new incoming messages + global.TgBotApi.on('message', (msg) => { + // For know we just support the text messages + if(!msg.text) + return; + var user = new User(msg.from), + message = msg.text; + + user.get('form_id', (form_id) => { + if(form_id !== ''){ + global.RedisClient.hmget(form_id, [':id', ':name'], (err, ret) => { + ret = { + ':id' : parseInt(ret[0]), + ':name' : ret[1] + }; + var form = this._forms[ret[':name']]; + var keys = Object.keys(form); + var len = keys.length; + + var editingKey = keys[ret[':id']]; + global.RedisClient.hset(form_id, editingKey, message); + global.RedisClient.hincrby(form_id, ':id', 1); + //Check if form completed or not + if(ret[':id'] + 1 == len){ + global.RedisClient.hgetall(form_id, (err, result) => { + this._resolveForms[form_id](result); + // Cleanup memory + this._rejectForms[form_id] = null; + // Close form and remove data from database + user.del('form_id'); + global.RedisClient.del(form_id); + }) + }else { + user.send(form[keys[ret[':id'] + 1]]['placeholder']); + } + }) + }else { + user.get('page', page => { + if(page == '' || msg.text.substr(0,6) == '/start'){ + // Open start page for the new users + this.go('open:start', user, false, msg) + }else { + user.get('args', args => { + this._getLinks(page, args, user, message).then(links => { + if(links[message]) + this.go(links[message], user, false, msg); + else if(page !== 'index'){ + this._getLinks('index', {}, user, message).then(links => { + if(links[message]) + this.go(links[message], user, false, msg); + }) + } + }) + }) + } + }); + } + }); + }); + + // Listen for receiving new incoming Callback Query + global.TgBotApi.on('callback_query', (callbackQuery) => { + var user = new User(callbackQuery.from), + action = callbackQuery.data, + s = action.search(':'); + if(action.substr(0, s) == 'open'){ + this.go(action, user, true, callbackQuery.message); + } + if(action.substr(0, s) == 'action'){ + this.openAction(action, user, callbackQuery.message, callbackQuery); + } + }); + + } + + createLink(page, args, is_action = false){ + page = (is_action ? 'action' : 'open') + ':' + page; + if(args) + page += '?' + JSON.stringify(args); + return page; + } + + /** + * + * @param page + * @param method + * @param cache_args + * @param expire_time + * @param change_history + */ + page(page, method, cache_args = [],expire_time = 86400, change_history = true, need_login = true) { + if(this._pages[page] || typeof method !== 'function') + return; + this._pages[page] = [method, cache_args,expire_time, change_history, need_login]; + } + + _getPage(name, args, user, is_callback, message){ + var page = this._pages[name]; + var method = page[0], + cache_args = page[1], + expire_time = page[2], + change_history = page[3], + need_login = true; + + if(cache_args === false){ + var m_ret = method(args, user, is_callback, message); + if(m_ret instanceof Promise){ + m_ret.then(m_ret => { + if(m_ret instanceof BotMessage){ + m_ret.send(user); + } + }) + }else { + if(m_ret instanceof BotMessage){ + m_ret.send(user); + } + } + return change_history; + } + + if(typeof method !== 'function') + return false; + var init = () => { + var c_args = []; + cache_args.forEach(value => { + if(value == '%u'){ + c_args.push(user.id) + }else { + c_args.push(args[value]) + } + }); + var cache_key = 'p' + name + ':' + JSON.stringify(c_args); + var cache_key_ = 'l' + name + ':' + JSON.stringify(c_args); + var save_cache = (m_ret) => { + var d; + if(m_ret instanceof BotMessage){ + d = m_ret.save(); + global.RedisClient.set(cache_key, d); + m_ret.send(user); + }else if(m_ret instanceof BotMessageSent){ + d = m_ret.save(); + global.RedisClient.set(cache_key, '+'+d); + }else { + global.RedisClient.set(cache_key, '-') + } + if(typeof expire_time == 'number'){ + global.RedisClient.expire(cache_key, expire_time); + global.RedisClient.expire(cache_key_,expire_time); + } + }; + global.RedisClient.get(cache_key, (err, re) => { + if(re == null){ + var m_ret = method(args, user, is_callback, message); + if(m_ret instanceof Promise){ + m_ret.then(m_ret => { + save_cache(m_ret); + }) + }else { + save_cache(m_ret); + } + }else if(re !== '-'){ + if(re[0] == '+'){ + re = JSON.parse(re.substr(1)); + var m = re[0], + t = re[1], + q = re[2]; + var msg = new BotMessageSent(message, t); + msg.load(q, user); + }else { + var msg = new BotMessage(); + msg.load(re); + msg.send(user); + } + } + }); + }; + if(need_login){ + user.isMemberOf(this.channel).then(re => { + if (!re) + return this.go('open:start', user, is_callback, message); + init() + }); + }else { + init(); + } + return change_history; + }; + + /** + * + * @param page + * @param method + * @param cache_args + * @param expire_time + * @param change_history + */ + links(page, method, cache_args = [],expire_time = 86400) { + if(this._links[page] || typeof method !== 'function') + return; + this._links[page] = [method, cache_args, expire_time]; + } + + _getLinks(page, args, user, message){ + var links = this._links[page]; + var method = links[0], + cache_args = links[1], + expire_time = links[2]; + + if(typeof method !== 'function') + return new Promise(resolve => { + resolve({}); + }); + if(cache_args === false){ + return new Promise(resolve => { + var m_ret = method(args, user, message); + if(m_ret instanceof Promise){ + m_ret.then(m_ret => { + resolve(m_ret) + }) + }else { + resolve(m_ret) + } + }) + } + var c_args = []; + cache_args.forEach(value => { + if(value == '%u'){ + c_args.push(user.id) + }else { + c_args.push(args[value]) + } + }); + var cache_key = 'l' + page + ':' + JSON.stringify(c_args); + var cache_key_ = 'p' + page + ':' + JSON.stringify(c_args); + + + var save_cache = (m_ret) => { + global.RedisClient.set(cache_key, JSON.stringify(m_ret)); + + if(typeof expire_time == 'number'){ + global.RedisClient.expire(cache_key, expire_time); + global.RedisClient.expire(cache_key_,expire_time); + } + }; + return new Promise(resolve => { + global.RedisClient.get(cache_key, (err, re) => { + if(re == null){ + var m_ret = method(args, user, message); + if(m_ret instanceof Promise){ + m_ret.then(m_ret => { + save_cache(m_ret); + resolve(m_ret) + }) + }else { + save_cache(m_ret); + resolve(m_ret) + } + }else{ + re = JSON.parse(re); + resolve(re); + } + }); + }) + } + + /** + * + * @param link + * @param user + * @param is_callback + * @param msg + */ + go(link, user, is_callback, msg) { + is_callback = is_callback || false; + var re = ((action) => { + var s = action.search(':'); + if(action.substr(0, s) == 'open'){ + var url = action.substr(s + 1); + s = url.search(/\?/); + var page, + args = {}; + if(s > 0){ + page = url.substr(0, s); + args = JSON.parse(url.substr(s+1)); + }else { + page = url; + } + return { + page: page, + args: args + } + }else if(action.substr(0,s) == 'action'){ + this.openAction(link, user, msg); + } + return false + })(link); + if(!re) + return; + var page = re['page'], + args = re['args']; + if(!this._pages[page]) + return; + + msg = new BotMessageSent(msg, 'text', user.id); + var change_history = this._getPage(page, args, user, is_callback, msg); + if(change_history){ + // ll: last link + user.get('ll', (err, data) => { + if(data !== null){ + global.RedisClient.rpush('h:' + user.id, data); + } + global.RedisClient.set('ll', link); + }); + user.set('page', page); + user.set('args', args); + } + } + + /** + * Register new form + * @param name + * @param form + */ + form(name, form){ + this._forms[name] = form; + } + static randomString(len = 32){ + const strings = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + var re = '', i; + for(i = 0; i < len;i++){ + re += strings[Math.floor(Math.random() * strings.length)] + } + return re; + } + + /** + * + * @param name + * @param user + * @returns {Promise} + */ + sendForm(name, user){ + return new Promise((resolve, reject) => { + // Exit if form is not defined + if(!this._forms[name]) + return; + // Create a random string for users + var id = Bot.randomString(); + // Open form for user + user.set('form_id', id); + + // Set initial form's data + global.RedisClient.hset(id, ':id', 0); + global.RedisClient.hset(id, ':name', name); + + //Save the callback functions + this._resolveForms[id] = resolve; + // if(reject) + // this._rejectForms[id] = reject; + + // Expire data after an hour + // global.RedisClient.expire(id, 60 * 60); + // setTimeout(function () { + // // todo Call the cancel function after the expire time + // }, 3600); + + user.send(this._forms[name][Object.keys(this._forms[name])[0]]['placeholder']); + }); + } + + action(name, method){ + if(this._actions[name] || typeof method !== 'function') + return; + this._actions[name] = method; + } + + openAction(action, user, message, callbackQuery){ + var re = ((action) => { + var s = action.search(':'); + if(action.substr(0, s) == 'action'){ + var url = action.substr(s + 1); + s = url.search(/\?/); + var page, + args = {}; + if(s > 0){ + page = url.substr(0, s); + args = JSON.parse(url.substr(s+1)); + }else { + page = url; + } + return { + page: page, + args: args + } + } + return false + })(action); + message = new BotMessageSent(message,'text', user.id) + if(typeof this._actions[re.page] == 'function') + this._actions[re.page](re.args,user, message, callbackQuery); + } + + answerCallbackQuery(callbackQueryId, text, showAlert = true, options = {}){ + return global.TgBotApi.answerCallbackQuery(callbackQueryId, text, showAlert, options); + } + + sendChatAction(chat_id ,action){ + return global.TgBotApi.sendChatAction(chat_id, action); + } +} \ No newline at end of file diff --git a/src/classes/BotMessage.js b/src/classes/BotMessage.js new file mode 100644 index 0000000..ff7608f --- /dev/null +++ b/src/classes/BotMessage.js @@ -0,0 +1,173 @@ +/***************************************************************************** + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + *___________________________________________________________________________* + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + *___________________________________________________________________________* + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *___________________________________________________________________________* + * Created by Qti3e * + * LO-VE * + *****************************************************************************/ + +/** + * Use this class to send messages to users :) + * Example: + * new BotMessage('video', '/file.mp4').send(user).then((msg) => { + * msg.editCaption('Edited Caption'); + * }); + */ +class BotMessage { + save(){ + return JSON.stringify([ + this.type, + this._data + ]) + } + load(json){ + var r = JSON.parse(json) + this.type = r[0] + this._data = r[1]; + } + + /** + * Set all initial values and get all of required arguments based on message type + * @param type + */ + constructor(type){ + type = type || 'text'; + this.type = type; + this._data = {}; + + switch(type){ + case 'text': + this._data['text'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + break; + case 'photo': + this._data['photo'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + break; + case 'document': + this._data['doc'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + this._data['fOptions'] = arguments[3] || {}; + break; + case 'audio': + this._data['audio'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + break; + case 'sticker': + this._data['sticker'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + break; + case 'voice': + this._data['voice'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + break; + case 'video': + this._data['video'] = arguments[1]; + this._data['options'] = arguments[2] || {}; + break; + case 'location': + this._data['latitude'] = arguments[1]; + this._data['longitude'] = arguments[2]; + this._data['options'] = arguments[3] || {}; + break; + case 'venue': + this._data['latitude'] = arguments[1]; + this._data['longitude'] = arguments[2]; + this._data['title'] = arguments[3]; + this._data['address'] = arguments[4]; + this._data['options'] = arguments[5] || {}; + break; + case 'contact': + this._data['number'] = arguments[1]; + this._data['firstName'] = arguments[2]; + this._data['options'] = arguments[3] || {}; + break; + } + } + + /** + * Send message to user + * @param user {User|number} + * @returns {Promise} + */ + send(user){ + var chat_id = user.id || user; + + return new Promise((resolve) => { + var callback = (msg) => { + global.RedisClient.hset(':u' + chat_id, ':lastmsg', JSON.stringify({ + id: msg.message_id, + type: this.type, + text: this._data['text'] + })); + var sent = new BotMessageSent(msg, this.type, chat_id); + resolve(sent); + }; + const TgBotAPI = global.TgBotApi; + switch(this.type){ + case 'text': + TgBotAPI.sendMessage(chat_id, this._data['text'], this._data['options']).then(callback); + break; + case 'photo': + TgBotAPI.sendPhoto(chat_id, this._data['photo'], this._data['options']).then(callback); + break; + case 'document': + TgBotAPI.sendDocument(chat_id, this._data['doc'], this._data['options'], this._data['fOptions']).then(callback); + break; + case 'audio': + TgBotAPI.sendAudio(chat_id, this._data['audio'], this._data['options']).then(callback); + break; + case 'sticker': + TgBotAPI.sendSticker(chat_id, this._data['sticker'], this._data['options']).then(callback); + break; + case 'voice': + TgBotAPI.sendVoice(chat_id, this._data['voice'], this._data['options']).then(callback); + break; + case 'video': + TgBotAPI.sendVideo(chat_id, this._data['video'], this._data['options']).then(callback); + break; + case 'location': + TgBotAPI.sendLocation(chat_id, this._data['latitude'], this._data['longitude'], this._data['options']).then(callback); + break; + case 'venue': + TgBotAPI.sendVenue(chat_id, this._data['latitude'], this._data['longitude'], this._data['title'], this._data['address'], this._data['options']).then(callback); + break; + case 'contact': + TgBotAPI.sendContact(chat_id, this._data['number'], this._data['firstName'], this._data['options']).then(callback); + break; + } + }); + } + + caption(caption){ + if(this.type == 'text') + return; + this._data['options']['caption'] = caption; + } + + replyMarkup(reply_markup){ + this._data['options']['reply_markup'] = reply_markup; + } + + markdown(){ + this._data['options']['parse_mode'] = 'markdown'; + } + + html(){ + this._data['options']['parse_mode'] = 'html'; + } + + disablePreview(){ + this._data['options']['disable_web_page_preview'] = false; + } +} diff --git a/src/classes/BotMessageSent.js b/src/classes/BotMessageSent.js new file mode 100644 index 0000000..6de168d --- /dev/null +++ b/src/classes/BotMessageSent.js @@ -0,0 +1,100 @@ +/***************************************************************************** + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + *___________________________________________________________________________* + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + *___________________________________________________________________________* + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *___________________________________________________________________________* + * Created by Qti3e * + * LO-VE * + *****************************************************************************/ +class BotMessageSent{ + save(){ + return JSON.stringify([this.message, this.type, this._q]); + } + + load(json, user){ + this.chat_id = user.id; + // json = JSON.parse(json); + json.forEach(value => { + var method = value[0], + args = [], + key; + for(key in value[1]){ + args.push(value[1][key]); + } + this[method](...args); + }); + } + + _load(message){ + this.message = message; + this.id = message.message_id; + this.from = message.from ? new User(message.from) : undefined; + this.chat = message.chat instanceof User ? message.chat : new User(message.chat); + this.forward_from = message.forward_from ? new User(message.forward_from) : undefined; + } + + constructor(message, type, chat_id){ + this._q = []; + this._load(message); + this.type = type; + this.chat_id = chat_id; + } + + editCaption(newCaption, options){ + this._q.push(['editCaption', arguments]); + options = options || {}; + if(this.message.reply_markup) + options.reply_markup = this.message.reply_markup; + return new Promise((resolve) => { + global.TgBotApi.editMessageCaption(newCaption, options, { + chat_id : this.chat_id, + message_id : this.id + }).then((msg) => { + this._load(msg); + resolve(this); + }) + }); + } + + editText(newText, options){ + this._q.push(['editText', arguments]); + options = options || {}; + if(newText == this.message.text) + return; + return new Promise((resolve) => { + options.chat_id = this.chat_id; + options.message_id = this.id; + global.TgBotApi.editMessageText(newText, options).then((msg) => { + this._load(msg); + global.RedisClient.hset(':u' + this.chat_id, ':lastmsg', JSON.stringify({ + id: this.id, + type: this.type, + text: newText + })); + resolve(this); + }) + }); + } + + editReplyMarkup(reply_markup){ + this._q.push(['editReplyMarkup', arguments]); + return new Promise((resolve) => { + global.TgBotApi.editMessageReplyMarkup(reply_markup, { + chat_id : this.chat_id, + message_id : this.id + }).then((msg) => { + this._load(msg); + resolve(this); + }) + }) + } +} \ No newline at end of file diff --git a/src/classes/TemplateEngine.js b/src/classes/TemplateEngine.js new file mode 100644 index 0000000..99dd2b9 --- /dev/null +++ b/src/classes/TemplateEngine.js @@ -0,0 +1,34 @@ +/***************************************************************************** + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + *___________________________________________________________________________* + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + *___________________________________________________________________________* + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *___________________________________________________________________________* + * Created by Qti3e * + * LO-VE * + *****************************************************************************/ + +const handlebars = require('handlebars'), + fs = require('fs'); +global._templateCache = {}; +function TemplateEngine(fileName) { + var template; + if(global._templateCache[fileName]){ + template = global._templateCache[fileName]; + }else { + var file = fs.readFileSync(fileName) + ''; + template = handlebars.compile(file); + global._templateCache[fileName] = template; + } + return (vars) => { + return template(vars); + }; +} \ No newline at end of file diff --git a/src/classes/User.js b/src/classes/User.js new file mode 100644 index 0000000..f1bbc59 --- /dev/null +++ b/src/classes/User.js @@ -0,0 +1,134 @@ +/***************************************************************************** + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + *___________________________________________________________________________* + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + *___________________________________________________________________________* + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *___________________________________________________________________________* + * Created by Qti3e * + * LO-VE * + *****************************************************************************/ + +/** + * This class is an object of a user, which means all of implements of this class + * are kindly a Telegram account, you can send them a message, video, ... or + * receive messages from them + */ +class User { + /** + * Set the initial user's value like id and name, etc... + * @param user + */ + constructor(user) { + this.id = user.id; + this.first_name = user.first_name; + this.last_name = user.last_name; + this.username = user.username; + this.language_code = user.language_code; + } + + /** + * Check if a user is member of a chat or not. + * The chat might be a chanel id. (But it requires administration permissions) + * @param chat_id + * @param force_update + * @returns {Promise} + */ + isMemberOf(chat_id, force_update = false){ + return new Promise((resolve) => { + global.RedisClient.get('i:' + this.id, (err, re) => { + if(re == null || force_update){ + global.TgBotApi.getChatMember(chat_id, this.id).then((ChatMember) => { + var re = ChatMember.status && (ChatMember.status == 'member' || ChatMember.status == 'administrator' || ChatMember.status == 'creator'); + global.RedisClient.set('i:' + this.id, re ? 1 : 0); + global.RedisClient.expire('i:' + this.id, 3600); + resolve(re); + }); + }else { + re = parseInt(re); + if(re){ + resolve(true); + }else { + resolve(false); + } + } + }); + }); + } + + /** + * Set a value for user (This function is like setting cookies) + * @param key + * @param value + * @returns {*} + */ + set(key, value){ + return global.RedisClient.hset(':u' + this.id, key, JSON.stringify(value)); + } + + /** + * Get a cookie value + * @param key + * @param callback + * @returns {string} + */ + get(key, callback){ + global.RedisClient.hget(':u' + this.id, key, (err, re) => { + if(typeof callback !== 'function') + return; + callback((re == '' || re == null || re == undefined) ? '' : JSON.parse(re)) + }); + } + + mGet(keys, callback){ + global.RedisClient.hmget(':u' + this.id, keys, (err, re) => { + if(typeof callback !== 'function') + return; + re.forEach((value, key) => { + re[key] = (value == '' || value == null || value == undefined) ? '' : JSON.parse(value); + }); + callback.apply(null, re); + }); + } + + del(key, callback){ + global.RedisClient.del(':u' + this.id, key, (err, re) => { + if(typeof callback !== 'function') + return; + callback(re); + }) + } + + /** + * + * @param message + * @returns {Promise} + */ + send(message){ + return new BotMessage('text', message, arguments[1]).send(this); + } + + /** + * Get the latest message that has been sent to user + * @param callback + */ + getLastMessage(callback){ + this.get(':lastmsg', (msg) => { + if(typeof msg == 'object') + callback(new BotMessageSent({ + message_id: msg.id, + chat: this, + text: msg.text + }, msg.type, this.id)); + else + callback(false) + }) + } +} \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..a886b8d --- /dev/null +++ b/src/index.js @@ -0,0 +1,34 @@ +/***************************************************************************** + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + *___________________________________________________________________________* + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + *___________________________________________________________________________* + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *___________________________________________________________________________* + * Created by Qti3e * + * LO-VE * + *****************************************************************************/ + +// Load main dependencies +const TelegramBot = require('node-telegram-bot-api'), + redis = require("redis"); + +// Set some global vars +// Note: because of this problem you won't be able to run more than one bot in each JS file. +global.RedisClient = redis.createClient(); +global.TgBotApi = undefined; + +// Include classes +module.exports = { + BotMessage: BotMessage, + Bot: Bot, + User: User, + Pug: TemplateEngine +};