UNPKG

7.03 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.Telegraf = void 0;
4const crypto = require("crypto");
5const http = require("http");
6const https = require("https");
7const util = require("util");
8const composer_1 = require("./composer");
9const compact_1 = require("./core/helpers/compact");
10const context_1 = require("./context");
11const debug_1 = require("debug");
12const webhook_1 = require("./core/network/webhook");
13const polling_1 = require("./core/network/polling");
14const p_timeout_1 = require("p-timeout");
15const telegram_1 = require("./telegram");
16const url_1 = require("url");
17const debug = (0, debug_1.default)('telegraf:main');
18const DEFAULT_OPTIONS = {
19 telegram: {},
20 handlerTimeout: 90000,
21 contextType: context_1.default,
22};
23function always(x) {
24 return () => x;
25}
26const anoop = always(Promise.resolve());
27// eslint-disable-next-line import/export
28class Telegraf extends composer_1.Composer {
29 constructor(token, options) {
30 super();
31 this.context = {};
32 this.handleError = (err, ctx) => {
33 // set exit code to emulate `warn-with-error-code` behavior of
34 // https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
35 // to prevent a clean exit despite an error being thrown
36 process.exitCode = 1;
37 console.error('Unhandled error while processing', ctx.update);
38 throw err;
39 };
40 // @ts-expect-error
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 /** @deprecated use `ctx.telegram.webhookReply` */
52 set webhookReply(webhookReply) {
53 this.telegram.webhookReply = webhookReply;
54 }
55 get webhookReply() {
56 return this.telegram.webhookReply;
57 }
58 /**
59 * _Override_ error handling
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 // eslint-disable-next-line @typescript-eslint/no-floating-promises
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) // salt
94 .digest('hex');
95 }
96 /**
97 * @see https://github.com/telegraf/telegraf/discussions/1344#discussioncomment-335700
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 // https://github.com/telegraf/telegraf/pull/1224#issuecomment-742693770
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}
172exports.Telegraf = Telegraf;