UNPKG

nowjs-web-telegram-api

Version:

NowCanDo Javascript Web Telegram Api [nowjs-web-telegram-api] is a library written by TypeScript code maintains under Apache 2.0 licence

626 lines 19.6 kB
"use strict"; const events_1 = require("events"); const stream_1 = require("stream"); const request = require("request-promise-native"); const path = require("path"); const mime = require("mime"); const URL = require("url"); const qs = require("querystring"); const FileType = require("file-type"); const http = require("http"); const https = require("https"); const fs = require("fs"); const bl = require('bl'); function timeout(ms, err) { let pr = this; return new Promise(function (resolve, reject) { pr.then(resolve); let err1 = new Error('Timeout after ' + ms + ' ms'); if (err) { err1 = (err instanceof Error ? err : new Error(err)); } setTimeout(function () { reject(new Error()); }, ms); }); } exports.timeout = timeout; ; Promise.constructor.prototype.timeout = timeout; Promise.prototype.timeout = timeout; const _messageTypes = [ 'text', 'audio', 'document', 'photo', 'sticker', 'video', 'voice', 'contact', 'location', 'new_chat_participant', 'left_chat_participant', 'new_chat_title', 'new_chat_photo', 'delete_chat_photo', 'group_chat_created' ]; const ANOTHER_WEB_HOOK_USED = 409; class TelegramBotPolling { constructor(token, options = {}, callback) { this.token = token; this.callback = callback; if (typeof options === 'function') { callback = options; options = {}; } this.offset = 0; this.token = token; this.callback = callback; this.timeout = options.timeout || 10; this.interval = (typeof options.interval === 'number') ? options.interval : 300; this.lastUpdate = 0; this.lastRequest = null; this.abort = false; this._polling(); } stopPolling() { this.abort = true; return this.lastRequest; } _polling() { this.lastRequest = this ._getUpdates() .then((updates) => { this.lastUpdate = Date.now(); updates.forEach((update) => { this.offset = update.update_id; this.callback(update); }); if (this.abort) { } else { setTimeout(() => this._polling(), this.interval); } }) .catch((err) => { throw err; }); } _safeParse(json) { try { return JSON.parse(json); } catch (err) { throw new Error(`Error parsing Telegram response: ${String(json)}`); } } _unsetWebHook() { return request({ url: URL.format({ protocol: 'https', host: 'api.telegram.org', pathname: `/bot${this.token}/setWebHook` }), simple: false, resolveWithFullResponse: true }) .promise() .then(resp => { if (!resp) { throw new Error(resp); } return []; }); } _getUpdates() { const opts = { qs: { offset: this.offset + 1, limit: this.limit, timeout: this.timeout }, url: URL.format({ protocol: 'https', host: 'api.telegram.org', pathname: `/bot${this.token}/getUpdates` }), simple: false, resolveWithFullResponse: true, forever: true, }; return request(opts) .promise() .timeout((10 + this.timeout) * 1000) .then((resp) => { if (resp.statusCode === ANOTHER_WEB_HOOK_USED) { return this._unsetWebHook(); } if (resp.statusCode !== 200) { throw new Error(`${resp.statusCode} ${resp.body}`); } const data = this._safeParse(resp.body); if (data.ok) { return data.result; } throw new Error(`${data.error_code} ${data.description}`); }); } } exports.TelegramBotPolling = TelegramBotPolling; class TelegramBotWebHook { constructor(token, options, callback) { this.token = token; this.callback = callback; this._parseBody = (err, body) => { if (err) { return err; } const data = this._safeParse(body); if (data) { return this.callback(data); } return null; }; this._requestListener = (req, res) => { if (!this.regex.test(req.url)) { res.statusCode = 401; res.end(); } else if (req.method === 'POST') { req .pipe(bl(this._parseBody)) .on('finish', () => res.end('OK')); } else { res.statusCode = 418; res.end(); } }; this.token = token; this.callback = callback; this.regex = new RegExp(this.token); if (typeof options === 'boolean') { options = {}; } options.port = options.port || 8443; if (options.key && options.cert) { const opts = { key: fs.readFileSync(options.key), cert: fs.readFileSync(options.cert) }; this._webServer = https.createServer(opts, this._requestListener); } else { this._webServer = http.createServer(this._requestListener); } this._webServer.listen(options.port, options.host, () => { }); } _safeParse(json) { try { return JSON.parse(json); } catch (err) { return null; } } } exports.TelegramBotWebHook = TelegramBotWebHook; class TelegramBot extends events_1.EventEmitter { constructor(options) { super(); this.textRegexpCallbacks = []; this.onReplyToMessages = []; this.onCommands = []; this.onEvents = []; this._isRunning = false; this._baseurl = 'https://api.telegram.org/bot'; if (!options || !options.token) { throw new Error("Telegram Bot Api need to set 'token' for communication"); } this._baseurl += options.token + '/'; this._options = options; if (options.polling && options.polling.enabled == true) { this.initPolling(); } if (options.webhook) { this._WebHook = new TelegramBotWebHook(options.token, options.webhook, this.processUpdate.bind(this)); } } static get MessageTypes() { return _messageTypes; } initPolling() { if (this._polling) { this._polling.abort = true; } this._polling = new TelegramBotPolling(this._options.token, this._options.polling, this.processUpdate.bind(this)); } stopPolling() { if (this._polling) { return this._polling.stopPolling(); } return Promise.resolve(); } safeParse(json) { try { return JSON.parse(json); } catch (err) { throw new Error(`Error parsing Telegram response: ${String(json)}`); } } fixReplyMarkup(obj) { const replyMarkup = obj.reply_markup; if (replyMarkup && typeof replyMarkup !== 'string') { obj.reply_markup = JSON.stringify(replyMarkup); } } formatSendData(type, data) { let formData; let fileName; let fileId; if (data instanceof stream_1.Stream) { fileName = URL.parse(path.basename(data.path.toString())).pathname; formData = {}; formData[type] = { value: data, options: { filename: qs.unescape(fileName), contentType: mime.lookup(fileName) } }; } else if (Buffer.isBuffer(data)) { const filetype = FileType(data); if (!filetype) { throw new Error('Unsupported Buffer file type'); } formData = {}; formData[type] = { value: data, options: { filename: `data.${filetype.ext}`, contentType: filetype.mime } }; } else if (fs.existsSync(data)) { fileName = path.basename(data); formData = {}; formData[type] = { value: fs.createReadStream(data), options: { filename: fileName, contentType: mime.lookup(fileName) } }; } else { fileId = data; } return [formData, fileId]; } makeRequest(urlpath, options) { options = options || {}; if (this._options.request) { Object.assign(options, this._options.request); } if (options.form) { this.fixReplyMarkup(options.form); } if (options.qs) { this.fixReplyMarkup(options.qs); } options.url = this._baseurl + urlpath; options.simple = false; options.resolveWithFullResponse = true; options.forever = true; return request(options) .then(resp => { if (resp.statusCode !== 200) { throw new Error(`${resp.statusCode} ${resp.body}`); } const data = this.safeParse(resp.body); if (data.ok) { return data.result; } throw new Error(`${data.error_code} ${data.description}`); }); } processUpdate(update) { const message = update.message; const editedMessage = update.edited_message; const inlineQuery = update.inline_query; const chosenInlineResult = update.chosen_inline_result; const callbackQuery = update.callback_query; if (message) { this.emit('message', message); const processMessageType = (messageType) => { if (message[messageType]) { this.emit(messageType, message); } }; TelegramBot.MessageTypes.forEach(processMessageType); if (message.text) { this.textRegexpCallbacks.some(reg => { const result = reg.regexp.exec(message.text); if (result) { reg.callback(message, result); return this._options.onlyFirstMatch; } }); } if (message.reply_to_message) { this.onReplyToMessages.forEach(reply => { if (reply.chatId === message.chat.id) { if (reply.messageId === message.reply_to_message.message_id) { reply.callback(message); } } }); } } else if (editedMessage) { this.emit('edited_message', editedMessage); if (editedMessage.text) { this.emit('edited_message_text', editedMessage); } if (editedMessage.caption) { this.emit('edited_message_caption', editedMessage); } } else if (inlineQuery) { this.emit('inline_query', inlineQuery); } else if (chosenInlineResult) { this.emit('chosen_inline_result', chosenInlineResult); } else if (callbackQuery) { this.emit('callback_query', callbackQuery); } } initBot() { return this.getMe() .then((result) => { if (result) { this._botUser = result; return true; } return false; }); } start() { if (this._isRunning == false) { return this.initBot(); } else { return Promise.resolve(false); } } stop() { if (this._isRunning == true) { } else { return Promise.resolve(false); } } getUpdates(options) { const form = options; return this.makeRequest('getUpdates', { form }); } setWebhook(options) { const url = options.url; const _path = 'setWebHook'; const opts = { qs: { url } }; if (options.certificate) { const [formData, certificate] = this.formatSendData('certificate', options.certificate); opts.formData = formData; opts.qs.certificate = certificate; } return this.makeRequest(_path, opts) .then(resp => { if (!resp) { throw new Error(resp); } return resp; }); } getWebhookInfo() { return this.makeRequest('getWebhookInfo'); } getMe() { const _path = 'getMe'; return this.makeRequest(_path); } sendMessage(options) { const form = options; return this.makeRequest('sendMessage', { form }); } forwardMessage(options) { const form = options; return this.makeRequest('forwardMessage', { form }); } sendPhoto(options) { const opts = { qs: options, formData: {} }; const content = this.formatSendData('photo', options.photo); opts.formData = content[0]; opts.qs.photo = content[1]; return this.makeRequest('sendPhoto', opts); } sendAudio(options) { const opts = { qs: options, formData: {} }; const content = this.formatSendData('audio', options.audio); opts.formData = content[0]; opts.qs.audio = content[1]; return this.makeRequest('sendAudio', opts); } sendDocument(options, fileOpts) { const opts = { qs: options, formData: {} }; const content = this.formatSendData('document', options.document); opts.formData = content[0]; opts.qs.document = content[1]; if (opts.formData && Object.keys(fileOpts).length) { opts.formData.document.options = fileOpts; } return this.makeRequest('sendDocument', opts); } sendSticker(options) { const opts = { qs: options }; const content = this.formatSendData('sticker', options.sticker); opts.formData = content[0]; opts.qs.sticker = content[1]; return this.makeRequest('sendSticker', opts); } sendVideo(options) { const opts = { qs: options }; const content = this.formatSendData('video', options.video); opts.formData = content[0]; opts.qs.video = content[1]; return this.makeRequest('sendVideo', opts); } sendVoice(options) { const opts = { qs: options }; const content = this.formatSendData('voice', options.voice); opts.formData = content[0]; opts.qs.voice = content[1]; return this.makeRequest('sendVoice', opts); } sendLocation(options) { const form = options; return this.makeRequest('sendLocation', { form }); } sendVenue(options) { const form = options; return this.makeRequest('sendVenue', { form }); } sendContact(options) { const form = options; return this.makeRequest('sendContact', { form }); } sendChatAction(options) { const form = options; return this.makeRequest('sendChatAction', { form }); } getUserProfilePhotos(options) { const form = options; return this.makeRequest('getUserProfilePhotos', { form }); } getFile(options) { const form = options; return this.makeRequest('getFile', { form }); } getFileLink(fileId) { return this.getFile({ file_id: fileId }) .then(resp => { return this._baseurl + resp.file_path; }); } downloadFile(fileId, downloadDir) { } kickChatMember(options) { const form = options; return this.makeRequest('kickChatMember', { form }); } leaveChat(options) { const form = options; return this.makeRequest('leaveChat', { form }); } unbanChatMember(options) { const form = options; return this.makeRequest('unbanChatMember', { form }); } getChat(options) { const form = options; return this.makeRequest('getChat', { form }); } getChatAdministrators(options) { const form = options; return this.makeRequest('getChatAdministrators', { form }); } getChatMembersCount(options) { const form = options; return this.makeRequest('getChatMembersCount', { form }); } getChatMember(options) { const form = options; return this.makeRequest('getChatMember', { form }); } answerCallbackQuery(options) { const form = options; return this.makeRequest('answerCallbackQuery', { form }); } editMessageText(options) { const form = options; return this.makeRequest('editMessageText', { form }); } editMessageCaption(options) { const form = options; return this.makeRequest('editMessageCaption', { form }); } editMessageReplyMarkup(options) { const form = options; return this.makeRequest('editMessageReplyMarkup', { form }); } sendGame(options) { const form = options; return this.makeRequest('sendGame', { form }); } setGameScore(options) { const form = options; return this.makeRequest('setGameScore', { form }); } getGameHighScores(options) { const form = options; return this.makeRequest('getGameHighScores', { form }); } answerInlineQuery(options) { const form = options; return this.makeRequest('answerInlineQuery', { form }); } onText(command) { let pr = new Promise((resolve, reject) => { let regexp; if (typeof command === "string") { regexp = new RegExp(command); } else { regexp = command; } let callback = (msg, result) => { resolve(msg); }; this.textRegexpCallbacks.push({ regexp, callback }); }); return pr; } onCommand(command) { let pr = new Promise((resolve, reject) => { let regexp; if (typeof command === "string") { regexp = new RegExp("/" + command, "ig"); } else { regexp = command; } let callback = (msg, result) => { resolve(msg); }; this.textRegexpCallbacks.push({ regexp, callback }); }); return pr; } onReplyToMessage(chatId, messageId, callback) { this.onReplyToMessages.push({ chatId, messageId, callback }); } } exports.TelegramBot = TelegramBot; //# sourceMappingURL=TelegramBotApi.js.map