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
JavaScript
"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