-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
117 lines (98 loc) · 3.02 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
'use strict'
const timeout = require('node:timers/promises').setTimeout
const fp = require('fastify-plugin')
const { Telegraf } = require('telegraf')
async function fastifyTelegram (app, options) {
const {
decoratorBotName = 'telegramBot',
waitForHealthPolling = app.initialConfig.pluginTimeout / 6,
baseUrl,
webhookSecret,
botToken,
onUnhandledError = (err) => {
app.log.error(err, 'fastify-telegram: unhandled error')
}
} = options
if (!botToken) {
throw new Error('fastify-telegram: botToken is required')
}
if (app[decoratorBotName]) {
throw new Error(`fastify-telegram: fastify.${decoratorBotName} already exists`)
}
const bot = new Telegraf(botToken, {
telegram: {
// agent: { keepAlive: true } // todo
// const { Agent } = require('undici')
// new Agent({
// keepAliveTimeout: 15,
// keepAliveMaxTimeout: 30
// })
}
})
bot.catch(onUnhandledError)
app.decorate(decoratorBotName, bot)
app.addHook('onClose', async function () {
try {
bot.stop() // it is sync...
} catch (error) {
app.log.warn(error, 'fastify-telegram: bot.stop() failed')
}
})
// ****************************************
// Long polling mode
if (!baseUrl) {
app.log.debug('Telegram long polling mode')
app.addHook('onReady', async function startPolling () {
// this function avoids memory leaks
let startError = null
function handleFatalError (err) {
app.log.fatal(err, 'fastify-telegram: bot.launch() failed')
startError = err
}
// bot.launch is an endless loop
// it triggers an error during startup if the config is invalid
await Promise.race([
bot.launch({ webhook: undefined }).catch(handleFatalError),
timeout(waitForHealthPolling)
])
if (startError) {
const fail = new Error(`fastify-telegram: bot.launch() failed: ${startError.message}`)
fail.cause = startError
throw fail
}
})
return
}
// ****************************************
// Webhook mode
let webhookFn
const routePath = `/telegraf/${bot.secretPathComponent()}`
app.decorate('telegramWebhook', routePath)
app.addHook('onReady', async function startWebHook () {
try {
webhookFn = await bot.createWebhook({
domain: baseUrl, // Public domain for webhook
secret_token: webhookSecret
})
} catch (error) {
const fail = new Error(`fastify-telegram: bot.createWebhook() failed: ${error.message}`)
fail.cause = error
throw fail
}
})
app.post(routePath, async (request, reply) => {
if (!webhookFn) {
throw new Error('Webhook not started - retry later')
}
reply.hijack() // Telegraf handles the reply
request.raw.body = request.body
await webhookFn(request.raw, reply.raw)
})
}
const plugin = fp(fastifyTelegram, {
name: 'fastify-telegram',
fastify: '^4.0.x'
})
module.exports = plugin
module.exports.default = plugin
module.exports.fastifyOverview = plugin