1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.Telegraf = void 0;
|
4 | const crypto = require("crypto");
|
5 | const http = require("http");
|
6 | const https = require("https");
|
7 | const util = require("util");
|
8 | const composer_1 = require("./composer");
|
9 | const compact_1 = require("./core/helpers/compact");
|
10 | const context_1 = require("./context");
|
11 | const debug_1 = require("debug");
|
12 | const webhook_1 = require("./core/network/webhook");
|
13 | const polling_1 = require("./core/network/polling");
|
14 | const p_timeout_1 = require("p-timeout");
|
15 | const telegram_1 = require("./telegram");
|
16 | const url_1 = require("url");
|
17 | const debug = (0, debug_1.default)('telegraf:main');
|
18 | const DEFAULT_OPTIONS = {
|
19 | telegram: {},
|
20 | handlerTimeout: 90000,
|
21 | contextType: context_1.default,
|
22 | };
|
23 | function always(x) {
|
24 | return () => x;
|
25 | }
|
26 | const anoop = always(Promise.resolve());
|
27 |
|
28 | class Telegraf extends composer_1.Composer {
|
29 | constructor(token, options) {
|
30 | super();
|
31 | this.context = {};
|
32 | this.handleError = (err, ctx) => {
|
33 |
|
34 |
|
35 |
|
36 | process.exitCode = 1;
|
37 | console.error('Unhandled error while processing', ctx.update);
|
38 | throw err;
|
39 | };
|
40 |
|
41 | this.options = {
|
42 | ...DEFAULT_OPTIONS,
|
43 | ...(0, compact_1.compactOptions)(options),
|
44 | };
|
45 | this.telegram = new telegram_1.default(token, this.options.telegram);
|
46 | debug('Created a `Telegraf` instance');
|
47 | }
|
48 | get token() {
|
49 | return this.telegram.token;
|
50 | }
|
51 |
|
52 | set webhookReply(webhookReply) {
|
53 | this.telegram.webhookReply = webhookReply;
|
54 | }
|
55 | get webhookReply() {
|
56 | return this.telegram.webhookReply;
|
57 | }
|
58 | |
59 |
|
60 |
|
61 | catch(handler) {
|
62 | this.handleError = handler;
|
63 | return this;
|
64 | }
|
65 | webhookCallback(path = '/') {
|
66 | return (0, webhook_1.default)(path, (update, res) => this.handleUpdate(update, res));
|
67 | }
|
68 | startPolling(allowedUpdates = []) {
|
69 | this.polling = new polling_1.Polling(this.telegram, allowedUpdates);
|
70 |
|
71 | this.polling.loop(async (updates) => {
|
72 | await this.handleUpdates(updates);
|
73 | });
|
74 | }
|
75 | startWebhook(hookPath, tlsOptions, port, host, cb) {
|
76 | const webhookCb = this.webhookCallback(hookPath);
|
77 | const callback = typeof cb === 'function'
|
78 | ? (req, res) => webhookCb(req, res, () => cb(req, res))
|
79 | : webhookCb;
|
80 | this.webhookServer =
|
81 | tlsOptions != null
|
82 | ? https.createServer(tlsOptions, callback)
|
83 | : http.createServer(callback);
|
84 | this.webhookServer.listen(port, host, () => {
|
85 | debug('Webhook listening on port: %s', port);
|
86 | });
|
87 | return this;
|
88 | }
|
89 | secretPathComponent() {
|
90 | return crypto
|
91 | .createHash('sha3-256')
|
92 | .update(this.token)
|
93 | .update(process.version)
|
94 | .digest('hex');
|
95 | }
|
96 | |
97 |
|
98 |
|
99 | async launch(config = {}) {
|
100 | var _a, _b, _c;
|
101 | debug('Connecting to Telegram');
|
102 | (_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = await this.telegram.getMe());
|
103 | debug(`Launching @${this.botInfo.username}`);
|
104 | if (config.webhook === undefined) {
|
105 | await this.telegram.deleteWebhook({
|
106 | drop_pending_updates: config.dropPendingUpdates,
|
107 | });
|
108 | this.startPolling(config.allowedUpdates);
|
109 | debug('Bot started with long polling');
|
110 | return;
|
111 | }
|
112 | if (typeof config.webhook.domain !== 'string' &&
|
113 | typeof config.webhook.hookPath !== 'string') {
|
114 | throw new Error('Webhook domain or webhook path is required');
|
115 | }
|
116 | let domain = (_b = config.webhook.domain) !== null && _b !== void 0 ? _b : '';
|
117 | if (domain.startsWith('https://') || domain.startsWith('http://')) {
|
118 | domain = new url_1.URL(domain).host;
|
119 | }
|
120 | const hookPath = (_c = config.webhook.hookPath) !== null && _c !== void 0 ? _c : `/telegraf/${this.secretPathComponent()}`;
|
121 | const { port, host, tlsOptions, cb } = config.webhook;
|
122 | this.startWebhook(hookPath, tlsOptions, port, host, cb);
|
123 | if (!domain) {
|
124 | debug('Bot started with webhook');
|
125 | return;
|
126 | }
|
127 | await this.telegram.setWebhook(`https://${domain}${hookPath}`, {
|
128 | drop_pending_updates: config.dropPendingUpdates,
|
129 | allowed_updates: config.allowedUpdates,
|
130 | });
|
131 | debug(`Bot started with webhook @ https://${domain}`);
|
132 | }
|
133 | stop(reason = 'unspecified') {
|
134 | var _a, _b;
|
135 | debug('Stopping bot... Reason:', reason);
|
136 |
|
137 | if (this.polling === undefined && this.webhookServer === undefined) {
|
138 | throw new Error('Bot is not running!');
|
139 | }
|
140 | (_a = this.webhookServer) === null || _a === void 0 ? void 0 : _a.close();
|
141 | (_b = this.polling) === null || _b === void 0 ? void 0 : _b.stop();
|
142 | }
|
143 | handleUpdates(updates) {
|
144 | if (!Array.isArray(updates)) {
|
145 | throw new TypeError(util.format('Updates must be an array, got', updates));
|
146 | }
|
147 | return Promise.all(updates.map((update) => this.handleUpdate(update)));
|
148 | }
|
149 | async handleUpdate(update, webhookResponse) {
|
150 | var _a, _b;
|
151 | (_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = (debug('Update %d is waiting for `botInfo` to be initialized', update.update_id),
|
152 | await ((_b = this.botInfoCall) !== null && _b !== void 0 ? _b : (this.botInfoCall = this.telegram.getMe()))));
|
153 | debug('Processing update', update.update_id);
|
154 | const tg = new telegram_1.default(this.token, this.telegram.options, webhookResponse);
|
155 | const TelegrafContext = this.options.contextType;
|
156 | const ctx = new TelegrafContext(update, tg, this.botInfo);
|
157 | Object.assign(ctx, this.context);
|
158 | try {
|
159 | await (0, p_timeout_1.default)(Promise.resolve(this.middleware()(ctx, anoop)), this.options.handlerTimeout);
|
160 | }
|
161 | catch (err) {
|
162 | return await this.handleError(err, ctx);
|
163 | }
|
164 | finally {
|
165 | if ((webhookResponse === null || webhookResponse === void 0 ? void 0 : webhookResponse.writableEnded) === false) {
|
166 | webhookResponse.end();
|
167 | }
|
168 | debug('Finished processing update', update.update_id);
|
169 | }
|
170 | }
|
171 | }
|
172 | exports.Telegraf = Telegraf;
|