@mtcute/dispatcher 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/README.md +26 -0
- package/cjs/callback-data-builder.d.ts +43 -0
- package/cjs/callback-data-builder.js +99 -0
- package/cjs/callback-data-builder.js.map +1 -0
- package/cjs/context/base.d.ts +8 -0
- package/cjs/context/base.js +3 -0
- package/cjs/context/base.js.map +1 -0
- package/cjs/context/callback-query.d.ts +27 -0
- package/cjs/context/callback-query.js +56 -0
- package/cjs/context/callback-query.js.map +1 -0
- package/cjs/context/chat-join-request.d.ts +16 -0
- package/cjs/context/chat-join-request.js +34 -0
- package/cjs/context/chat-join-request.js.map +1 -0
- package/cjs/context/chosen-inline-result.d.ts +21 -0
- package/cjs/context/chosen-inline-result.js +35 -0
- package/cjs/context/chosen-inline-result.js.map +1 -0
- package/cjs/context/index.d.ts +8 -0
- package/cjs/context/index.js +24 -0
- package/cjs/context/index.js.map +1 -0
- package/cjs/context/inline-query.d.ts +14 -0
- package/cjs/context/inline-query.js +22 -0
- package/cjs/context/inline-query.js.map +1 -0
- package/cjs/context/message.d.ts +72 -0
- package/cjs/context/message.js +142 -0
- package/cjs/context/message.js.map +1 -0
- package/cjs/context/parse.d.ts +1 -0
- package/cjs/context/parse.js +34 -0
- package/cjs/context/parse.js.map +1 -0
- package/cjs/context/pre-checkout-query.d.ts +16 -0
- package/cjs/context/pre-checkout-query.js +26 -0
- package/cjs/context/pre-checkout-query.js.map +1 -0
- package/cjs/dispatcher.d.ts +641 -0
- package/cjs/dispatcher.js +765 -0
- package/cjs/dispatcher.js.map +1 -0
- package/cjs/filters/bots.d.ts +70 -0
- package/cjs/filters/bots.js +129 -0
- package/cjs/filters/bots.js.map +1 -0
- package/cjs/filters/bundle.d.ts +10 -0
- package/cjs/filters/bundle.js +27 -0
- package/cjs/filters/bundle.js.map +1 -0
- package/cjs/filters/chat.d.ts +27 -0
- package/cjs/filters/chat.js +55 -0
- package/cjs/filters/chat.js.map +1 -0
- package/cjs/filters/group.d.ts +25 -0
- package/cjs/filters/group.js +72 -0
- package/cjs/filters/group.js.map +1 -0
- package/cjs/filters/index.d.ts +3 -0
- package/cjs/filters/index.js +29 -0
- package/cjs/filters/index.js.map +1 -0
- package/cjs/filters/logic.d.ts +29 -0
- package/cjs/filters/logic.js +114 -0
- package/cjs/filters/logic.js.map +1 -0
- package/cjs/filters/message.d.ts +295 -0
- package/cjs/filters/message.js +150 -0
- package/cjs/filters/message.js.map +1 -0
- package/cjs/filters/state.d.ts +15 -0
- package/cjs/filters/state.js +32 -0
- package/cjs/filters/state.js.map +1 -0
- package/cjs/filters/text.d.ts +64 -0
- package/cjs/filters/text.js +132 -0
- package/cjs/filters/text.js.map +1 -0
- package/cjs/filters/types.d.ts +91 -0
- package/cjs/filters/types.js +6 -0
- package/cjs/filters/types.js.map +1 -0
- package/cjs/filters/updates.d.ts +46 -0
- package/cjs/filters/updates.js +46 -0
- package/cjs/filters/updates.js.map +1 -0
- package/cjs/filters/user.d.ts +24 -0
- package/cjs/filters/user.js +76 -0
- package/cjs/filters/user.js.map +1 -0
- package/cjs/handler.d.ts +31 -0
- package/cjs/handler.js +4 -0
- package/cjs/handler.js.map +1 -0
- package/cjs/index.d.ts +8 -0
- package/cjs/index.js +25 -0
- package/cjs/index.js.map +1 -0
- package/cjs/package.json +3 -0
- package/cjs/propagation.d.ts +21 -0
- package/cjs/propagation.js +26 -0
- package/cjs/propagation.js.map +1 -0
- package/cjs/state/index.d.ts +3 -0
- package/cjs/state/index.js +20 -0
- package/cjs/state/index.js.map +1 -0
- package/cjs/state/key.d.ts +23 -0
- package/cjs/state/key.js +45 -0
- package/cjs/state/key.js.map +1 -0
- package/cjs/state/storage.d.ts +75 -0
- package/cjs/state/storage.js +17 -0
- package/cjs/state/storage.js.map +1 -0
- package/cjs/state/update-state.d.ts +151 -0
- package/cjs/state/update-state.js +211 -0
- package/cjs/state/update-state.js.map +1 -0
- package/cjs/wizard.d.ts +60 -0
- package/cjs/wizard.js +103 -0
- package/cjs/wizard.js.map +1 -0
- package/esm/callback-data-builder.d.ts +43 -0
- package/esm/callback-data-builder.js +95 -0
- package/esm/callback-data-builder.js.map +1 -0
- package/esm/context/base.d.ts +8 -0
- package/esm/context/base.js +2 -0
- package/esm/context/base.js.map +1 -0
- package/esm/context/callback-query.d.ts +27 -0
- package/esm/context/callback-query.js +52 -0
- package/esm/context/callback-query.js.map +1 -0
- package/esm/context/chat-join-request.d.ts +16 -0
- package/esm/context/chat-join-request.js +30 -0
- package/esm/context/chat-join-request.js.map +1 -0
- package/esm/context/chosen-inline-result.d.ts +21 -0
- package/esm/context/chosen-inline-result.js +31 -0
- package/esm/context/chosen-inline-result.js.map +1 -0
- package/esm/context/index.d.ts +8 -0
- package/esm/context/index.js +8 -0
- package/esm/context/index.js.map +1 -0
- package/esm/context/inline-query.d.ts +14 -0
- package/esm/context/inline-query.js +18 -0
- package/esm/context/inline-query.js.map +1 -0
- package/esm/context/message.d.ts +72 -0
- package/esm/context/message.js +138 -0
- package/esm/context/message.js.map +1 -0
- package/esm/context/parse.d.ts +1 -0
- package/esm/context/parse.js +30 -0
- package/esm/context/parse.js.map +1 -0
- package/esm/context/pre-checkout-query.d.ts +16 -0
- package/esm/context/pre-checkout-query.js +22 -0
- package/esm/context/pre-checkout-query.js.map +1 -0
- package/esm/dispatcher.d.ts +641 -0
- package/esm/dispatcher.js +761 -0
- package/esm/dispatcher.js.map +1 -0
- package/esm/filters/bots.d.ts +70 -0
- package/esm/filters/bots.js +125 -0
- package/esm/filters/bots.js.map +1 -0
- package/esm/filters/bundle.d.ts +10 -0
- package/esm/filters/bundle.js +11 -0
- package/esm/filters/bundle.js.map +1 -0
- package/esm/filters/chat.d.ts +27 -0
- package/esm/filters/chat.js +50 -0
- package/esm/filters/chat.js.map +1 -0
- package/esm/filters/group.d.ts +25 -0
- package/esm/filters/group.js +67 -0
- package/esm/filters/group.js.map +1 -0
- package/esm/filters/index.d.ts +3 -0
- package/esm/filters/index.js +3 -0
- package/esm/filters/index.js.map +1 -0
- package/esm/filters/logic.d.ts +29 -0
- package/esm/filters/logic.js +107 -0
- package/esm/filters/logic.js.map +1 -0
- package/esm/filters/message.d.ts +295 -0
- package/esm/filters/message.js +130 -0
- package/esm/filters/message.js.map +1 -0
- package/esm/filters/state.d.ts +15 -0
- package/esm/filters/state.js +27 -0
- package/esm/filters/state.js.map +1 -0
- package/esm/filters/text.d.ts +64 -0
- package/esm/filters/text.js +124 -0
- package/esm/filters/text.js.map +1 -0
- package/esm/filters/types.d.ts +91 -0
- package/esm/filters/types.js +5 -0
- package/esm/filters/types.js.map +1 -0
- package/esm/filters/updates.d.ts +46 -0
- package/esm/filters/updates.js +39 -0
- package/esm/filters/updates.js.map +1 -0
- package/esm/filters/user.d.ts +24 -0
- package/esm/filters/user.js +70 -0
- package/esm/filters/user.js.map +1 -0
- package/esm/handler.d.ts +31 -0
- package/esm/handler.js +3 -0
- package/esm/handler.js.map +1 -0
- package/esm/index.d.ts +8 -0
- package/esm/index.js +9 -0
- package/esm/index.js.map +1 -0
- package/esm/propagation.d.ts +21 -0
- package/esm/propagation.js +23 -0
- package/esm/propagation.js.map +1 -0
- package/esm/state/index.d.ts +3 -0
- package/esm/state/index.js +4 -0
- package/esm/state/index.js.map +1 -0
- package/esm/state/key.d.ts +23 -0
- package/esm/state/key.js +41 -0
- package/esm/state/key.js.map +1 -0
- package/esm/state/storage.d.ts +75 -0
- package/esm/state/storage.js +13 -0
- package/esm/state/storage.js.map +1 -0
- package/esm/state/update-state.d.ts +151 -0
- package/esm/state/update-state.js +206 -0
- package/esm/state/update-state.js.map +1 -0
- package/esm/wizard.d.ts +60 -0
- package/esm/wizard.js +99 -0
- package/esm/wizard.js.map +1 -0
- package/package.json +21 -0
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable @typescript-eslint/unified-signatures,@typescript-eslint/no-unsafe-assignment */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-call,max-depth,dot-notation */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types */
|
|
5
|
+
// ^^ will be looked into in MTQ-29
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Dispatcher = void 0;
|
|
8
|
+
const client_1 = require("@mtcute/client");
|
|
9
|
+
const parse_js_1 = require("./context/parse.js");
|
|
10
|
+
const index_js_1 = require("./state/index.js");
|
|
11
|
+
/**
|
|
12
|
+
* Updates dispatcher
|
|
13
|
+
*/
|
|
14
|
+
class Dispatcher {
|
|
15
|
+
constructor(client, params) {
|
|
16
|
+
this._groups = {};
|
|
17
|
+
this._groupsOrder = [];
|
|
18
|
+
this._children = [];
|
|
19
|
+
this.dispatchRawUpdate = this.dispatchRawUpdate.bind(this);
|
|
20
|
+
this.dispatchUpdate = this.dispatchUpdate.bind(this);
|
|
21
|
+
// eslint-disable-next-line prefer-const
|
|
22
|
+
let { storage, key, sceneName } = params ?? {};
|
|
23
|
+
if (client) {
|
|
24
|
+
this.bindToClient(client);
|
|
25
|
+
if (!storage) {
|
|
26
|
+
const _storage = client.storage;
|
|
27
|
+
if (!(0, index_js_1.isCompatibleStorage)(_storage)) {
|
|
28
|
+
throw new client_1.MtArgumentError('Storage used by the client is not compatible with the dispatcher. Please provide a compatible storage manually');
|
|
29
|
+
}
|
|
30
|
+
storage = _storage;
|
|
31
|
+
}
|
|
32
|
+
if (storage) {
|
|
33
|
+
this._storage = storage;
|
|
34
|
+
this._stateKeyDelegate = (key ?? index_js_1.defaultStateKeyDelegate);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// child dispatcher without client
|
|
39
|
+
if (storage) {
|
|
40
|
+
this._customStorage = storage;
|
|
41
|
+
}
|
|
42
|
+
if (key) {
|
|
43
|
+
this._customStateKeyDelegate = key;
|
|
44
|
+
}
|
|
45
|
+
if (sceneName) {
|
|
46
|
+
if (sceneName[0] === '$') {
|
|
47
|
+
throw new client_1.MtArgumentError('Scene name cannot start with $');
|
|
48
|
+
}
|
|
49
|
+
this._scene = sceneName;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a new dispatcher and bind it to the client.
|
|
55
|
+
*/
|
|
56
|
+
static for(client, params) {
|
|
57
|
+
return new Dispatcher(client, params);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create a new child dispatcher.
|
|
61
|
+
*/
|
|
62
|
+
static child(params) {
|
|
63
|
+
return new Dispatcher(undefined, params);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a new scene dispatcher
|
|
67
|
+
*/
|
|
68
|
+
static scene(name, params) {
|
|
69
|
+
return new Dispatcher(undefined, { sceneName: name, ...params });
|
|
70
|
+
}
|
|
71
|
+
/** For scene dispatchers, name of the scene */
|
|
72
|
+
get sceneName() {
|
|
73
|
+
return this._scene;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Bind the dispatcher to the client.
|
|
77
|
+
* Called by the constructor automatically if
|
|
78
|
+
* `client` was passed.
|
|
79
|
+
*
|
|
80
|
+
* Under the hood, this replaces client's `dispatchUpdate`
|
|
81
|
+
* function, meaning you can't bind two different
|
|
82
|
+
* dispatchers to the same client at the same time.
|
|
83
|
+
* Instead, use {@link extend}, {@link addChild}
|
|
84
|
+
* or {@link addScene} on the existing, already bound dispatcher.
|
|
85
|
+
*
|
|
86
|
+
* Dispatcher also uses bound client to throw errors
|
|
87
|
+
*/
|
|
88
|
+
bindToClient(client) {
|
|
89
|
+
client.on('update', this.dispatchUpdate);
|
|
90
|
+
client.on('raw_update', this.dispatchRawUpdate);
|
|
91
|
+
this._client = client;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Unbind a dispatcher from the client.
|
|
95
|
+
*
|
|
96
|
+
* This will replace client's dispatchUpdate with a no-op.
|
|
97
|
+
* If this dispatcher is not bound, nothing will happen.
|
|
98
|
+
*/
|
|
99
|
+
unbind() {
|
|
100
|
+
if (this._client) {
|
|
101
|
+
this._client.off('update', this.dispatchUpdate);
|
|
102
|
+
this._client.off('raw_update', this.dispatchRawUpdate);
|
|
103
|
+
this._client = undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Process a raw update with this dispatcher.
|
|
108
|
+
* Calling this method without bound client will not work.
|
|
109
|
+
*
|
|
110
|
+
* Under the hood asynchronously calls {@link dispatchRawUpdateNow}
|
|
111
|
+
* with error handler set to client's one.
|
|
112
|
+
*
|
|
113
|
+
* @param update Update to process
|
|
114
|
+
* @param peers Peers index
|
|
115
|
+
*/
|
|
116
|
+
dispatchRawUpdate(update, peers) {
|
|
117
|
+
if (!this._client)
|
|
118
|
+
return;
|
|
119
|
+
// order does not matter in the dispatcher,
|
|
120
|
+
// so we can handle each update in its own task
|
|
121
|
+
this.dispatchRawUpdateNow(update, peers).catch((err) => this._client._emitError(err));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Process a raw update right now in the current stack.
|
|
125
|
+
*
|
|
126
|
+
* Unlike {@link dispatchRawUpdate}, this does not schedule
|
|
127
|
+
* the update to be dispatched, but dispatches it immediately,
|
|
128
|
+
* and after `await`ing this method you can be certain that the update
|
|
129
|
+
* was fully processed by all the registered handlers, including children.
|
|
130
|
+
*
|
|
131
|
+
* @param update Update to process
|
|
132
|
+
* @param peers Peers map
|
|
133
|
+
* @returns Whether the update was handled
|
|
134
|
+
*/
|
|
135
|
+
async dispatchRawUpdateNow(update, peers) {
|
|
136
|
+
if (!this._client)
|
|
137
|
+
return false;
|
|
138
|
+
let handled = false;
|
|
139
|
+
outer: for (const grp of this._groupsOrder) {
|
|
140
|
+
const group = this._groups[grp];
|
|
141
|
+
if ('raw' in group) {
|
|
142
|
+
const handlers = group.raw;
|
|
143
|
+
for (const h of handlers) {
|
|
144
|
+
let result;
|
|
145
|
+
if (!h.check || (await h.check(this._client, update, peers))) {
|
|
146
|
+
result = await h.callback(this._client, update, peers);
|
|
147
|
+
handled = true;
|
|
148
|
+
}
|
|
149
|
+
else
|
|
150
|
+
continue;
|
|
151
|
+
switch (result) {
|
|
152
|
+
case 'continue':
|
|
153
|
+
continue;
|
|
154
|
+
case 'stop':
|
|
155
|
+
break outer;
|
|
156
|
+
case 'stop-children':
|
|
157
|
+
return handled;
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const child of this._children) {
|
|
164
|
+
const childHandled = await child.dispatchRawUpdateNow(update, peers);
|
|
165
|
+
handled || (handled = childHandled);
|
|
166
|
+
}
|
|
167
|
+
return handled;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Process an update with this dispatcher.
|
|
171
|
+
* Calling this method without bound client will not work.
|
|
172
|
+
*
|
|
173
|
+
* Under the hood asynchronously calls {@link dispatchUpdateNow}
|
|
174
|
+
* with error handler set to client's one.
|
|
175
|
+
*
|
|
176
|
+
* @param update Update to process
|
|
177
|
+
*/
|
|
178
|
+
dispatchUpdate(update) {
|
|
179
|
+
if (!this._client)
|
|
180
|
+
return;
|
|
181
|
+
// order does not matter in the dispatcher,
|
|
182
|
+
// so we can handle each update in its own task
|
|
183
|
+
this.dispatchUpdateNow(update).catch((err) => this._client._emitError(err));
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Process an update right now in the current stack.
|
|
187
|
+
*
|
|
188
|
+
* Unlike {@link dispatchUpdate}, this does not schedule
|
|
189
|
+
* the update to be dispatched, but dispatches it immediately,
|
|
190
|
+
* and after `await`ing this method you can be certain that the update
|
|
191
|
+
* was fully processed by all the registered handlers, including children.
|
|
192
|
+
*
|
|
193
|
+
* @param update Update to process
|
|
194
|
+
* @returns Whether the update was handled
|
|
195
|
+
*/
|
|
196
|
+
async dispatchUpdateNow(update) {
|
|
197
|
+
return this._dispatchUpdateNowImpl(update);
|
|
198
|
+
}
|
|
199
|
+
async _dispatchUpdateNowImpl(update,
|
|
200
|
+
// this is getting a bit crazy lol
|
|
201
|
+
parsedState, parsedScene, forceScene, parsedContext) {
|
|
202
|
+
if (!this._client)
|
|
203
|
+
return false;
|
|
204
|
+
if (parsedScene === undefined) {
|
|
205
|
+
if (this._storage &&
|
|
206
|
+
this._scenes &&
|
|
207
|
+
(update.name === 'new_message' ||
|
|
208
|
+
update.name === 'edit_message' ||
|
|
209
|
+
update.name === 'callback_query' ||
|
|
210
|
+
update.name === 'message_group')) {
|
|
211
|
+
// no need to fetch scene if there are no registered scenes
|
|
212
|
+
if (!parsedContext)
|
|
213
|
+
parsedContext = (0, parse_js_1._parsedUpdateToContext)(this._client, update);
|
|
214
|
+
const key = await this._stateKeyDelegate(parsedContext);
|
|
215
|
+
if (key) {
|
|
216
|
+
parsedScene = await this._storage.getCurrentScene(key);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
parsedScene = null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
parsedScene = null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (!forceScene && parsedScene !== null) {
|
|
227
|
+
if (this._scene) {
|
|
228
|
+
if (this._scene !== parsedScene) {
|
|
229
|
+
// should not happen, but just in case
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
if (!this._scenes || !(parsedScene in this._scenes)) {
|
|
235
|
+
// not registered scene
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
return this._scenes[parsedScene]._dispatchUpdateNowImpl(update, parsedState, parsedScene, true);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (parsedState === undefined) {
|
|
242
|
+
if (this._storage &&
|
|
243
|
+
(update.name === 'new_message' ||
|
|
244
|
+
update.name === 'edit_message' ||
|
|
245
|
+
update.name === 'callback_query' ||
|
|
246
|
+
update.name === 'message_group')) {
|
|
247
|
+
if (!parsedContext)
|
|
248
|
+
parsedContext = (0, parse_js_1._parsedUpdateToContext)(this._client, update);
|
|
249
|
+
const key = await this._stateKeyDelegate(parsedContext);
|
|
250
|
+
if (key) {
|
|
251
|
+
let customKey;
|
|
252
|
+
if (!this._customStateKeyDelegate ||
|
|
253
|
+
(customKey = await this._customStateKeyDelegate(parsedContext))) {
|
|
254
|
+
parsedState = new index_js_1.UpdateState(this._storage, key, this._scene ?? null, this._sceneScoped, this._customStorage, customKey);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
parsedState = null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
parsedState = null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
let shouldDispatch = true;
|
|
266
|
+
let shouldDispatchChildren = true;
|
|
267
|
+
let handled = false;
|
|
268
|
+
switch (await this._preUpdateHandler?.(update, parsedState)) {
|
|
269
|
+
case 'stop':
|
|
270
|
+
shouldDispatch = false;
|
|
271
|
+
break;
|
|
272
|
+
case 'stop-children':
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
if (shouldDispatch) {
|
|
276
|
+
outer: for (const grp of this._groupsOrder) {
|
|
277
|
+
const group = this._groups[grp];
|
|
278
|
+
if (update.name in group) {
|
|
279
|
+
// raw is not handled here, so we can safely assume this
|
|
280
|
+
const handlers = group[update.name];
|
|
281
|
+
try {
|
|
282
|
+
for (const h of handlers) {
|
|
283
|
+
let result;
|
|
284
|
+
if (!parsedContext)
|
|
285
|
+
parsedContext = (0, parse_js_1._parsedUpdateToContext)(this._client, update);
|
|
286
|
+
if (!h.check || (await h.check(parsedContext, parsedState))) {
|
|
287
|
+
result = await h.callback(parsedContext, parsedState);
|
|
288
|
+
handled = true;
|
|
289
|
+
}
|
|
290
|
+
else
|
|
291
|
+
continue;
|
|
292
|
+
switch (result) {
|
|
293
|
+
case 'continue':
|
|
294
|
+
continue;
|
|
295
|
+
case 'stop':
|
|
296
|
+
break outer;
|
|
297
|
+
case 'stop-children':
|
|
298
|
+
shouldDispatchChildren = false;
|
|
299
|
+
break outer;
|
|
300
|
+
case 'scene': {
|
|
301
|
+
if (!parsedState) {
|
|
302
|
+
throw new client_1.MtArgumentError('Cannot use ToScene without state');
|
|
303
|
+
}
|
|
304
|
+
const scene = parsedState['_scene'];
|
|
305
|
+
if (!scene) {
|
|
306
|
+
throw new client_1.MtArgumentError('Cannot use ToScene without entering a scene');
|
|
307
|
+
}
|
|
308
|
+
return this._scenes[scene]._dispatchUpdateNowImpl(update, undefined, scene, true);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch (e) {
|
|
315
|
+
if (this._errorHandler) {
|
|
316
|
+
const handled = await this._errorHandler(e, update, parsedState);
|
|
317
|
+
if (!handled)
|
|
318
|
+
throw e;
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
throw e;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (shouldDispatchChildren) {
|
|
328
|
+
for (const child of this._children) {
|
|
329
|
+
const childHandled = await child._dispatchUpdateNowImpl(update);
|
|
330
|
+
handled || (handled = childHandled);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
await this._postUpdateHandler?.(handled, update, parsedState);
|
|
334
|
+
return handled;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Add an update handler to a given handlers group
|
|
338
|
+
*
|
|
339
|
+
* @param handler Update handler
|
|
340
|
+
* @param group Handler group index
|
|
341
|
+
*/
|
|
342
|
+
addUpdateHandler(handler, group = 0) {
|
|
343
|
+
if (!(group in this._groups)) {
|
|
344
|
+
this._groups[group] = {};
|
|
345
|
+
this._groupsOrder.push(group);
|
|
346
|
+
this._groupsOrder.sort((a, b) => a - b);
|
|
347
|
+
}
|
|
348
|
+
if (!(handler.name in this._groups[group])) {
|
|
349
|
+
this._groups[group][handler.name] = [];
|
|
350
|
+
}
|
|
351
|
+
this._groups[group][handler.name].push(handler);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Remove an update handler (or handlers) from a given
|
|
355
|
+
* handler group.
|
|
356
|
+
*
|
|
357
|
+
* @param handler Update handler to remove, its name or `'all'` to remove all
|
|
358
|
+
* @param group Handler group index (-1 to affect all groups)
|
|
359
|
+
*/
|
|
360
|
+
removeUpdateHandler(handler, group = 0) {
|
|
361
|
+
if (group !== -1 && !(group in this._groups)) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (typeof handler === 'string') {
|
|
365
|
+
if (handler === 'all') {
|
|
366
|
+
if (group === -1) {
|
|
367
|
+
this._groups = {};
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
delete this._groups[group];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
delete this._groups[group][handler];
|
|
375
|
+
}
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (!(handler.name in this._groups[group])) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const idx = this._groups[group][handler.name].indexOf(handler);
|
|
382
|
+
if (idx > -1) {
|
|
383
|
+
this._groups[group][handler.name].splice(idx, 1);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Register an error handler.
|
|
388
|
+
*
|
|
389
|
+
* This is used locally within this dispatcher
|
|
390
|
+
* (does not affect children/parent) whenever
|
|
391
|
+
* an error is thrown inside an update handler.
|
|
392
|
+
* Not used for raw update handlers
|
|
393
|
+
*
|
|
394
|
+
* When an error is thrown, but there is no error
|
|
395
|
+
* handler, it is propagated to `TelegramClient`.
|
|
396
|
+
*
|
|
397
|
+
* There can be at most one error handler.
|
|
398
|
+
* Pass `null` to remove it.
|
|
399
|
+
*
|
|
400
|
+
* @param handler Error handler
|
|
401
|
+
*/
|
|
402
|
+
onError(handler) {
|
|
403
|
+
if (handler)
|
|
404
|
+
this._errorHandler = handler;
|
|
405
|
+
else
|
|
406
|
+
this._errorHandler = undefined;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Register pre-update middleware.
|
|
410
|
+
*
|
|
411
|
+
* This is used locally within this dispatcher
|
|
412
|
+
* (does not affect children/parent) before processing
|
|
413
|
+
* an update, and can be used to skip this update.
|
|
414
|
+
*
|
|
415
|
+
* There can be at most one pre-update middleware.
|
|
416
|
+
* Pass `null` to remove it.
|
|
417
|
+
*
|
|
418
|
+
* @param handler Pre-update middleware
|
|
419
|
+
*/
|
|
420
|
+
onPreUpdate(handler) {
|
|
421
|
+
if (handler)
|
|
422
|
+
this._preUpdateHandler = handler;
|
|
423
|
+
else
|
|
424
|
+
this._preUpdateHandler = undefined;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Register post-update middleware.
|
|
428
|
+
*
|
|
429
|
+
* This is used locally within this dispatcher
|
|
430
|
+
* (does not affect children/parent) after successfully
|
|
431
|
+
* processing an update, and can be used for stats.
|
|
432
|
+
*
|
|
433
|
+
* There can be at most one post-update middleware.
|
|
434
|
+
* Pass `null` to remove it.
|
|
435
|
+
*
|
|
436
|
+
* @param handler Pre-update middleware
|
|
437
|
+
*/
|
|
438
|
+
onPostUpdate(handler) {
|
|
439
|
+
if (handler)
|
|
440
|
+
this._postUpdateHandler = handler;
|
|
441
|
+
else
|
|
442
|
+
this._postUpdateHandler = undefined;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Set error handler that will propagate
|
|
446
|
+
* the error to the parent dispatcher
|
|
447
|
+
*/
|
|
448
|
+
propagateErrorToParent(err, update, state) {
|
|
449
|
+
if (!this.parent) {
|
|
450
|
+
throw new client_1.MtArgumentError('This dispatcher is not a child');
|
|
451
|
+
}
|
|
452
|
+
if (this.parent._errorHandler) {
|
|
453
|
+
return this.parent._errorHandler(err, update, state);
|
|
454
|
+
}
|
|
455
|
+
throw err;
|
|
456
|
+
}
|
|
457
|
+
// children //
|
|
458
|
+
/**
|
|
459
|
+
* Get parent dispatcher if current dispatcher is a child.
|
|
460
|
+
* Otherwise, return `null`
|
|
461
|
+
*/
|
|
462
|
+
get parent() {
|
|
463
|
+
return this._parent ?? null;
|
|
464
|
+
}
|
|
465
|
+
_prepareChild(child) {
|
|
466
|
+
if (child._client) {
|
|
467
|
+
throw new client_1.MtArgumentError('Provided dispatcher is ' +
|
|
468
|
+
(child._parent ?
|
|
469
|
+
'already a child. Use parent.removeChild() before calling addChild()' :
|
|
470
|
+
'already bound to a client. Use unbind() before calling addChild()'));
|
|
471
|
+
}
|
|
472
|
+
child._parent = this;
|
|
473
|
+
child._client = this._client;
|
|
474
|
+
child._storage = this._storage;
|
|
475
|
+
child._stateKeyDelegate = this._stateKeyDelegate;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Add a child dispatcher.
|
|
479
|
+
*
|
|
480
|
+
* Child dispatchers are called when dispatching updates
|
|
481
|
+
* just like normal, except they can be controlled
|
|
482
|
+
* externally. Additionally, child dispatcher have their own
|
|
483
|
+
* independent handler grouping that does not interfere with parent's,
|
|
484
|
+
* including `StopPropagation` (i.e. returning `StopPropagation` will
|
|
485
|
+
* still call children. To entirely stop, use `StopChildrenPropagation`)
|
|
486
|
+
*
|
|
487
|
+
* Note that child dispatchers share the same TelegramClient and
|
|
488
|
+
* storage binding as the parent, don't bind them manually.
|
|
489
|
+
*
|
|
490
|
+
* @param child Other dispatcher
|
|
491
|
+
*/
|
|
492
|
+
addChild(child) {
|
|
493
|
+
if (this._children.includes(child))
|
|
494
|
+
return;
|
|
495
|
+
this._prepareChild(child);
|
|
496
|
+
this._children.push(child);
|
|
497
|
+
}
|
|
498
|
+
addScene(scene, scoped = true) {
|
|
499
|
+
if (!this._scenes)
|
|
500
|
+
this._scenes = {};
|
|
501
|
+
if (!scene._scene) {
|
|
502
|
+
throw new client_1.MtArgumentError('Non-scene dispatcher passed to addScene. Use `Dispatcher.scene()` to create one.');
|
|
503
|
+
}
|
|
504
|
+
if (scene._scene in this._scenes) {
|
|
505
|
+
throw new client_1.MtArgumentError(`Scene with name ${scene._scene} is already registered!`);
|
|
506
|
+
}
|
|
507
|
+
this._prepareChild(scene);
|
|
508
|
+
scene._sceneScoped = scoped;
|
|
509
|
+
this._scenes[scene._scene] = scene;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Remove a child dispatcher.
|
|
513
|
+
*
|
|
514
|
+
* Removing child dispatcher will also remove
|
|
515
|
+
* child dispatcher's client binding.
|
|
516
|
+
*
|
|
517
|
+
* If the provided dispatcher is not a child of current,
|
|
518
|
+
* this function will silently fail.
|
|
519
|
+
*
|
|
520
|
+
* @param child Other dispatcher
|
|
521
|
+
*/
|
|
522
|
+
removeChild(child) {
|
|
523
|
+
const idx = this._children.indexOf(child);
|
|
524
|
+
if (idx > -1) {
|
|
525
|
+
child._unparent();
|
|
526
|
+
this._children.splice(idx, 1);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
_unparent() {
|
|
530
|
+
this._parent = this._client = undefined;
|
|
531
|
+
this._stateKeyDelegate = undefined;
|
|
532
|
+
this._storage = undefined;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Extend current dispatcher by copying other dispatcher's
|
|
536
|
+
* handlers and children to the current.
|
|
537
|
+
*
|
|
538
|
+
* This might be more efficient for simple cases, but do note that the handler
|
|
539
|
+
* groups, children and scenes will get merged (unlike {@link addChild},
|
|
540
|
+
* where they are independent). Also note that unlike with children,
|
|
541
|
+
* when adding handlers to `other` *after* you extended
|
|
542
|
+
* the current dispatcher, changes will not be applied.
|
|
543
|
+
*
|
|
544
|
+
* @param other Other dispatcher
|
|
545
|
+
*/
|
|
546
|
+
extend(other) {
|
|
547
|
+
if (other._customStorage || other._customStateKeyDelegate) {
|
|
548
|
+
throw new client_1.MtArgumentError('Provided dispatcher has custom storage and cannot be extended from.');
|
|
549
|
+
}
|
|
550
|
+
other._groupsOrder.forEach((group) => {
|
|
551
|
+
if (!(group in this._groups)) {
|
|
552
|
+
this._groups[group] = other._groups[group];
|
|
553
|
+
this._groupsOrder.push(group);
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
const otherGrp = other._groups[group];
|
|
557
|
+
const selfGrp = this._groups[group];
|
|
558
|
+
Object.keys(otherGrp).forEach((typ) => {
|
|
559
|
+
if (!(typ in selfGrp)) {
|
|
560
|
+
selfGrp[typ] = otherGrp[typ];
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
selfGrp[typ].push(...otherGrp[typ]);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
other._children.forEach((it) => {
|
|
569
|
+
it._unparent();
|
|
570
|
+
this.addChild(it);
|
|
571
|
+
});
|
|
572
|
+
if (other._scenes) {
|
|
573
|
+
const otherScenes = other._scenes;
|
|
574
|
+
if (!this._scenes)
|
|
575
|
+
this._scenes = {};
|
|
576
|
+
const myScenes = this._scenes;
|
|
577
|
+
Object.keys(otherScenes).forEach((key) => {
|
|
578
|
+
otherScenes[key]._unparent();
|
|
579
|
+
if (key in myScenes) {
|
|
580
|
+
// will be overwritten
|
|
581
|
+
delete myScenes[key];
|
|
582
|
+
}
|
|
583
|
+
this.addScene(myScenes[key], myScenes[key]._sceneScoped);
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
this._groupsOrder.sort((a, b) => a - b);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Create a clone of this dispatcher, that has the same handlers,
|
|
590
|
+
* but is not bound to a client or to a parent dispatcher.
|
|
591
|
+
*
|
|
592
|
+
* Custom Storage and key delegate are copied too.
|
|
593
|
+
*
|
|
594
|
+
* By default, child dispatchers (and scenes) are ignored, since
|
|
595
|
+
* that requires cloning every single one of them recursively
|
|
596
|
+
* and then binding them back.
|
|
597
|
+
*
|
|
598
|
+
* @param children Whether to also clone children and scenes
|
|
599
|
+
*/
|
|
600
|
+
clone(children = false) {
|
|
601
|
+
const dp = new Dispatcher();
|
|
602
|
+
// copy handlers.
|
|
603
|
+
Object.keys(this._groups).forEach((key) => {
|
|
604
|
+
const idx = key;
|
|
605
|
+
dp._groups[idx] = {};
|
|
606
|
+
Object.keys(this._groups[idx]).forEach((type) => {
|
|
607
|
+
dp._groups[idx][type] = [...this._groups[idx][type]];
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
dp._groupsOrder = [...this._groupsOrder];
|
|
611
|
+
dp._errorHandler = this._errorHandler;
|
|
612
|
+
dp._customStateKeyDelegate = this._customStateKeyDelegate;
|
|
613
|
+
dp._customStorage = this._customStorage;
|
|
614
|
+
if (children) {
|
|
615
|
+
this._children.forEach((it) => {
|
|
616
|
+
const child = it.clone(true);
|
|
617
|
+
dp.addChild(child);
|
|
618
|
+
});
|
|
619
|
+
if (this._scenes) {
|
|
620
|
+
Object.keys(this._scenes).forEach((key) => {
|
|
621
|
+
const scene = this._scenes[key].clone(true);
|
|
622
|
+
dp.addScene(scene, this._scenes[key]._sceneScoped);
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return dp;
|
|
627
|
+
}
|
|
628
|
+
getState(object) {
|
|
629
|
+
if (!this._storage) {
|
|
630
|
+
throw new client_1.MtArgumentError('Cannot use getUpdateState() filter without state storage');
|
|
631
|
+
}
|
|
632
|
+
if (typeof object === 'string') {
|
|
633
|
+
return new index_js_1.UpdateState(this._storage, object, this._scene ?? null, this._sceneScoped, this._customStorage);
|
|
634
|
+
}
|
|
635
|
+
return Promise.resolve(this._stateKeyDelegate(object)).then((key) => {
|
|
636
|
+
if (!key) {
|
|
637
|
+
throw new client_1.MtArgumentError('Cannot derive key from given object');
|
|
638
|
+
}
|
|
639
|
+
if (!this._customStateKeyDelegate) {
|
|
640
|
+
return new index_js_1.UpdateState(this._storage, key, this._scene ?? null, this._sceneScoped, this._customStorage);
|
|
641
|
+
}
|
|
642
|
+
return Promise.resolve(this._customStateKeyDelegate(object)).then((customKey) => {
|
|
643
|
+
if (!customKey) {
|
|
644
|
+
throw new client_1.MtArgumentError('Cannot derive custom key from given object');
|
|
645
|
+
}
|
|
646
|
+
return new index_js_1.UpdateState(this._storage, key, this._scene ?? null, this._sceneScoped, this._customStorage, customKey);
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Get global state.
|
|
652
|
+
*
|
|
653
|
+
* This will load the state for the given object
|
|
654
|
+
* ignoring local custom storage, key delegate and scene scope.
|
|
655
|
+
*/
|
|
656
|
+
getGlobalState(object) {
|
|
657
|
+
if (!this._parent) {
|
|
658
|
+
throw new client_1.MtArgumentError('This dispatcher does not have a parent');
|
|
659
|
+
}
|
|
660
|
+
return Promise.resolve(this._stateKeyDelegate(object)).then((key) => {
|
|
661
|
+
if (!key) {
|
|
662
|
+
throw new client_1.MtArgumentError('Cannot derive key from given object');
|
|
663
|
+
}
|
|
664
|
+
return new index_js_1.UpdateState(this._storage, key, this._scene ?? null, false);
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
// addUpdateHandler convenience wrappers //
|
|
668
|
+
_addKnownHandler(name, filter, handler, group) {
|
|
669
|
+
if (typeof handler === 'number' || typeof handler === 'undefined') {
|
|
670
|
+
this.addUpdateHandler({
|
|
671
|
+
name,
|
|
672
|
+
callback: filter,
|
|
673
|
+
}, handler);
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
this.addUpdateHandler({
|
|
677
|
+
name,
|
|
678
|
+
callback: handler,
|
|
679
|
+
check: filter,
|
|
680
|
+
}, group);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/** @internal */
|
|
684
|
+
onRawUpdate(filter, handler, group) {
|
|
685
|
+
this._addKnownHandler('raw', filter, handler, group);
|
|
686
|
+
}
|
|
687
|
+
/** @internal */
|
|
688
|
+
onNewMessage(filter, handler, group) {
|
|
689
|
+
this._addKnownHandler('new_message', filter, handler, group);
|
|
690
|
+
}
|
|
691
|
+
/** @internal */
|
|
692
|
+
onEditMessage(filter, handler, group) {
|
|
693
|
+
this._addKnownHandler('edit_message', filter, handler, group);
|
|
694
|
+
}
|
|
695
|
+
/** @internal */
|
|
696
|
+
onMessageGroup(filter, handler, group) {
|
|
697
|
+
this._addKnownHandler('message_group', filter, handler, group);
|
|
698
|
+
}
|
|
699
|
+
/** @internal */
|
|
700
|
+
onDeleteMessage(filter, handler, group) {
|
|
701
|
+
this._addKnownHandler('delete_message', filter, handler, group);
|
|
702
|
+
}
|
|
703
|
+
/** @internal */
|
|
704
|
+
onChatMemberUpdate(filter, handler, group) {
|
|
705
|
+
this._addKnownHandler('chat_member', filter, handler, group);
|
|
706
|
+
}
|
|
707
|
+
/** @internal */
|
|
708
|
+
onInlineQuery(filter, handler, group) {
|
|
709
|
+
this._addKnownHandler('inline_query', filter, handler, group);
|
|
710
|
+
}
|
|
711
|
+
/** @internal */
|
|
712
|
+
onChosenInlineResult(filter, handler, group) {
|
|
713
|
+
this._addKnownHandler('chosen_inline_result', filter, handler, group);
|
|
714
|
+
}
|
|
715
|
+
/** @internal */
|
|
716
|
+
onCallbackQuery(filter, handler, group) {
|
|
717
|
+
this._addKnownHandler('callback_query', filter, handler, group);
|
|
718
|
+
}
|
|
719
|
+
/** @internal */
|
|
720
|
+
onPollUpdate(filter, handler, group) {
|
|
721
|
+
this._addKnownHandler('poll', filter, handler, group);
|
|
722
|
+
}
|
|
723
|
+
/** @internal */
|
|
724
|
+
onPollVote(filter, handler, group) {
|
|
725
|
+
this._addKnownHandler('poll_vote', filter, handler, group);
|
|
726
|
+
}
|
|
727
|
+
/** @internal */
|
|
728
|
+
onUserStatusUpdate(filter, handler, group) {
|
|
729
|
+
this._addKnownHandler('user_status', filter, handler, group);
|
|
730
|
+
}
|
|
731
|
+
/** @internal */
|
|
732
|
+
onUserTyping(filter, handler, group) {
|
|
733
|
+
this._addKnownHandler('user_typing', filter, handler, group);
|
|
734
|
+
}
|
|
735
|
+
/** @internal */
|
|
736
|
+
onHistoryRead(filter, handler, group) {
|
|
737
|
+
this._addKnownHandler('history_read', filter, handler, group);
|
|
738
|
+
}
|
|
739
|
+
/** @internal */
|
|
740
|
+
onBotStopped(filter, handler, group) {
|
|
741
|
+
this._addKnownHandler('bot_stopped', filter, handler, group);
|
|
742
|
+
}
|
|
743
|
+
/** @internal */
|
|
744
|
+
onBotChatJoinRequest(filter, handler, group) {
|
|
745
|
+
this._addKnownHandler('bot_chat_join_request', filter, handler, group);
|
|
746
|
+
}
|
|
747
|
+
/** @internal */
|
|
748
|
+
onChatJoinRequest(filter, handler, group) {
|
|
749
|
+
this._addKnownHandler('chat_join_request', filter, handler, group);
|
|
750
|
+
}
|
|
751
|
+
/** @internal */
|
|
752
|
+
onPreCheckoutQuery(filter, handler, group) {
|
|
753
|
+
this._addKnownHandler('pre_checkout_query', filter, handler, group);
|
|
754
|
+
}
|
|
755
|
+
/** @internal */
|
|
756
|
+
onStoryUpdate(filter, handler, group) {
|
|
757
|
+
this._addKnownHandler('story', filter, handler, group);
|
|
758
|
+
}
|
|
759
|
+
/** @internal */
|
|
760
|
+
onDeleteStory(filter, handler, group) {
|
|
761
|
+
this._addKnownHandler('delete_story', filter, handler, group);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
exports.Dispatcher = Dispatcher;
|
|
765
|
+
//# sourceMappingURL=dispatcher.js.map
|