telegraf
Version:
📡 Modern Telegram bot framework
161 lines (145 loc) • 4.62 kB
JavaScript
const debug = require('debug')('telegraf:core')
const util = require('util')
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 Context = require('./core/context')
const generateCallback = require('./core/network/webhook')
const DefaultOptions = {
retryAfter: 1,
handlerTimeout: 0
}
class Telegraf extends Composer {
constructor (token, options) {
super()
this.options = Object.assign({}, DefaultOptions, 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) {
const config = this.telegram ? this.telegram.options : this.options.telegram
this.telegram = new Telegram(token, config)
}
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) {
this.polling.timeout = timeout
this.polling.limit = limit
this.polling.allowedUpdates = allowedUpdates
? Array.isArray(allowedUpdates) ? allowedUpdates : [`${allowedUpdates}`]
: null
if (!this.polling.started) {
this.polling.started = true
this.fetchUpdates()
}
return this
}
startWebhook (path, tlsOptions, port, host, cb) {
const webhookCb = this.webhookCallback(path)
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
}
stop (cb = () => {}) {
this.polling.started = false
if (this.webhookServer) {
this.webhookServer.close(cb)
} else {
cb()
}
return this
}
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('⚡ update', update.update_id)
const telegram = webhookResponse && this.webhookReply
? new Telegram(this.token, this.telegram.options, webhookResponse)
: this.telegram
const ctx = new Context(update, telegram, this.options)
Object.assign(ctx, this.context)
return this.middleware()(ctx).catch(this.handleError)
}
fetchUpdates () {
const { timeout, limit, offset, started, allowedUpdates } = this.polling
if (!started) {
return
}
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.handleUpdates(updates).then(() => updates))
.catch((err) => {
console.error('Failed to process updates.', err)
this.polling.started = false
this.polling.offset = 0
return []
})
.then((updates) => {
if (updates.length > 0) {
this.polling.offset = updates[updates.length - 1].update_id + 1
}
this.fetchUpdates()
})
}
}
module.exports = Object.assign(Telegraf, {
Composer,
Extra,
Markup,
Router,
Telegram,
session,
memorySession: util.deprecate(session, '⚠️ Telegraf: memorySession() is deprecated, use session() instead')
})