Files
APP-SIGMA-WEB/node_modules/telegraf/telegraf.js
2024-07-13 00:27:32 -05:00

222 lines
6.6 KiB
JavaScript

const debug = require('debug')('telegraf:core')
const Telegram = require('./telegram')
const Extra = require('./extra')
const Composer = require('./composer')
const Markup = require('./markup')
const session = require('./session')
const Router = require('./router')
const Stage = require('./stage')
const BaseScene = require('./scenes/base')
const Context = require('./context')
const generateCallback = require('./core/network/webhook')
const crypto = require('crypto')
const { URL } = require('url')
const DEFAULT_OPTIONS = {
retryAfter: 1,
handlerTimeout: 0,
contextType: Context
}
const noop = () => { }
class Telegraf extends Composer {
constructor (token, options) {
super()
this.options = {
...DEFAULT_OPTIONS,
...options
}
this.token = token
this.handleError = (err) => {
console.error()
console.error((err.stack || err.toString()).replace(/^/gm, ' '))
console.error()
throw err
}
this.context = {}
this.polling = {
offset: 0,
started: false
}
}
set token (token) {
this.telegram = new Telegram(token, this.telegram
? this.telegram.options
: this.options.telegram
)
}
get token () {
return this.telegram.token
}
set webhookReply (webhookReply) {
this.telegram.webhookReply = webhookReply
}
get webhookReply () {
return this.telegram.webhookReply
}/* eslint brace-style: 0 */
catch (handler) {
this.handleError = handler
return this
}
webhookCallback (path = '/') {
return generateCallback(path, (update, res) => this.handleUpdate(update, res), debug)
}
startPolling (timeout = 30, limit = 100, allowedUpdates, stopCallback = noop) {
this.polling.timeout = timeout
this.polling.limit = limit
this.polling.allowedUpdates = allowedUpdates
? Array.isArray(allowedUpdates) ? allowedUpdates : [`${allowedUpdates}`]
: null
this.polling.stopCallback = stopCallback
if (!this.polling.started) {
this.polling.started = true
this.fetchUpdates()
}
return this
}
startWebhook (hookPath, tlsOptions, port, host, cb) {
const webhookCb = this.webhookCallback(hookPath)
const callback = cb && typeof cb === 'function'
? (req, res) => webhookCb(req, res, () => cb(req, res))
: webhookCb
this.webhookServer = tlsOptions
? require('https').createServer(tlsOptions, callback)
: require('http').createServer(callback)
this.webhookServer.listen(port, host, () => {
debug('Webhook listening on port: %s', port)
})
return this
}
launch (config = {}) {
debug('Connecting to Telegram')
return this.telegram.getMe()
.then((botInfo) => {
debug(`Launching @${botInfo.username}`)
this.options.username = botInfo.username
this.context.botInfo = botInfo
if (!config.webhook) {
const { timeout, limit, allowedUpdates, stopCallback } = config.polling || {}
return this.telegram.deleteWebhook()
.then(() => this.startPolling(timeout, limit, allowedUpdates, stopCallback))
.then(() => debug('Bot started with long-polling'))
}
if (typeof config.webhook.domain !== 'string' && typeof config.webhook.hookPath !== 'string') {
throw new Error('Webhook domain or webhook path is required')
}
let domain = config.webhook.domain || ''
if (domain.startsWith('https://') || domain.startsWith('http://')) {
domain = new URL(domain).host
}
const hookPath = config.webhook.hookPath || `/telegraf/${crypto.randomBytes(32).toString('hex')}`
const { port, host, tlsOptions, cb } = config.webhook
this.startWebhook(hookPath, tlsOptions, port, host, cb)
if (!domain) {
debug('Bot started with webhook')
return
}
return this.telegram
.setWebhook(`https://${domain}${hookPath}`)
.then(() => debug(`Bot started with webhook @ https://${domain}`))
})
.catch((err) => {
console.error('Launch failed')
console.error(err.stack || err.toString())
})
}
stop (cb = noop) {
debug('Stopping bot...')
return new Promise((resolve) => {
const done = () => resolve() & cb()
if (this.webhookServer) {
return this.webhookServer.close(done)
} else if (!this.polling.started) {
return done()
}
this.polling.stopCallback = done
this.polling.started = false
})
}
handleUpdates (updates) {
if (!Array.isArray(updates)) {
return Promise.reject(new Error('Updates must be an array'))
}
const processAll = Promise.all(updates.map((update) => this.handleUpdate(update)))
if (this.options.handlerTimeout === 0) {
return processAll
}
return Promise.race([
processAll,
new Promise((resolve) => setTimeout(resolve, this.options.handlerTimeout))
])
}
handleUpdate (update, webhookResponse) {
debug('Processing update', update.update_id)
const tg = new Telegram(this.token, this.telegram.options, webhookResponse)
const TelegrafContext = this.options.contextType
const ctx = new TelegrafContext(update, tg, this.options)
Object.assign(ctx, this.context)
return this.middleware()(ctx).catch((err) => this.handleError(err, ctx))
}
fetchUpdates () {
if (!this.polling.started) {
this.polling.stopCallback && this.polling.stopCallback()
return
}
const { timeout, limit, offset, allowedUpdates } = this.polling
this.telegram.getUpdates(timeout, limit, offset, allowedUpdates)
.catch((err) => {
if (err.code === 401 || err.code === 409) {
throw err
}
const wait = (err.parameters && err.parameters.retry_after) || this.options.retryAfter
console.error(`Failed to fetch updates. Waiting: ${wait}s`, err.message)
return new Promise((resolve) => setTimeout(resolve, wait * 1000, []))
})
.then((updates) => this.polling.started
? this.handleUpdates(updates).then(() => updates)
: []
)
.catch((err) => {
console.error('Failed to process updates.', err)
this.polling.started = false
this.polling.offset = 0
this.polling.stopCallback && this.polling.stopCallback()
return []
})
.then((updates) => {
if (updates.length > 0) {
this.polling.offset = updates[updates.length - 1].update_id + 1
}
this.fetchUpdates()
})
}
}
module.exports = Object.assign(Telegraf, {
Context,
Composer,
default: Telegraf,
Extra,
Markup,
Router,
Telegraf,
Telegram,
Stage,
BaseScene,
session
})