Intial Commit
This commit is contained in:
65
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/errors.js
generated
vendored
Normal file
65
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/errors.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
exports.BaseError = class BaseError extends Error {
|
||||
/**
|
||||
* @class BaseError
|
||||
* @constructor
|
||||
* @private
|
||||
* @param {String} code Error code
|
||||
* @param {String} message Error message
|
||||
*/
|
||||
constructor(code, message) {
|
||||
super(`${code}: ${message}`);
|
||||
this.code = code;
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
code: this.code,
|
||||
message: this.message,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.FatalError = class FatalError extends exports.BaseError {
|
||||
/**
|
||||
* Fatal Error. Error code is `"EFATAL"`.
|
||||
* @class FatalError
|
||||
* @constructor
|
||||
* @param {String|Error} data Error object or message
|
||||
*/
|
||||
constructor(data) {
|
||||
const error = (typeof data === 'string') ? null : data;
|
||||
const message = error ? error.message : data;
|
||||
super('EFATAL', message);
|
||||
if (error) this.stack = error.stack;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.ParseError = class ParseError extends exports.BaseError {
|
||||
/**
|
||||
* Error during parsing. Error code is `"EPARSE"`.
|
||||
* @class ParseError
|
||||
* @constructor
|
||||
* @param {String} message Error message
|
||||
* @param {http.IncomingMessage} response Server response
|
||||
*/
|
||||
constructor(message, response) {
|
||||
super('EPARSE', message);
|
||||
this.response = response;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.TelegramError = class TelegramError extends exports.BaseError {
|
||||
/**
|
||||
* Error returned from Telegram. Error code is `"ETELEGRAM"`.
|
||||
* @class TelegramError
|
||||
* @constructor
|
||||
* @param {String} message Error message
|
||||
* @param {http.IncomingMessage} response Server response
|
||||
*/
|
||||
constructor(message, response) {
|
||||
super('ETELEGRAM', message);
|
||||
this.response = response;
|
||||
}
|
||||
};
|
||||
1966
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/telegram.js
generated
vendored
Normal file
1966
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/telegram.js
generated
vendored
Normal file
@@ -0,0 +1,1966 @@
|
||||
// shims
|
||||
require('array.prototype.findindex').shim(); // for Node.js v0.x
|
||||
|
||||
const errors = require('./errors');
|
||||
const TelegramBotWebHook = require('./telegramWebHook');
|
||||
const TelegramBotPolling = require('./telegramPolling');
|
||||
const debug = require('debug')('node-telegram-bot-api');
|
||||
const EventEmitter = require('eventemitter3');
|
||||
const fileType = require('file-type');
|
||||
const request = require('request-promise');
|
||||
const streamedRequest = require('request');
|
||||
const qs = require('querystring');
|
||||
const stream = require('stream');
|
||||
const mime = require('mime');
|
||||
const path = require('path');
|
||||
const URL = require('url');
|
||||
const fs = require('fs');
|
||||
const pump = require('pump');
|
||||
const deprecate = require('depd')('node-telegram-bot-api');
|
||||
let Promise = require('bluebird');
|
||||
|
||||
const _messageTypes = [
|
||||
'text',
|
||||
'animation',
|
||||
'audio',
|
||||
'channel_chat_created',
|
||||
'contact',
|
||||
'delete_chat_photo',
|
||||
'document',
|
||||
'game',
|
||||
'group_chat_created',
|
||||
'invoice',
|
||||
'left_chat_member',
|
||||
'location',
|
||||
'migrate_from_chat_id',
|
||||
'migrate_to_chat_id',
|
||||
'new_chat_members',
|
||||
'new_chat_photo',
|
||||
'new_chat_title',
|
||||
'passport_data',
|
||||
'photo',
|
||||
'pinned_message',
|
||||
'poll',
|
||||
'sticker',
|
||||
'successful_payment',
|
||||
'supergroup_chat_created',
|
||||
'video',
|
||||
'video_note',
|
||||
'voice',
|
||||
];
|
||||
const _deprecatedMessageTypes = [
|
||||
'new_chat_participant', 'left_chat_participant'
|
||||
];
|
||||
|
||||
|
||||
if (!process.env.NTBA_FIX_319) {
|
||||
// Enable Promise cancellation.
|
||||
try {
|
||||
const msg =
|
||||
'Automatic enabling of cancellation of promises is deprecated.\n' +
|
||||
'In the future, you will have to enable it yourself.\n' +
|
||||
'See https://github.com/yagop/node-telegram-bot-api/issues/319.';
|
||||
deprecate(msg);
|
||||
Promise.config({
|
||||
cancellation: true,
|
||||
});
|
||||
} catch (ex) {
|
||||
/* eslint-disable no-console */
|
||||
const msg =
|
||||
'error: Enabling Promise cancellation failed.\n' +
|
||||
' Temporary fix is to load/require this library as early as possible before using any Promises.';
|
||||
console.error(msg);
|
||||
throw ex;
|
||||
/* eslint-enable no-console */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JSON-serialize data. If the provided data is already a String,
|
||||
* return it as is.
|
||||
* @private
|
||||
* @param {*} data
|
||||
* @return {String}
|
||||
*/
|
||||
function stringify(data) {
|
||||
if (typeof data === 'string') {
|
||||
return data;
|
||||
}
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
|
||||
class TelegramBot extends EventEmitter {
|
||||
/**
|
||||
* The different errors the library uses.
|
||||
* @type {Object}
|
||||
*/
|
||||
static get errors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* The types of message updates the library handles.
|
||||
* @type {String[]}
|
||||
*/
|
||||
static get messageTypes() {
|
||||
return _messageTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Promise library used internally, for all existing and new
|
||||
* instances.
|
||||
* @param {Function} customPromise
|
||||
*
|
||||
* @example
|
||||
* const TelegramBot = require('node-telegram-bot-api');
|
||||
* TelegramBot.Promise = myPromise;
|
||||
*/
|
||||
static set Promise(customPromise) {
|
||||
Promise = customPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener for the specified [event](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events).
|
||||
* This is the usual `emitter.on()` method.
|
||||
* @param {String} event
|
||||
* @param {Function} listener
|
||||
* @see {@link https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events|Available events}
|
||||
* @see https://nodejs.org/api/events.html#events_emitter_on_eventname_listener
|
||||
*/
|
||||
on(event, listener) {
|
||||
if (_deprecatedMessageTypes.indexOf(event) !== -1) {
|
||||
const url = 'https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events';
|
||||
deprecate(`Events ${_deprecatedMessageTypes.join(',')} are deprecated. See the updated list of events: ${url}`);
|
||||
}
|
||||
super.on(event, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Both request method to obtain messages are implemented. To use standard polling, set `polling: true`
|
||||
* on `options`. Notice that [webHook](https://core.telegram.org/bots/api#setwebhook) will need a SSL certificate.
|
||||
* Emits `message` when a message arrives.
|
||||
*
|
||||
* @class TelegramBot
|
||||
* @constructor
|
||||
* @param {String} token Bot Token
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean|Object} [options.polling=false] Set true to enable polling or set options.
|
||||
* If a WebHook has been set, it will be deleted automatically.
|
||||
* @param {String|Number} [options.polling.timeout=10] *Deprecated. Use `options.polling.params` instead*.
|
||||
* Timeout in seconds for long polling.
|
||||
* @param {String|Number} [options.polling.interval=300] Interval between requests in miliseconds
|
||||
* @param {Boolean} [options.polling.autoStart=true] Start polling immediately
|
||||
* @param {Object} [options.polling.params] Parameters to be used in polling API requests.
|
||||
* See https://core.telegram.org/bots/api#getupdates for more information.
|
||||
* @param {Number} [options.polling.params.timeout=10] Timeout in seconds for long polling.
|
||||
* @param {Boolean|Object} [options.webHook=false] Set true to enable WebHook or set options
|
||||
* @param {String} [options.webHook.host="0.0.0.0"] Host to bind to
|
||||
* @param {Number} [options.webHook.port=8443] Port to bind to
|
||||
* @param {String} [options.webHook.key] Path to file with PEM private key for webHook server.
|
||||
* The file is read **synchronously**!
|
||||
* @param {String} [options.webHook.cert] Path to file with PEM certificate (public) for webHook server.
|
||||
* The file is read **synchronously**!
|
||||
* @param {String} [options.webHook.pfx] Path to file with PFX private key and certificate chain for webHook server.
|
||||
* The file is read **synchronously**!
|
||||
* @param {Boolean} [options.webHook.autoOpen=true] Open webHook immediately
|
||||
* @param {Object} [options.webHook.https] Options to be passed to `https.createServer()`.
|
||||
* Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be
|
||||
* used to override `key`, `cert` and `pfx` in this object, respectively.
|
||||
* See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information.
|
||||
* @param {String} [options.webHook.healthEndpoint="/healthz"] An endpoint for health checks that always responds with 200 OK
|
||||
* @param {Boolean} [options.onlyFirstMatch=false] Set to true to stop after first match. Otherwise, all regexps are executed
|
||||
* @param {Object} [options.request] Options which will be added for all requests to telegram api.
|
||||
* See https://github.com/request/request#requestoptions-callback for more information.
|
||||
* @param {String} [options.baseApiUrl="https://api.telegram.org"] API Base URl; useful for proxying and testing
|
||||
* @param {Boolean} [options.filepath=true] Allow passing file-paths as arguments when sending files,
|
||||
* such as photos using `TelegramBot#sendPhoto()`. See [usage information][usage-sending-files-performance]
|
||||
* for more information on this option and its consequences.
|
||||
* @param {Boolean} [options.badRejection=false] Set to `true`
|
||||
* **if and only if** the Node.js version you're using terminates the
|
||||
* process on unhandled rejections. This option is only for
|
||||
* *forward-compatibility purposes*.
|
||||
* @see https://core.telegram.org/bots/api
|
||||
*/
|
||||
constructor(token, options = {}) {
|
||||
super();
|
||||
this.token = token;
|
||||
this.options = options;
|
||||
this.options.polling = (typeof options.polling === 'undefined') ? false : options.polling;
|
||||
this.options.webHook = (typeof options.webHook === 'undefined') ? false : options.webHook;
|
||||
this.options.baseApiUrl = options.baseApiUrl || 'https://api.telegram.org';
|
||||
this.options.filepath = (typeof options.filepath === 'undefined') ? true : options.filepath;
|
||||
this.options.badRejection = (typeof options.badRejection === 'undefined') ? false : options.badRejection;
|
||||
this._textRegexpCallbacks = [];
|
||||
this._replyListenerId = 0;
|
||||
this._replyListeners = [];
|
||||
this._polling = null;
|
||||
this._webHook = null;
|
||||
|
||||
if (options.polling) {
|
||||
const autoStart = options.polling.autoStart;
|
||||
if (typeof autoStart === 'undefined' || autoStart === true) {
|
||||
this.startPolling();
|
||||
}
|
||||
}
|
||||
|
||||
if (options.webHook) {
|
||||
const autoOpen = options.webHook.autoOpen;
|
||||
if (typeof autoOpen === 'undefined' || autoOpen === true) {
|
||||
this.openWebHook();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates url with bot token and provided path/method you want to be got/executed by bot
|
||||
* @param {String} path
|
||||
* @return {String} url
|
||||
* @private
|
||||
* @see https://core.telegram.org/bots/api#making-requests
|
||||
*/
|
||||
_buildURL(_path) {
|
||||
return `${this.options.baseApiUrl}/bot${this.token}/${_path}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix 'reply_markup' parameter by making it JSON-serialized, as
|
||||
* required by the Telegram Bot API
|
||||
* @param {Object} obj Object; either 'form' or 'qs'
|
||||
* @private
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
_fixReplyMarkup(obj) {
|
||||
const replyMarkup = obj.reply_markup;
|
||||
if (replyMarkup && typeof replyMarkup !== 'string') {
|
||||
obj.reply_markup = stringify(replyMarkup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request against the API
|
||||
* @param {String} _path API endpoint
|
||||
* @param {Object} [options]
|
||||
* @private
|
||||
* @return {Promise}
|
||||
*/
|
||||
_request(_path, options = {}) {
|
||||
if (!this.token) {
|
||||
return Promise.reject(new errors.FatalError('Telegram Bot Token not provided!'));
|
||||
}
|
||||
|
||||
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.method = 'POST';
|
||||
options.url = this._buildURL(_path);
|
||||
options.simple = false;
|
||||
options.resolveWithFullResponse = true;
|
||||
options.forever = true;
|
||||
debug('HTTP request: %j', options);
|
||||
return request(options)
|
||||
.then(resp => {
|
||||
let data;
|
||||
try {
|
||||
data = resp.body = JSON.parse(resp.body);
|
||||
} catch (err) {
|
||||
throw new errors.ParseError(`Error parsing response: ${resp.body}`, resp);
|
||||
}
|
||||
|
||||
if (data.ok) {
|
||||
return data.result;
|
||||
}
|
||||
|
||||
throw new errors.TelegramError(`${data.error_code} ${data.description}`, resp);
|
||||
}).catch(error => {
|
||||
// TODO: why can't we do `error instanceof errors.BaseError`?
|
||||
if (error.response) throw error;
|
||||
throw new errors.FatalError(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format data to be uploaded; handles file paths, streams and buffers
|
||||
* @param {String} type
|
||||
* @param {String|stream.Stream|Buffer} data
|
||||
* @param {Object} fileOptions File options
|
||||
* @param {String} [fileOptions.filename] File name
|
||||
* @param {String} [fileOptions.contentType] Content type (i.e. MIME)
|
||||
* @return {Array} formatted
|
||||
* @return {Object} formatted[0] formData
|
||||
* @return {String} formatted[1] fileId
|
||||
* @throws Error if Buffer file type is not supported.
|
||||
* @see https://npmjs.com/package/file-type
|
||||
* @private
|
||||
*/
|
||||
_formatSendData(type, data, fileOptions = {}) {
|
||||
const deprecationMessage =
|
||||
'See https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files' +
|
||||
' for more information on how sending files has been improved and' +
|
||||
' on how to disable this deprecation message altogether.';
|
||||
let filedata = data;
|
||||
let filename = fileOptions.filename;
|
||||
let contentType = fileOptions.contentType;
|
||||
|
||||
if (data instanceof stream.Stream) {
|
||||
if (!filename && data.path) {
|
||||
// Will be 'null' if could not be parsed.
|
||||
// For example, 'data.path' === '/?id=123' from 'request("https://example.com/?id=123")'
|
||||
const url = URL.parse(path.basename(data.path.toString()));
|
||||
if (url.pathname) {
|
||||
filename = qs.unescape(url.pathname);
|
||||
}
|
||||
}
|
||||
} else if (Buffer.isBuffer(data)) {
|
||||
if (!filename && !process.env.NTBA_FIX_350) {
|
||||
deprecate(`Buffers will have their filenames default to "filename" instead of "data". ${deprecationMessage}`);
|
||||
filename = 'data';
|
||||
}
|
||||
if (!contentType) {
|
||||
const filetype = fileType(data);
|
||||
if (filetype) {
|
||||
contentType = filetype.mime;
|
||||
const ext = filetype.ext;
|
||||
if (ext && !process.env.NTBA_FIX_350) {
|
||||
filename = `${filename}.${ext}`;
|
||||
}
|
||||
} else if (!process.env.NTBA_FIX_350) {
|
||||
deprecate(`An error will no longer be thrown if file-type of buffer could not be detected. ${deprecationMessage}`);
|
||||
throw new errors.FatalError('Unsupported Buffer file-type');
|
||||
}
|
||||
}
|
||||
} else if (data) {
|
||||
if (this.options.filepath && fs.existsSync(data)) {
|
||||
filedata = fs.createReadStream(data);
|
||||
if (!filename) {
|
||||
filename = path.basename(data);
|
||||
}
|
||||
} else {
|
||||
return [null, data];
|
||||
}
|
||||
} else {
|
||||
return [null, data];
|
||||
}
|
||||
|
||||
filename = filename || 'filename';
|
||||
contentType = contentType || mime.lookup(filename);
|
||||
if (process.env.NTBA_FIX_350) {
|
||||
contentType = contentType || 'application/octet-stream';
|
||||
} else {
|
||||
deprecate(`In the future, content-type of files you send will default to "application/octet-stream". ${deprecationMessage}`);
|
||||
}
|
||||
|
||||
// TODO: Add missing file extension.
|
||||
|
||||
return [{
|
||||
[type]: {
|
||||
value: filedata,
|
||||
options: {
|
||||
filename,
|
||||
contentType,
|
||||
},
|
||||
},
|
||||
}, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* Start polling.
|
||||
* Rejects returned promise if a WebHook is being used by this instance.
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.restart=true] Consecutive calls to this method causes polling to be restarted
|
||||
* @return {Promise}
|
||||
*/
|
||||
startPolling(options = {}) {
|
||||
if (this.hasOpenWebHook()) {
|
||||
return Promise.reject(new errors.FatalError('Polling and WebHook are mutually exclusive'));
|
||||
}
|
||||
options.restart = typeof options.restart === 'undefined' ? true : options.restart;
|
||||
if (!this._polling) {
|
||||
this._polling = new TelegramBotPolling(this);
|
||||
}
|
||||
return this._polling.start(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of `TelegramBot#startPolling()`. This is **deprecated**.
|
||||
* @param {Object} [options]
|
||||
* @return {Promise}
|
||||
* @deprecated
|
||||
*/
|
||||
initPolling() {
|
||||
deprecate('TelegramBot#initPolling() is deprecated. Use TelegramBot#startPolling() instead.');
|
||||
return this.startPolling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops polling after the last polling request resolves.
|
||||
* Multiple invocations do nothing if polling is already stopped.
|
||||
* Returning the promise of the last polling request is **deprecated**.
|
||||
* @param {Object} [options] Options
|
||||
* @param {Boolean} [options.cancel] Cancel current request
|
||||
* @param {String} [options.reason] Reason for stopping polling
|
||||
* @return {Promise}
|
||||
*/
|
||||
stopPolling(options) {
|
||||
if (!this._polling) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._polling.stop(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if polling. Otherwise, false.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isPolling() {
|
||||
return this._polling ? this._polling.isPolling() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open webhook.
|
||||
* Multiple invocations do nothing if webhook is already open.
|
||||
* Rejects returned promise if Polling is being used by this instance.
|
||||
* @return {Promise}
|
||||
*/
|
||||
openWebHook() {
|
||||
if (this.isPolling()) {
|
||||
return Promise.reject(new errors.FatalError('WebHook and Polling are mutually exclusive'));
|
||||
}
|
||||
if (!this._webHook) {
|
||||
this._webHook = new TelegramBotWebHook(this);
|
||||
}
|
||||
return this._webHook.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close webhook after closing all current connections.
|
||||
* Multiple invocations do nothing if webhook is already closed.
|
||||
* @return {Promise} promise
|
||||
*/
|
||||
closeWebHook() {
|
||||
if (!this._webHook) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._webHook.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if using webhook and it is open i.e. accepts connections.
|
||||
* Otherwise, false.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
hasOpenWebHook() {
|
||||
return this._webHook ? this._webHook.isOpen() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns basic information about the bot in form of a `User` object.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getme
|
||||
*/
|
||||
getMe(form = {}) {
|
||||
return this._request('getMe', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an url to receive incoming updates via an outgoing webHook.
|
||||
* This method has an [older, compatible signature][setWebHook-v0.25.0]
|
||||
* that is being deprecated.
|
||||
*
|
||||
* @param {String} url URL where Telegram will make HTTP Post. Leave empty to
|
||||
* delete webHook.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {String|stream.Stream} [options.certificate] PEM certificate key (public).
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setwebhook
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
setWebHook(url, options = {}, fileOptions = {}) {
|
||||
/* The older method signature was setWebHook(url, cert).
|
||||
* We need to ensure backwards-compatibility while maintaining
|
||||
* consistency of the method signatures throughout the library */
|
||||
let cert;
|
||||
// Note: 'options' could be an object, if a stream was provided (in place of 'cert')
|
||||
if (typeof options !== 'object' || options instanceof stream.Stream) {
|
||||
deprecate('The method signature setWebHook(url, cert) has been deprecated since v0.25.0');
|
||||
cert = options;
|
||||
options = {}; // eslint-disable-line no-param-reassign
|
||||
} else {
|
||||
cert = options.certificate;
|
||||
}
|
||||
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.url = url;
|
||||
|
||||
if (cert) {
|
||||
try {
|
||||
const sendData = this._formatSendData('certificate', cert, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.certificate = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return this._request('setWebHook', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to remove webhook integration if you decide to
|
||||
* switch back to getUpdates. Returns True on success.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#deletewebhook
|
||||
*/
|
||||
deleteWebHook(form = {}) {
|
||||
return this._request('deleteWebhook', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get current webhook status.
|
||||
* On success, returns a [WebhookInfo](https://core.telegram.org/bots/api#webhookinfo) object.
|
||||
* If the bot is using getUpdates, will return an object with the
|
||||
* url field empty.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getwebhookinfo
|
||||
*/
|
||||
getWebHookInfo(form = {}) {
|
||||
return this._request('getWebhookInfo', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to receive incoming updates using long polling.
|
||||
* This method has an [older, compatible signature][getUpdates-v0.25.0]
|
||||
* that is being deprecated.
|
||||
*
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getupdates
|
||||
*/
|
||||
getUpdates(form = {}) {
|
||||
/* The older method signature was getUpdates(timeout, limit, offset).
|
||||
* We need to ensure backwards-compatibility while maintaining
|
||||
* consistency of the method signatures throughout the library */
|
||||
if (typeof form !== 'object') {
|
||||
/* eslint-disable no-param-reassign, prefer-rest-params */
|
||||
deprecate('The method signature getUpdates(timeout, limit, offset) has been deprecated since v0.25.0');
|
||||
form = {
|
||||
timeout: arguments[0],
|
||||
limit: arguments[1],
|
||||
offset: arguments[2],
|
||||
};
|
||||
/* eslint-enable no-param-reassign, prefer-rest-params */
|
||||
}
|
||||
|
||||
return this._request('getUpdates', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an update; emitting the proper events and executing regexp
|
||||
* callbacks. This method is useful should you be using a different
|
||||
* way to fetch updates, other than those provided by TelegramBot.
|
||||
* @param {Object} update
|
||||
* @see https://core.telegram.org/bots/api#update
|
||||
*/
|
||||
processUpdate(update) {
|
||||
debug('Process Update %j', update);
|
||||
const message = update.message;
|
||||
const editedMessage = update.edited_message;
|
||||
const channelPost = update.channel_post;
|
||||
const editedChannelPost = update.edited_channel_post;
|
||||
const inlineQuery = update.inline_query;
|
||||
const chosenInlineResult = update.chosen_inline_result;
|
||||
const callbackQuery = update.callback_query;
|
||||
const shippingQuery = update.shipping_query;
|
||||
const preCheckoutQuery = update.pre_checkout_query;
|
||||
const poll = update.poll;
|
||||
|
||||
if (message) {
|
||||
debug('Process Update message %j', message);
|
||||
const metadata = {};
|
||||
metadata.type = TelegramBot.messageTypes.find((messageType) => {
|
||||
return message[messageType];
|
||||
});
|
||||
this.emit('message', message, metadata);
|
||||
if (metadata.type) {
|
||||
debug('Emitting %s: %j', metadata.type, message);
|
||||
this.emit(metadata.type, message, metadata);
|
||||
}
|
||||
if (message.text) {
|
||||
debug('Text message');
|
||||
this._textRegexpCallbacks.some(reg => {
|
||||
debug('Matching %s with %s', message.text, reg.regexp);
|
||||
const result = reg.regexp.exec(message.text);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
// reset index so we start at the beginning of the regex each time
|
||||
reg.regexp.lastIndex = 0;
|
||||
debug('Matches %s', reg.regexp);
|
||||
reg.callback(message, result);
|
||||
// returning truthy value exits .some
|
||||
return this.options.onlyFirstMatch;
|
||||
});
|
||||
}
|
||||
if (message.reply_to_message) {
|
||||
// Only callbacks waiting for this message
|
||||
this._replyListeners.forEach(reply => {
|
||||
// Message from the same chat
|
||||
if (reply.chatId === message.chat.id) {
|
||||
// Responding to that message
|
||||
if (reply.messageId === message.reply_to_message.message_id) {
|
||||
// Resolve the promise
|
||||
reply.callback(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (editedMessage) {
|
||||
debug('Process Update edited_message %j', 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 (channelPost) {
|
||||
debug('Process Update channel_post %j', channelPost);
|
||||
this.emit('channel_post', channelPost);
|
||||
} else if (editedChannelPost) {
|
||||
debug('Process Update edited_channel_post %j', editedChannelPost);
|
||||
this.emit('edited_channel_post', editedChannelPost);
|
||||
if (editedChannelPost.text) {
|
||||
this.emit('edited_channel_post_text', editedChannelPost);
|
||||
}
|
||||
if (editedChannelPost.caption) {
|
||||
this.emit('edited_channel_post_caption', editedChannelPost);
|
||||
}
|
||||
} else if (inlineQuery) {
|
||||
debug('Process Update inline_query %j', inlineQuery);
|
||||
this.emit('inline_query', inlineQuery);
|
||||
} else if (chosenInlineResult) {
|
||||
debug('Process Update chosen_inline_result %j', chosenInlineResult);
|
||||
this.emit('chosen_inline_result', chosenInlineResult);
|
||||
} else if (callbackQuery) {
|
||||
debug('Process Update callback_query %j', callbackQuery);
|
||||
this.emit('callback_query', callbackQuery);
|
||||
} else if (shippingQuery) {
|
||||
debug('Process Update shipping_query %j', shippingQuery);
|
||||
this.emit('shipping_query', shippingQuery);
|
||||
} else if (preCheckoutQuery) {
|
||||
debug('Process Update pre_checkout_query %j', preCheckoutQuery);
|
||||
this.emit('pre_checkout_query', preCheckoutQuery);
|
||||
} else if (poll) {
|
||||
debug('Process Update poll %j', poll);
|
||||
this.emit('poll', poll);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send text message.
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} text Text of the message to be sent
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
sendMessage(chatId, text, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.text = text;
|
||||
return this._request('sendMessage', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send answers to an inline query.
|
||||
* @param {String} inlineQueryId Unique identifier of the query
|
||||
* @param {InlineQueryResult[]} results An array of results for the inline query
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#answerinlinequery
|
||||
*/
|
||||
answerInlineQuery(inlineQueryId, results, form = {}) {
|
||||
form.inline_query_id = inlineQueryId;
|
||||
form.results = stringify(results);
|
||||
return this._request('answerInlineQuery', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward messages of any kind.
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {Number|String} fromChatId Unique identifier for the chat where the
|
||||
* original message was sent
|
||||
* @param {Number|String} messageId Unique message identifier
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
*/
|
||||
forwardMessage(chatId, fromChatId, messageId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.from_chat_id = fromChatId;
|
||||
form.message_id = messageId;
|
||||
return this._request('forwardMessage', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send photo
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} photo A file path or a Stream. Can
|
||||
* also be a `file_id` previously uploaded
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendphoto
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendPhoto(chatId, photo, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('photo', photo, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.photo = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendPhoto', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send audio
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} audio A file path, Stream or Buffer.
|
||||
* Can also be a `file_id` previously uploaded.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendaudio
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendAudio(chatId, audio, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('audio', audio, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.audio = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendAudio', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Document
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} doc A file path, Stream or Buffer.
|
||||
* Can also be a `file_id` previously uploaded.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendDocument
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendDocument(chatId, doc, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('document', doc, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.document = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendDocument', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send .webp stickers.
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} sticker A file path, Stream or Buffer.
|
||||
* Can also be a `file_id` previously uploaded. Stickers are WebP format files.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendsticker
|
||||
*/
|
||||
sendSticker(chatId, sticker, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('sticker', sticker, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.sticker = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendSticker', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document).
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} video A file path or Stream.
|
||||
* Can also be a `file_id` previously uploaded.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendvideo
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendVideo(chatId, video, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('video', video, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.video = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendVideo', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} animation A file path, Stream or Buffer.
|
||||
* Can also be a `file_id` previously uploaded.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendanimation
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendAnimation(chatId, animation, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('animation', animation, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.document = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendAnimation', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to send rounded square videos of upto 1 minute long.
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} videoNote A file path or Stream.
|
||||
* Can also be a `file_id` previously uploaded.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @info The length parameter is actually optional. However, the API (at time of writing) requires you to always provide it until it is fixed.
|
||||
* @see https://core.telegram.org/bots/api#sendvideonote
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendVideoNote(chatId, videoNote, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('video_note', videoNote, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.video_note = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendVideoNote', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send voice
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String|stream.Stream|Buffer} voice A file path, Stream or Buffer.
|
||||
* Can also be a `file_id` previously uploaded.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendvoice
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendVoice(chatId, voice, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('voice', voice, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.voice = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('sendVoice', opts);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send chat action.
|
||||
* `typing` for text messages,
|
||||
* `upload_photo` for photos, `record_video` or `upload_video` for videos,
|
||||
* `record_audio` or `upload_audio` for audio files, `upload_document` for general files,
|
||||
* `find_location` for location data.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} action Type of action to broadcast.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendchataction
|
||||
*/
|
||||
sendChatAction(chatId, action, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.action = action;
|
||||
return this._request('sendChatAction', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to kick a user from a group or a supergroup.
|
||||
* In the case of supergroups, the user will not be able to return
|
||||
* to the group on their own using invite links, etc., unless unbanned
|
||||
* first. The bot must be an administrator in the group for this to work.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#kickchatmember
|
||||
*/
|
||||
kickChatMember(chatId, userId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.user_id = userId;
|
||||
return this._request('kickChatMember', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to unban a previously kicked user in a supergroup.
|
||||
* The user will not return to the group automatically, but will be
|
||||
* able to join via link, etc. The bot must be an administrator in
|
||||
* the group for this to work. Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#unbanchatmember
|
||||
*/
|
||||
unbanChatMember(chatId, userId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.user_id = userId;
|
||||
return this._request('unbanChatMember', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to restrict a user in a supergroup.
|
||||
* The bot must be an administrator in the supergroup for this to work
|
||||
* and must have the appropriate admin rights. Pass True for all boolean parameters
|
||||
* to lift restrictions from a user. Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the target chat or username of the target supergroup
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#restrictchatmember
|
||||
*/
|
||||
restrictChatMember(chatId, userId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.user_id = userId;
|
||||
return this._request('restrictChatMember', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to promote or demote a user in a supergroup or a channel.
|
||||
* The bot must be an administrator in the chat for this to work
|
||||
* and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the target chat or username of the target supergroup
|
||||
* @param {Number} userId
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#promotechatmember
|
||||
*/
|
||||
promoteChatMember(chatId, userId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.user_id = userId;
|
||||
return this._request('promoteChatMember', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to export an invite link to a supergroup or a channel.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns exported invite link as String on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the target chat or username of the target supergroup
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#exportchatinvitelink
|
||||
*/
|
||||
exportChatInviteLink(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('exportChatInviteLink', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to set a new profile photo for the chat. Photos can't be changed for private chats.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {stream.Stream|Buffer} photo A file path or a Stream.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setchatphoto
|
||||
*/
|
||||
setChatPhoto(chatId, photo, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
try {
|
||||
const sendData = this._formatSendData('photo', photo, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.photo = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('setChatPhoto', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to delete a chat photo. Photos can't be changed for private chats.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#deletechatphoto
|
||||
*/
|
||||
deleteChatPhoto(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('deleteChatPhoto', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to change the title of a chat. Titles can't be changed for private chats.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} title New chat title, 1-255 characters
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setchattitle
|
||||
*/
|
||||
setChatTitle(chatId, title, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.title = title;
|
||||
return this._request('setChatTitle', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to change the description of a supergroup or a channel.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} description New chat title, 1-255 characters
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setchatdescription
|
||||
*/
|
||||
setChatDescription(chatId, description, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.description = description;
|
||||
return this._request('setChatDescription', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to pin a message in a supergroup.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {Number} messageId Identifier of a message to pin
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#pinchatmessage
|
||||
*/
|
||||
pinChatMessage(chatId, messageId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.message_id = messageId;
|
||||
return this._request('pinChatMessage', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to unpin a message in a supergroup chat.
|
||||
* The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#unpinchatmessage
|
||||
*/
|
||||
unpinChatMessage(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('unpinChatMessage', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to send answers to callback queries sent from
|
||||
* inline keyboards. The answer will be displayed to the user as
|
||||
* a notification at the top of the chat screen or as an alert.
|
||||
* On success, True is returned.
|
||||
*
|
||||
* This method has **older, compatible signatures ([1][answerCallbackQuery-v0.27.1])([2][answerCallbackQuery-v0.29.0])**
|
||||
* that are being deprecated.
|
||||
*
|
||||
* @param {String} callbackQueryId Unique identifier for the query to be answered
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#answercallbackquery
|
||||
*/
|
||||
answerCallbackQuery(callbackQueryId, form = {}) {
|
||||
/* The older method signature (in/before v0.27.1) was answerCallbackQuery(callbackQueryId, text, showAlert).
|
||||
* We need to ensure backwards-compatibility while maintaining
|
||||
* consistency of the method signatures throughout the library */
|
||||
if (typeof form !== 'object') {
|
||||
/* eslint-disable no-param-reassign, prefer-rest-params */
|
||||
deprecate('The method signature answerCallbackQuery(callbackQueryId, text, showAlert) has been deprecated since v0.27.1');
|
||||
form = {
|
||||
callback_query_id: arguments[0],
|
||||
text: arguments[1],
|
||||
show_alert: arguments[2],
|
||||
};
|
||||
/* eslint-enable no-param-reassign, prefer-rest-params */
|
||||
}
|
||||
/* The older method signature (in/before v0.29.0) was answerCallbackQuery([options]).
|
||||
* We need to ensure backwards-compatibility while maintaining
|
||||
* consistency of the method signatures throughout the library. */
|
||||
if (typeof callbackQueryId === 'object') {
|
||||
/* eslint-disable no-param-reassign, prefer-rest-params */
|
||||
deprecate('The method signature answerCallbackQuery([options]) has been deprecated since v0.29.0');
|
||||
form = callbackQueryId;
|
||||
/* eslint-enable no-param-reassign, prefer-rest-params */
|
||||
} else {
|
||||
form.callback_query_id = callbackQueryId;
|
||||
}
|
||||
return this._request('answerCallbackQuery', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to edit text messages sent by the bot or via
|
||||
* the bot (for inline bots). On success, the edited Message is
|
||||
* returned.
|
||||
*
|
||||
* Note that you must provide one of chat_id, message_id, or
|
||||
* inline_message_id in your request.
|
||||
*
|
||||
* @param {String} text New text of the message
|
||||
* @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#editmessagetext
|
||||
*/
|
||||
editMessageText(text, form = {}) {
|
||||
form.text = text;
|
||||
return this._request('editMessageText', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to edit captions of messages sent by the
|
||||
* bot or via the bot (for inline bots). On success, the
|
||||
* edited Message is returned.
|
||||
*
|
||||
* Note that you must provide one of chat_id, message_id, or
|
||||
* inline_message_id in your request.
|
||||
*
|
||||
* @param {String} caption New caption of the message
|
||||
* @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#editmessagecaption
|
||||
*/
|
||||
editMessageCaption(caption, form = {}) {
|
||||
form.caption = caption;
|
||||
return this._request('editMessageCaption', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to edit audio, document, photo, or video messages.
|
||||
* If a message is a part of a message album, then it can be edited only to a photo or a video.
|
||||
* Otherwise, message type can be changed arbitrarily. When inline message is edited, new file can't be uploaded.
|
||||
* Use previously uploaded file via its file_id or specify a URL.
|
||||
* On success, the edited Message is returned.
|
||||
*
|
||||
* Note that you must provide one of chat_id, message_id, or
|
||||
* inline_message_id in your request.
|
||||
*
|
||||
* @param {Object} media A JSON-serialized object for a new media content of the message
|
||||
* @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#editmessagemedia
|
||||
*/
|
||||
editMessageMedia(media, form = {}) {
|
||||
form.media = stringify(media);
|
||||
return this._request('editMessageMedia', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to edit only the reply markup of messages
|
||||
* sent by the bot or via the bot (for inline bots).
|
||||
* On success, the edited Message is returned.
|
||||
*
|
||||
* Note that you must provide one of chat_id, message_id, or
|
||||
* inline_message_id in your request.
|
||||
*
|
||||
* @param {Object} replyMarkup A JSON-serialized object for an inline keyboard.
|
||||
* @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#editmessagetext
|
||||
*/
|
||||
editMessageReplyMarkup(replyMarkup, form = {}) {
|
||||
form.reply_markup = replyMarkup;
|
||||
return this._request('editMessageReplyMarkup', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get a list of profile pictures for a user.
|
||||
* Returns a [UserProfilePhotos](https://core.telegram.org/bots/api#userprofilephotos) object.
|
||||
* This method has an [older, compatible signature][getUserProfilePhotos-v0.25.0]
|
||||
* that is being deprecated.
|
||||
*
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getuserprofilephotos
|
||||
*/
|
||||
getUserProfilePhotos(userId, form = {}) {
|
||||
/* The older method signature was getUserProfilePhotos(userId, offset, limit).
|
||||
* We need to ensure backwards-compatibility while maintaining
|
||||
* consistency of the method signatures throughout the library */
|
||||
if (typeof form !== 'object') {
|
||||
/* eslint-disable no-param-reassign, prefer-rest-params */
|
||||
deprecate('The method signature getUserProfilePhotos(userId, offset, limit) has been deprecated since v0.25.0');
|
||||
form = {
|
||||
offset: arguments[1],
|
||||
limit: arguments[2],
|
||||
};
|
||||
/* eslint-enable no-param-reassign, prefer-rest-params */
|
||||
}
|
||||
form.user_id = userId;
|
||||
return this._request('getUserProfilePhotos', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send location.
|
||||
* Use this method to send point on the map.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {Float} latitude Latitude of location
|
||||
* @param {Float} longitude Longitude of location
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendlocation
|
||||
*/
|
||||
sendLocation(chatId, latitude, longitude, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.latitude = latitude;
|
||||
form.longitude = longitude;
|
||||
return this._request('sendLocation', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to edit live location messages sent by
|
||||
* the bot or via the bot (for inline bots).
|
||||
*
|
||||
* Note that you must provide one of chat_id, message_id, or
|
||||
* inline_message_id in your request.
|
||||
*
|
||||
* @param {Float} latitude Latitude of location
|
||||
* @param {Float} longitude Longitude of location
|
||||
* @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#editmessagelivelocation
|
||||
*/
|
||||
editMessageLiveLocation(latitude, longitude, form = {}) {
|
||||
form.latitude = latitude;
|
||||
form.longitude = longitude;
|
||||
return this._request('editMessageLiveLocation', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to stop updating a live location message sent by
|
||||
* the bot or via the bot (for inline bots) before live_period expires.
|
||||
*
|
||||
* Note that you must provide one of chat_id, message_id, or
|
||||
* inline_message_id in your request.
|
||||
*
|
||||
* @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#stopmessagelivelocation
|
||||
*/
|
||||
stopMessageLiveLocation(form = {}) {
|
||||
return this._request('stopMessageLiveLocation', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send venue.
|
||||
* Use this method to send information about a venue.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {Float} latitude Latitude of location
|
||||
* @param {Float} longitude Longitude of location
|
||||
* @param {String} title Name of the venue
|
||||
* @param {String} address Address of the venue
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendvenue
|
||||
*/
|
||||
sendVenue(chatId, latitude, longitude, title, address, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.latitude = latitude;
|
||||
form.longitude = longitude;
|
||||
form.title = title;
|
||||
form.address = address;
|
||||
return this._request('sendVenue', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send contact.
|
||||
* Use this method to send phone contacts.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} phoneNumber Contact's phone number
|
||||
* @param {String} firstName Contact's first name
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendcontact
|
||||
*/
|
||||
sendContact(chatId, phoneNumber, firstName, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.phone_number = phoneNumber;
|
||||
form.first_name = firstName;
|
||||
return this._request('sendContact', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send poll.
|
||||
* Use this method to send a native poll.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the group/channel
|
||||
* @param {String} question Poll question, 255 char limit
|
||||
* @param {Array} pollOptions Poll options, between 2-10 options
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendpoll
|
||||
*/
|
||||
sendPoll(chatId, question, pollOptions, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.question = question;
|
||||
form.options = stringify(pollOptions);
|
||||
return this._request('sendPoll', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop poll.
|
||||
* Use this method to stop a native poll.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the group/channel
|
||||
* @param {Number} pollId Identifier of the original message with the poll
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#stoppoll
|
||||
*/
|
||||
stopPoll(chatId, pollId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.message_id = pollId;
|
||||
return this._request('stopPoll', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file.
|
||||
* Use this method to get basic info about a file and prepare it for downloading.
|
||||
* Attention: link will be valid for 1 hour.
|
||||
*
|
||||
* @param {String} fileId File identifier to get info about
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getfile
|
||||
*/
|
||||
getFile(fileId, form = {}) {
|
||||
form.file_id = fileId;
|
||||
return this._request('getFile', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get link for file.
|
||||
* Use this method to get link for file for subsequent use.
|
||||
* Attention: link will be valid for 1 hour.
|
||||
*
|
||||
* This method is a sugar extension of the (getFile)[#getfilefileid] method,
|
||||
* which returns just path to file on remote server (you will have to manually build full uri after that).
|
||||
*
|
||||
* @param {String} fileId File identifier to get info about
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise} promise Promise which will have *fileURI* in resolve callback
|
||||
* @see https://core.telegram.org/bots/api#getfile
|
||||
*/
|
||||
getFileLink(fileId, form = {}) {
|
||||
return this.getFile(fileId, form)
|
||||
.then(resp => `${this.options.baseApiUrl}/file/bot${this.token}/${resp.file_path}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a readable stream for file.
|
||||
*
|
||||
* `fileStream.path` is the specified file ID i.e. `fileId`.
|
||||
* `fileStream` emits event `info` passing a single argument i.e.
|
||||
* `info` with the interface `{ uri }` where `uri` is the URI of the
|
||||
* file on Telegram servers.
|
||||
*
|
||||
* This method is a sugar extension of the [getFileLink](#TelegramBot+getFileLink) method,
|
||||
* which returns the full URI to the file on remote server.
|
||||
*
|
||||
* @param {String} fileId File identifier to get info about
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {stream.Readable} fileStream
|
||||
*/
|
||||
getFileStream(fileId, form = {}) {
|
||||
const fileStream = new stream.PassThrough();
|
||||
fileStream.path = fileId;
|
||||
this.getFileLink(fileId, form)
|
||||
.then((fileURI) => {
|
||||
fileStream.emit('info', {
|
||||
uri: fileURI,
|
||||
});
|
||||
pump(streamedRequest({ uri: fileURI }), fileStream);
|
||||
})
|
||||
.catch((error) => {
|
||||
fileStream.emit('error', error);
|
||||
});
|
||||
return fileStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads file in the specified folder.
|
||||
*
|
||||
* This method is a sugar extension of the [getFileStream](#TelegramBot+getFileStream) method,
|
||||
* which returns a readable file stream.
|
||||
*
|
||||
* @param {String} fileId File identifier to get info about
|
||||
* @param {String} downloadDir Absolute path to the folder in which file will be saved
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise} promise Promise, which will have *filePath* of downloaded file in resolve callback
|
||||
*/
|
||||
downloadFile(fileId, downloadDir, form = {}) {
|
||||
let resolve;
|
||||
let reject;
|
||||
const promise = new Promise((a, b) => {
|
||||
resolve = a;
|
||||
reject = b;
|
||||
});
|
||||
const fileStream = this.getFileStream(fileId, form);
|
||||
fileStream.on('info', (info) => {
|
||||
const fileName = info.uri.slice(info.uri.lastIndexOf('/') + 1);
|
||||
// TODO: Ensure fileName doesn't contains slashes
|
||||
const filePath = path.join(downloadDir, fileName);
|
||||
pump(fileStream, fs.createWriteStream(filePath), (error) => {
|
||||
if (error) { return reject(error); }
|
||||
return resolve(filePath);
|
||||
});
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a RegExp to test against an incomming text message.
|
||||
* @param {RegExp} regexp RegExp to be executed with `exec`.
|
||||
* @param {Function} callback Callback will be called with 2 parameters,
|
||||
* the `msg` and the result of executing `regexp.exec` on message text.
|
||||
*/
|
||||
onText(regexp, callback) {
|
||||
this._textRegexpCallbacks.push({ regexp, callback });
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener registered with `onText()`.
|
||||
* @param {RegExp} regexp RegExp used previously in `onText()`
|
||||
* @return {Object} deletedListener The removed reply listener if
|
||||
* found. This object has `regexp` and `callback`
|
||||
* properties. If not found, returns `null`.
|
||||
*/
|
||||
removeTextListener(regexp) {
|
||||
const index = this._textRegexpCallbacks.findIndex((textListener) => {
|
||||
return textListener.regexp === regexp;
|
||||
});
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
return this._textRegexpCallbacks.splice(index, 1)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a reply to wait for a message response.
|
||||
* @param {Number|String} chatId The chat id where the message cames from.
|
||||
* @param {Number|String} messageId The message id to be replied.
|
||||
* @param {Function} callback Callback will be called with the reply
|
||||
* message.
|
||||
* @return {Number} id The ID of the inserted reply listener.
|
||||
*/
|
||||
onReplyToMessage(chatId, messageId, callback) {
|
||||
const id = ++this._replyListenerId;
|
||||
this._replyListeners.push({
|
||||
id,
|
||||
chatId,
|
||||
messageId,
|
||||
callback
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a reply that has been prev. registered for a message response.
|
||||
* @param {Number} replyListenerId The ID of the reply listener.
|
||||
* @return {Object} deletedListener The removed reply listener if
|
||||
* found. This object has `id`, `chatId`, `messageId` and `callback`
|
||||
* properties. If not found, returns `null`.
|
||||
*/
|
||||
removeReplyListener(replyListenerId) {
|
||||
const index = this._replyListeners.findIndex((replyListener) => {
|
||||
return replyListener.id === replyListenerId;
|
||||
});
|
||||
if (index === -1) {
|
||||
return null;
|
||||
}
|
||||
return this._replyListeners.splice(index, 1)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get up to date information about the chat
|
||||
* (current name of the user for one-on-one conversations, current
|
||||
* username of a user, group or channel, etc.).
|
||||
* @param {Number|String} chatId Unique identifier for the target chat or username of the target supergroup or channel
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getchat
|
||||
*/
|
||||
getChat(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('getChat', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the administrators in a chat in form of an Array of `ChatMember` objects.
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getchatadministrators
|
||||
*/
|
||||
getChatAdministrators(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('getChatAdministrators', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get the number of members in a chat.
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getchatmemberscount
|
||||
*/
|
||||
getChatMembersCount(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('getChatMembersCount', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get information about a member of a chat.
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getchatmember
|
||||
*/
|
||||
getChatMember(chatId, userId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.user_id = userId;
|
||||
return this._request('getChatMember', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a group, supergroup or channel.
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#leavechat
|
||||
*/
|
||||
leaveChat(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('leaveChat', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to set a new group sticker set for a supergroup.
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)
|
||||
* @param {String} stickerSetName Name of the sticker set to be set as the group sticker set
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setchatstickerset
|
||||
*/
|
||||
setChatStickerSet(chatId, stickerSetName, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.sticker_set_name = stickerSetName;
|
||||
return this._request('setChatStickerSet', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to delete a group sticker set from a supergroup.
|
||||
* @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#deletechatstickerset
|
||||
*/
|
||||
deleteChatStickerSet(chatId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
return this._request('deleteChatStickerSet', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to send a game.
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} gameShortName name of the game to be sent.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendgame
|
||||
*/
|
||||
sendGame(chatId, gameShortName, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.game_short_name = gameShortName;
|
||||
return this._request('sendGame', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to set the score of the specified user in a game.
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Number} score New score value.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setgamescore
|
||||
*/
|
||||
setGameScore(userId, score, form = {}) {
|
||||
form.user_id = userId;
|
||||
form.score = score;
|
||||
return this._request('setGameScore', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get data for high score table.
|
||||
* @param {Number} userId Unique identifier of the target user
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getgamehighscores
|
||||
*/
|
||||
getGameHighScores(userId, form = {}) {
|
||||
form.user_id = userId;
|
||||
return this._request('getGameHighScores', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to delete a message.
|
||||
* @param {Number|String} chatId Unique identifier of the target chat
|
||||
* @param {Number} messageId Unique identifier of the target message
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#deletemessage
|
||||
*/
|
||||
deleteMessage(chatId, messageId, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.message_id = messageId;
|
||||
return this._request('deleteMessage', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Send invoice.
|
||||
* Use this method to send an invoice.
|
||||
*
|
||||
* @param {Number|String} chatId Unique identifier for the message recipient
|
||||
* @param {String} title Product name
|
||||
* @param {String} description product description
|
||||
* @param {String} payload Bot defined invoice payload
|
||||
* @param {String} providerToken Payments provider token
|
||||
* @param {String} startParameter Deep-linking parameter
|
||||
* @param {String} currency Three-letter ISO 4217 currency code
|
||||
* @param {Array} prices Breakdown of prices
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendinvoice
|
||||
*/
|
||||
sendInvoice(chatId, title, description, payload, providerToken, startParameter, currency, prices, form = {}) {
|
||||
form.chat_id = chatId;
|
||||
form.title = title;
|
||||
form.description = description;
|
||||
form.payload = payload;
|
||||
form.provider_token = providerToken;
|
||||
form.start_parameter = startParameter;
|
||||
form.currency = currency;
|
||||
form.prices = stringify(prices);
|
||||
form.provider_data = stringify(form.provider_data);
|
||||
return this._request('sendInvoice', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer shipping query..
|
||||
* Use this method to reply to shipping queries.
|
||||
*
|
||||
* @param {String} shippingQueryId Unique identifier for the query to be answered
|
||||
* @param {Boolean} ok Specify if delivery of the product is possible
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#answershippingquery
|
||||
*/
|
||||
answerShippingQuery(shippingQueryId, ok, form = {}) {
|
||||
form.shipping_query_id = shippingQueryId;
|
||||
form.ok = ok;
|
||||
form.shipping_options = stringify(form.shipping_options);
|
||||
return this._request('answerShippingQuery', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer pre-checkout query.
|
||||
* Use this method to confirm shipping of a product.
|
||||
*
|
||||
* @param {String} preCheckoutQueryId Unique identifier for the query to be answered
|
||||
* @param {Boolean} ok Specify if every order details are ok
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#answerprecheckoutquery
|
||||
*/
|
||||
answerPreCheckoutQuery(preCheckoutQueryId, ok, form = {}) {
|
||||
form.pre_checkout_query_id = preCheckoutQueryId;
|
||||
form.ok = ok;
|
||||
return this._request('answerPreCheckoutQuery', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to get a sticker set. On success, a [StickerSet](https://core.telegram.org/bots/api#stickerset) object is returned.
|
||||
*
|
||||
* @param {String} name Name of the sticker set
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#getstickerset
|
||||
*/
|
||||
getStickerSet(name, form = {}) {
|
||||
form.name = name;
|
||||
return this._request('getStickerSet', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to upload a .png file with a sticker for later use in *createNewStickerSet* and *addStickerToSet* methods (can be used multiple
|
||||
* times). Returns the uploaded [File](https://core.telegram.org/bots/api#file) on success.
|
||||
*
|
||||
* @param {Number} userId User identifier of sticker file owner
|
||||
* @param {String|stream.Stream|Buffer} pngSticker A file path or a Stream. Can also be a `file_id` previously uploaded. **Png** image with the
|
||||
* sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px.
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#uploadstickerfile
|
||||
*/
|
||||
uploadStickerFile(userId, pngSticker, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.user_id = userId;
|
||||
try {
|
||||
const sendData = this._formatSendData('png_sticker', pngSticker, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.png_sticker = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('uploadStickerFile', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to create new sticker set owned by a user.
|
||||
* The bot will be able to edit the created sticker set.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number} userId User identifier of created sticker set owner
|
||||
* @param {String} name Short name of sticker set, to be used in `t.me/addstickers/` URLs (e.g., *animals*)
|
||||
* @param {String} title Sticker set title, 1-64 characters
|
||||
* @param {String|stream.Stream|Buffer} pngSticker Png image with the sticker, must be up to 512 kilobytes in size,
|
||||
* dimensions must not exceed 512px, and either width or height must be exactly 512px.
|
||||
* @param {String} emojis One or more emoji corresponding to the sticker
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#createnewstickerset
|
||||
* @todo Add tests for this method!
|
||||
*/
|
||||
createNewStickerSet(userId, name, title, pngSticker, emojis, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.user_id = userId;
|
||||
opts.qs.name = name;
|
||||
opts.qs.title = title;
|
||||
opts.qs.emojis = emojis;
|
||||
opts.qs.mask_position = stringify(options.mask_position);
|
||||
try {
|
||||
const sendData = this._formatSendData('png_sticker', pngSticker, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.png_sticker = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('createNewStickerSet', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to add a new sticker to a set created by the bot.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {Number} userId User identifier of sticker set owner
|
||||
* @param {String} name Sticker set name
|
||||
* @param {String|stream.Stream|Buffer} pngSticker Png image with the sticker, must be up to 512 kilobytes in size,
|
||||
* dimensions must not exceed 512px, and either width or height must be exactly 512px
|
||||
* @param {String} emojis One or more emoji corresponding to the sticker
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @param {Object} [fileOptions] Optional file related meta-data
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#addstickertoset
|
||||
* @todo Add tests for this method!
|
||||
*/
|
||||
addStickerToSet(userId, name, pngSticker, emojis, options = {}, fileOptions = {}) {
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.user_id = userId;
|
||||
opts.qs.name = name;
|
||||
opts.qs.emojis = emojis;
|
||||
opts.qs.mask_position = stringify(options.mask_position);
|
||||
try {
|
||||
const sendData = this._formatSendData('png_sticker', pngSticker, fileOptions);
|
||||
opts.formData = sendData[0];
|
||||
opts.qs.png_sticker = sendData[1];
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
return this._request('addStickerToSet', opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to move a sticker in a set created by the bot to a specific position.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {String} sticker File identifier of the sticker
|
||||
* @param {Number} position New sticker position in the set, zero-based
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#setstickerpositioninset
|
||||
* @todo Add tests for this method!
|
||||
*/
|
||||
setStickerPositionInSet(sticker, position, form = {}) {
|
||||
form.sticker = sticker;
|
||||
form.position = position;
|
||||
return this._request('setStickerPositionInSet', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to delete a sticker from a set created by the bot.
|
||||
* Returns True on success.
|
||||
*
|
||||
* @param {String} sticker File identifier of the sticker
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#deletestickerfromset
|
||||
* @todo Add tests for this method!
|
||||
*/
|
||||
deleteStickerFromSet(sticker, form = {}) {
|
||||
form.sticker = sticker;
|
||||
return this._request('deleteStickerFromSet', { form });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to send a group of photos or videos as an album.
|
||||
* On success, an array of the sent [Messages](https://core.telegram.org/bots/api#message)
|
||||
* is returned.
|
||||
*
|
||||
* If you wish to [specify file options](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files),
|
||||
* add a `fileOptions` property to the target input in `media`.
|
||||
*
|
||||
* @param {String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)
|
||||
* @param {Array} media A JSON-serialized array describing photos and videos to be sent, must include 2–10 items
|
||||
* @param {Object} [options] Additional Telegram query options
|
||||
* @return {Promise}
|
||||
* @see https://core.telegram.org/bots/api#sendmediagroup
|
||||
* @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files
|
||||
*/
|
||||
sendMediaGroup(chatId, media, options = {}) {
|
||||
const opts = {
|
||||
qs: options,
|
||||
};
|
||||
opts.qs.chat_id = chatId;
|
||||
|
||||
opts.formData = {};
|
||||
const inputMedia = [];
|
||||
let index = 0;
|
||||
for (const input of media) {
|
||||
const payload = Object.assign({}, input);
|
||||
delete payload.media;
|
||||
delete payload.fileOptions;
|
||||
try {
|
||||
const attachName = String(index);
|
||||
const [formData, fileId] = this._formatSendData(attachName, input.media, input.fileOptions);
|
||||
if (formData) {
|
||||
opts.formData[attachName] = formData[attachName];
|
||||
payload.media = `attach://${attachName}`;
|
||||
} else {
|
||||
payload.media = fileId;
|
||||
}
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
inputMedia.push(payload);
|
||||
index++;
|
||||
}
|
||||
opts.qs.media = JSON.stringify(inputMedia);
|
||||
|
||||
return this._request('sendMediaGroup', opts);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TelegramBot;
|
||||
202
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/telegramPolling.js
generated
vendored
Normal file
202
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/telegramPolling.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
const errors = require('./errors');
|
||||
const debug = require('debug')('node-telegram-bot-api');
|
||||
const deprecate = require('depd')('node-telegram-bot-api');
|
||||
const ANOTHER_WEB_HOOK_USED = 409;
|
||||
|
||||
|
||||
class TelegramBotPolling {
|
||||
/**
|
||||
* Handles polling against the Telegram servers.
|
||||
* @param {TelegramBot} bot
|
||||
* @see https://core.telegram.org/bots/api#getting-updates
|
||||
*/
|
||||
constructor(bot) {
|
||||
this.bot = bot;
|
||||
this.options = (typeof bot.options.polling === 'boolean') ? {} : bot.options.polling;
|
||||
this.options.interval = (typeof this.options.interval === 'number') ? this.options.interval : 300;
|
||||
this.options.params = (typeof this.options.params === 'object') ? this.options.params : {};
|
||||
this.options.params.offset = (typeof this.options.params.offset === 'number') ? this.options.params.offset : 0;
|
||||
this.options.params.timeout = (typeof this.options.params.timeout === 'number') ? this.options.params.timeout : 10;
|
||||
if (typeof this.options.timeout === 'number') {
|
||||
deprecate('`options.polling.timeout` is deprecated. Use `options.polling.params` instead.');
|
||||
this.options.params.timeout = this.options.timeout;
|
||||
}
|
||||
this._lastUpdate = 0;
|
||||
this._lastRequest = null;
|
||||
this._abort = false;
|
||||
this._pollingTimeout = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start polling
|
||||
* @param {Object} [options]
|
||||
* @param {Object} [options.restart]
|
||||
* @return {Promise}
|
||||
*/
|
||||
start(options = {}) {
|
||||
if (this._lastRequest) {
|
||||
if (!options.restart) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this.stop({
|
||||
cancel: true,
|
||||
reason: 'Polling restart',
|
||||
}).then(() => {
|
||||
return this._polling();
|
||||
});
|
||||
}
|
||||
return this._polling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop polling
|
||||
* @param {Object} [options] Options
|
||||
* @param {Boolean} [options.cancel] Cancel current request
|
||||
* @param {String} [options.reason] Reason for stopping polling
|
||||
* @return {Promise}
|
||||
*/
|
||||
stop(options = {}) {
|
||||
if (!this._lastRequest) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const lastRequest = this._lastRequest;
|
||||
this._lastRequest = null;
|
||||
clearTimeout(this._pollingTimeout);
|
||||
if (options.cancel) {
|
||||
const reason = options.reason || 'Polling stop';
|
||||
lastRequest.cancel(reason);
|
||||
return Promise.resolve();
|
||||
}
|
||||
this._abort = true;
|
||||
return lastRequest.finally(() => {
|
||||
this._abort = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if is polling. Otherwise, `false`.
|
||||
*/
|
||||
isPolling() {
|
||||
return !!this._lastRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error thrown during polling.
|
||||
* @private
|
||||
* @param {Error} error
|
||||
*/
|
||||
_error(error) {
|
||||
if (!this.bot.listeners('polling_error').length) {
|
||||
return console.error('error: [polling_error] %j', error); // eslint-disable-line no-console
|
||||
}
|
||||
return this.bot.emit('polling_error', error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes polling (with recursion!)
|
||||
* @return {Promise} promise of the current request
|
||||
* @private
|
||||
*/
|
||||
_polling() {
|
||||
this._lastRequest = this
|
||||
._getUpdates()
|
||||
.then(updates => {
|
||||
this._lastUpdate = Date.now();
|
||||
debug('polling data %j', updates);
|
||||
updates.forEach(update => {
|
||||
this.options.params.offset = update.update_id + 1;
|
||||
debug('updated offset: %s', this.options.params.offset);
|
||||
try {
|
||||
this.bot.processUpdate(update);
|
||||
} catch (err) {
|
||||
err._processing = true;
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
return null;
|
||||
})
|
||||
.catch(err => {
|
||||
debug('polling error: %s', err.message);
|
||||
if (!err._processing) {
|
||||
return this._error(err);
|
||||
}
|
||||
delete err._processing;
|
||||
/*
|
||||
* An error occured while processing the items,
|
||||
* i.e. in `this.bot.processUpdate()` above.
|
||||
* We need to mark the already-processed items
|
||||
* to avoid fetching them again once the application
|
||||
* is restarted, or moves to next polling interval
|
||||
* (in cases where unhandled rejections do not terminate
|
||||
* the process).
|
||||
* See https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067
|
||||
*/
|
||||
if (!this.bot.options.badRejection) {
|
||||
return this._error(err);
|
||||
}
|
||||
const opts = {
|
||||
offset: this.options.params.offset,
|
||||
limit: 1,
|
||||
timeout: 0,
|
||||
};
|
||||
return this.bot.getUpdates(opts).then(() => {
|
||||
return this._error(err);
|
||||
}).catch(requestErr => {
|
||||
/*
|
||||
* We have been unable to handle this error.
|
||||
* We have to log this to stderr to ensure devops
|
||||
* understands that they may receive already-processed items
|
||||
* on app restart.
|
||||
* We simply can not rescue this situation, emit "error"
|
||||
* event, with the hope that the application exits.
|
||||
*/
|
||||
/* eslint-disable no-console */
|
||||
const bugUrl = 'https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067';
|
||||
console.error('error: Internal handling of The Offset Infinite Loop failed');
|
||||
console.error(`error: Due to error '${requestErr}'`);
|
||||
console.error('error: You may receive already-processed updates on app restart');
|
||||
console.error(`error: Please see ${bugUrl} for more information`);
|
||||
/* eslint-enable no-console */
|
||||
return this.bot.emit('error', new errors.FatalError(err));
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
if (this._abort) {
|
||||
debug('Polling is aborted!');
|
||||
} else {
|
||||
debug('setTimeout for %s miliseconds', this.options.interval);
|
||||
this._pollingTimeout = setTimeout(() => this._polling(), this.options.interval);
|
||||
}
|
||||
});
|
||||
return this._lastRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset current webhook. Used when we detect that a webhook has been set
|
||||
* and we are trying to poll. Polling and WebHook are mutually exclusive.
|
||||
* @see https://core.telegram.org/bots/api#getting-updates
|
||||
* @private
|
||||
*/
|
||||
_unsetWebHook() {
|
||||
debug('unsetting webhook');
|
||||
return this.bot._request('setWebHook');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve updates
|
||||
*/
|
||||
_getUpdates() {
|
||||
debug('polling with options: %j', this.options.params);
|
||||
return this.bot.getUpdates(this.options.params)
|
||||
.catch(err => {
|
||||
if (err.response && err.response.statusCode === ANOTHER_WEB_HOOK_USED) {
|
||||
return this._unsetWebHook().then(() => {
|
||||
return this.bot.getUpdates(this.options.params);
|
||||
});
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TelegramBotPolling;
|
||||
156
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/telegramWebHook.js
generated
vendored
Normal file
156
nodered/rootfs/data/node_modules/node-telegram-bot-api/src/telegramWebHook.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
const errors = require('./errors');
|
||||
const debug = require('debug')('node-telegram-bot-api');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const bl = require('bl');
|
||||
const Promise = require('bluebird');
|
||||
|
||||
|
||||
class TelegramBotWebHook {
|
||||
/**
|
||||
* Sets up a webhook to receive updates
|
||||
* @param {TelegramBot} bot
|
||||
* @see https://core.telegram.org/bots/api#getting-updates
|
||||
*/
|
||||
constructor(bot) {
|
||||
this.bot = bot;
|
||||
this.options = (typeof bot.options.webHook === 'boolean') ? {} : bot.options.webHook;
|
||||
this.options.host = this.options.host || '0.0.0.0';
|
||||
this.options.port = this.options.port || 8443;
|
||||
this.options.https = this.options.https || {};
|
||||
this.options.healthEndpoint = this.options.healthEndpoint || '/healthz';
|
||||
this._healthRegex = new RegExp(this.options.healthEndpoint);
|
||||
this._webServer = null;
|
||||
this._open = false;
|
||||
this._requestListener = this._requestListener.bind(this);
|
||||
this._parseBody = this._parseBody.bind(this);
|
||||
|
||||
if (this.options.key && this.options.cert) {
|
||||
debug('HTTPS WebHook enabled (by key/cert)');
|
||||
this.options.https.key = fs.readFileSync(this.options.key);
|
||||
this.options.https.cert = fs.readFileSync(this.options.cert);
|
||||
this._webServer = https.createServer(this.options.https, this._requestListener);
|
||||
} else if (this.options.pfx) {
|
||||
debug('HTTPS WebHook enabled (by pfx)');
|
||||
this.options.https.pfx = fs.readFileSync(this.options.pfx);
|
||||
this._webServer = https.createServer(this.options.https, this._requestListener);
|
||||
} else if (Object.keys(this.options.https).length) {
|
||||
debug('HTTPS WebHook enabled by (https)');
|
||||
this._webServer = https.createServer(this.options.https, this._requestListener);
|
||||
} else {
|
||||
debug('HTTP WebHook enabled');
|
||||
this._webServer = http.createServer(this._requestListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open WebHook by listening on the port
|
||||
* @return {Promise}
|
||||
*/
|
||||
open() {
|
||||
if (this.isOpen()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
this._webServer.listen(this.options.port, this.options.host, () => {
|
||||
debug('WebHook listening on port %s', this.options.port);
|
||||
this._open = true;
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the webHook
|
||||
* @return {Promise}
|
||||
*/
|
||||
close() {
|
||||
if (!this.isOpen()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
this._webServer.close(error => {
|
||||
if (error) return reject(error);
|
||||
this._open = false;
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if server is listening. Otherwise, `false`.
|
||||
*/
|
||||
isOpen() {
|
||||
// NOTE: Since `http.Server.listening` was added in v5.7.0
|
||||
// and we still need to support Node v4,
|
||||
// we are going to fallback to 'this._open'.
|
||||
// The following LOC would suffice for newer versions of Node.js
|
||||
// return this._webServer.listening;
|
||||
return this._open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle error thrown during processing of webhook request.
|
||||
* @private
|
||||
* @param {Error} error
|
||||
*/
|
||||
_error(error) {
|
||||
if (!this.bot.listeners('webhook_error').length) {
|
||||
return console.error('error: [webhook_error] %j', error); // eslint-disable-line no-console
|
||||
}
|
||||
return this.bot.emit('webhook_error', error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request body by passing it to 'callback'
|
||||
* @private
|
||||
*/
|
||||
_parseBody(error, body) {
|
||||
if (error) {
|
||||
return this._error(new errors.FatalError(error));
|
||||
}
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(body.toString());
|
||||
} catch (parseError) {
|
||||
return this._error(new errors.ParseError(parseError.message));
|
||||
}
|
||||
|
||||
return this.bot.processUpdate(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for 'request' event on server
|
||||
* @private
|
||||
* @see https://nodejs.org/docs/latest/api/http.html#http_http_createserver_requestlistener
|
||||
* @see https://nodejs.org/docs/latest/api/https.html#https_https_createserver_options_requestlistener
|
||||
*/
|
||||
_requestListener(req, res) {
|
||||
debug('WebHook request URL: %s', req.url);
|
||||
debug('WebHook request headers: %j', req.headers);
|
||||
|
||||
if (req.url.indexOf(this.bot.token) !== -1) {
|
||||
if (req.method !== 'POST') {
|
||||
debug('WebHook request isn\'t a POST');
|
||||
res.statusCode = 418; // I'm a teabot!
|
||||
res.end();
|
||||
} else {
|
||||
req
|
||||
.pipe(bl(this._parseBody))
|
||||
.on('finish', () => res.end('OK'));
|
||||
}
|
||||
} else if (this._healthRegex.test(req.url)) {
|
||||
debug('WebHook health check passed');
|
||||
res.statusCode = 200;
|
||||
res.end('OK');
|
||||
} else {
|
||||
debug('WebHook request unauthorized');
|
||||
res.statusCode = 401;
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TelegramBotWebHook;
|
||||
Reference in New Issue
Block a user