@mtkruto/node 0.0.985 → 0.0.987
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/esm/client/0_utilities.d.ts +2 -0
- package/esm/client/0_utilities.js +22 -0
- package/esm/client/1_client_abstract.d.ts +15 -10
- package/esm/client/1_client_abstract.js +26 -27
- package/esm/client/2_client_plain.d.ts +9 -3
- package/esm/client/2_client_plain.js +9 -5
- package/esm/client/3_client.d.ts +30 -19
- package/esm/client/3_client.js +319 -291
- package/esm/connection/0_connection.d.ts +1 -0
- package/esm/connection/0_connection.js +8 -0
- package/esm/connection/1_connection_web_socket.d.ts +3 -1
- package/esm/connection/1_connection_web_socket.js +28 -9
- package/esm/constants.d.ts +1 -1
- package/esm/constants.js +1 -1
- package/esm/deps.js +1 -1
- package/esm/tl/0_tl_raw_reader.d.ts +2 -0
- package/esm/tl/0_tl_raw_reader.js +3 -1
- package/esm/tl/3_tl_reader.js +2 -2
- package/esm/transport/2_transport_provider.d.ts +7 -14
- package/esm/transport/2_transport_provider.js +9 -12
- package/esm/utilities/0_queue.d.ts +6 -0
- package/esm/utilities/0_queue.js +38 -0
- package/package.json +1 -1
- package/script/client/0_utilities.d.ts +2 -0
- package/script/client/0_utilities.js +25 -1
- package/script/client/1_client_abstract.d.ts +15 -10
- package/script/client/1_client_abstract.js +26 -27
- package/script/client/2_client_plain.d.ts +9 -3
- package/script/client/2_client_plain.js +9 -5
- package/script/client/3_client.d.ts +30 -19
- package/script/client/3_client.js +318 -290
- package/script/connection/0_connection.d.ts +1 -0
- package/script/connection/0_connection.js +8 -0
- package/script/connection/1_connection_web_socket.d.ts +3 -1
- package/script/connection/1_connection_web_socket.js +28 -9
- package/script/constants.d.ts +1 -1
- package/script/constants.js +1 -1
- package/script/deps.js +1 -1
- package/script/tl/0_tl_raw_reader.d.ts +2 -0
- package/script/tl/0_tl_raw_reader.js +5 -2
- package/script/tl/3_tl_reader.js +1 -1
- package/script/transport/2_transport_provider.d.ts +7 -14
- package/script/transport/2_transport_provider.js +9 -12
- package/script/utilities/0_queue.d.ts +6 -0
- package/script/utilities/0_queue.js +42 -0
|
@@ -52,12 +52,13 @@ const _2_client_plain_js_1 = require("./2_client_plain.js");
|
|
|
52
52
|
const _1_misc_js_1 = require("../utilities/1_misc.js");
|
|
53
53
|
const _0_utilities_js_1 = require("./0_utilities.js");
|
|
54
54
|
const _1_user_js_1 = require("../types/1_user.js");
|
|
55
|
+
const _0_tl_raw_reader_js_1 = require("../tl/0_tl_raw_reader.js");
|
|
56
|
+
const _0_queue_js_1 = require("../utilities/0_queue.js");
|
|
55
57
|
const d = (0, deps_js_1.debug)("Client");
|
|
56
58
|
const dGap = (0, deps_js_1.debug)("Client/recoverUpdateGap");
|
|
57
59
|
const dGapC = (0, deps_js_1.debug)("Client/recoverChannelUpdateGap");
|
|
58
60
|
const dAuth = (0, deps_js_1.debug)("Client/authorize");
|
|
59
61
|
const dRecv = (0, deps_js_1.debug)("Client/receiveLoop");
|
|
60
|
-
const UPDATE_GAP = Symbol();
|
|
61
62
|
exports.getEntity = Symbol();
|
|
62
63
|
exports.getStickerSetName = Symbol();
|
|
63
64
|
exports.handleMigrationError = Symbol();
|
|
@@ -76,8 +77,8 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
76
77
|
* @param apiHash App's API hash from [my.telegram.org/apps](https://my.telegram.org/apps). Defaults to empty string (unset).
|
|
77
78
|
* @param params Other parameters.
|
|
78
79
|
*/
|
|
79
|
-
constructor(storage = new _1_storage_memory_js_1.StorageMemory(), apiId = 0, apiHash = "", params
|
|
80
|
-
super(params
|
|
80
|
+
constructor(storage = new _1_storage_memory_js_1.StorageMemory(), apiId = 0, apiHash = "", params) {
|
|
81
|
+
super(params);
|
|
81
82
|
Object.defineProperty(this, "storage", {
|
|
82
83
|
enumerable: true,
|
|
83
84
|
configurable: true,
|
|
@@ -132,12 +133,6 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
132
133
|
writable: true,
|
|
133
134
|
value: void 0
|
|
134
135
|
});
|
|
135
|
-
Object.defineProperty(this, "updateHandler", {
|
|
136
|
-
enumerable: true,
|
|
137
|
-
configurable: true,
|
|
138
|
-
writable: true,
|
|
139
|
-
value: null
|
|
140
|
-
});
|
|
141
136
|
Object.defineProperty(this, "parseMode", {
|
|
142
137
|
enumerable: true,
|
|
143
138
|
configurable: true,
|
|
@@ -192,12 +187,26 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
192
187
|
writable: true,
|
|
193
188
|
value: void 0
|
|
194
189
|
});
|
|
190
|
+
Object.defineProperty(this, "stateChangeHandler", {
|
|
191
|
+
enumerable: true,
|
|
192
|
+
configurable: true,
|
|
193
|
+
writable: true,
|
|
194
|
+
value: ((connected) => {
|
|
195
|
+
this.propagateConnectionState(connected ? "ready" : "not-connected");
|
|
196
|
+
}).bind(this)
|
|
197
|
+
});
|
|
195
198
|
Object.defineProperty(this, "storageInited", {
|
|
196
199
|
enumerable: true,
|
|
197
200
|
configurable: true,
|
|
198
201
|
writable: true,
|
|
199
202
|
value: false
|
|
200
203
|
});
|
|
204
|
+
Object.defineProperty(this, "connectMutex", {
|
|
205
|
+
enumerable: true,
|
|
206
|
+
configurable: true,
|
|
207
|
+
writable: true,
|
|
208
|
+
value: new deps_js_1.Mutex()
|
|
209
|
+
});
|
|
201
210
|
Object.defineProperty(this, "connectionInited", {
|
|
202
211
|
enumerable: true,
|
|
203
212
|
configurable: true,
|
|
@@ -216,23 +225,25 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
216
225
|
writable: true,
|
|
217
226
|
value: 0n
|
|
218
227
|
});
|
|
219
|
-
Object.defineProperty(this, "
|
|
228
|
+
Object.defineProperty(this, "handleUpdateQueue", {
|
|
220
229
|
enumerable: true,
|
|
221
230
|
configurable: true,
|
|
222
231
|
writable: true,
|
|
223
|
-
value: new
|
|
232
|
+
value: new _0_queue_js_1.Queue()
|
|
224
233
|
});
|
|
225
|
-
Object.defineProperty(this, "
|
|
234
|
+
Object.defineProperty(this, "processUpdatesQueue", {
|
|
226
235
|
enumerable: true,
|
|
227
236
|
configurable: true,
|
|
228
237
|
writable: true,
|
|
229
|
-
value: new
|
|
238
|
+
value: new _0_queue_js_1.Queue()
|
|
230
239
|
});
|
|
231
|
-
Object.defineProperty(this, "
|
|
240
|
+
Object.defineProperty(this, "handler", {
|
|
232
241
|
enumerable: true,
|
|
233
242
|
configurable: true,
|
|
234
243
|
writable: true,
|
|
235
|
-
value:
|
|
244
|
+
value: (_upd, next) => {
|
|
245
|
+
next();
|
|
246
|
+
}
|
|
236
247
|
});
|
|
237
248
|
this.parseMode = params?.parseMode ?? ParseMode.None;
|
|
238
249
|
this.appVersion = params?.appVersion ?? constants_js_1.APP_VERSION;
|
|
@@ -244,6 +255,9 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
244
255
|
this.publicKeys = params?.publicKeys;
|
|
245
256
|
this.autoStart = params?.autoStart ?? true;
|
|
246
257
|
}
|
|
258
|
+
propagateConnectionState(connectionState) {
|
|
259
|
+
return this.handler({ connectionState }, resolve);
|
|
260
|
+
}
|
|
247
261
|
/**
|
|
248
262
|
* Sets the DC and resets the auth key stored in the session provider
|
|
249
263
|
* if the stored DC was not the same as the `dc` parameter.
|
|
@@ -273,38 +287,47 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
273
287
|
* Before establishing the connection, the session is saved.
|
|
274
288
|
*/
|
|
275
289
|
async connect() {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
this.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
290
|
+
const release = await this.connectMutex.acquire();
|
|
291
|
+
try {
|
|
292
|
+
if (this.connected) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (!this.storageInited) {
|
|
296
|
+
await this.storage.init();
|
|
297
|
+
this.storageInited = true;
|
|
298
|
+
}
|
|
299
|
+
const authKey = await this.storage.getAuthKey();
|
|
300
|
+
if (authKey == null) {
|
|
301
|
+
const plain = new _2_client_plain_js_1.ClientPlain({ initialDc: this.initialDc, transportProvider: this.transportProvider, cdn: this.cdn, publicKeys: this.publicKeys });
|
|
302
|
+
const dc = await this.storage.getDc();
|
|
303
|
+
if (dc != null) {
|
|
304
|
+
plain.setDc(dc);
|
|
305
|
+
}
|
|
306
|
+
await plain.connect();
|
|
307
|
+
const { authKey, salt } = await plain.createAuthKey();
|
|
308
|
+
await plain.disconnect();
|
|
309
|
+
await this.storage.setAuthKey(authKey);
|
|
310
|
+
await this.setAuth(authKey);
|
|
311
|
+
this.state.salt = salt;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
await this.setAuth(authKey);
|
|
315
|
+
}
|
|
283
316
|
const dc = await this.storage.getDc();
|
|
284
317
|
if (dc != null) {
|
|
285
|
-
|
|
318
|
+
await this.setDc(dc);
|
|
286
319
|
}
|
|
287
|
-
await
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
this.
|
|
293
|
-
|
|
294
|
-
else {
|
|
295
|
-
await this.setAuth(authKey);
|
|
296
|
-
}
|
|
297
|
-
const dc = await this.storage.getDc();
|
|
298
|
-
if (dc != null) {
|
|
299
|
-
await this.setDc(dc);
|
|
320
|
+
await super.connect();
|
|
321
|
+
if (dc == null) {
|
|
322
|
+
await this.storage.setDc(this.initialDc);
|
|
323
|
+
}
|
|
324
|
+
d("encrypted client connected");
|
|
325
|
+
(0, _1_misc_js_1.drop)(this.receiveLoop());
|
|
326
|
+
(0, _1_misc_js_1.drop)(this.pingLoop());
|
|
300
327
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
await this.storage.setDc(this.transportProvider.initialDc);
|
|
328
|
+
finally {
|
|
329
|
+
release();
|
|
304
330
|
}
|
|
305
|
-
d("encrypted client connected");
|
|
306
|
-
(0, _1_misc_js_1.drop)(this.receiveLoop());
|
|
307
|
-
(0, _1_misc_js_1.drop)(this.pingLoop());
|
|
308
331
|
}
|
|
309
332
|
async fetchState(source) {
|
|
310
333
|
const state = await this.invoke(new functions.UpdatesGetState());
|
|
@@ -378,7 +401,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
378
401
|
params = (0, _1_misc_js_1.mustPrompt)("Bot token:");
|
|
379
402
|
}
|
|
380
403
|
else {
|
|
381
|
-
params = { phone: () => (0, _1_misc_js_1.mustPrompt)("Phone number:"), code: () => (0, _1_misc_js_1.mustPrompt)("Verification code:"), password: () => (0, _1_misc_js_1.mustPrompt)(
|
|
404
|
+
params = { phone: () => (0, _1_misc_js_1.mustPrompt)("Phone number:"), code: () => (0, _1_misc_js_1.mustPrompt)("Verification code:"), password: () => (0, _1_misc_js_1.mustPrompt)("Password:") };
|
|
382
405
|
}
|
|
383
406
|
}
|
|
384
407
|
dAuth("authorizing with %s", typeof params === "string" ? "bot token" : params instanceof types.AuthExportedAuthorization ? "exported authorization" : "AuthorizeUserParams");
|
|
@@ -538,7 +561,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
538
561
|
await this.authorize(params);
|
|
539
562
|
}
|
|
540
563
|
async receiveLoop() {
|
|
541
|
-
if (!this.auth) {
|
|
564
|
+
if (!this.auth || !this.transport) {
|
|
542
565
|
throw new Error("Not connected");
|
|
543
566
|
}
|
|
544
567
|
while (this.connected) {
|
|
@@ -547,7 +570,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
547
570
|
await this.send(new types.MsgsAck({ msgIds: [...this.toAcknowledge] }));
|
|
548
571
|
this.toAcknowledge.clear();
|
|
549
572
|
}
|
|
550
|
-
const buffer = await this.transport.receive();
|
|
573
|
+
const buffer = await this.transport.transport.receive();
|
|
551
574
|
let decrypted;
|
|
552
575
|
try {
|
|
553
576
|
decrypted = await ((0, _0_message_js_1.decryptMessage)(buffer, this.auth.key, this.auth.id, this.sessionId));
|
|
@@ -564,8 +587,8 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
564
587
|
body = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(body.packedData)).readObject();
|
|
565
588
|
}
|
|
566
589
|
dRecv("received %s", body.constructor.name);
|
|
567
|
-
if (body instanceof types.
|
|
568
|
-
(
|
|
590
|
+
if (body instanceof types.TypeUpdates || body instanceof types.TypeUpdate) {
|
|
591
|
+
this.processUpdatesQueue.add(() => this.processUpdates(body));
|
|
569
592
|
}
|
|
570
593
|
else if (message.body instanceof _5_rpc_result_js_1.RPCResult) {
|
|
571
594
|
let result = message.body.result;
|
|
@@ -592,7 +615,10 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
592
615
|
}
|
|
593
616
|
};
|
|
594
617
|
if (result instanceof types.TypeUpdates || result instanceof types.TypeUpdate) {
|
|
595
|
-
this.
|
|
618
|
+
this.processUpdatesQueue.add(async () => {
|
|
619
|
+
await this.processUpdates(result);
|
|
620
|
+
resolvePromise();
|
|
621
|
+
});
|
|
596
622
|
}
|
|
597
623
|
else {
|
|
598
624
|
await this.processResult(result);
|
|
@@ -622,6 +648,10 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
622
648
|
if (!this.connected) {
|
|
623
649
|
break;
|
|
624
650
|
}
|
|
651
|
+
else if (err instanceof _0_tl_raw_reader_js_1.TLError) {
|
|
652
|
+
dRecv("failed to deserialize: %o", err);
|
|
653
|
+
(0, _1_misc_js_1.drop)(this.recoverUpdateGap("deserialize"));
|
|
654
|
+
}
|
|
625
655
|
else {
|
|
626
656
|
throw err;
|
|
627
657
|
}
|
|
@@ -640,7 +670,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
640
670
|
}
|
|
641
671
|
}
|
|
642
672
|
async invoke(function_, noWait) {
|
|
643
|
-
if (!this.auth) {
|
|
673
|
+
if (!this.auth || !this.transport) {
|
|
644
674
|
if (this.autoStart && !this.autoStarted) {
|
|
645
675
|
await this.start();
|
|
646
676
|
}
|
|
@@ -648,7 +678,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
648
678
|
throw new Error("Not connected");
|
|
649
679
|
}
|
|
650
680
|
}
|
|
651
|
-
if (!this.auth) {
|
|
681
|
+
if (!this.auth || !this.transport) {
|
|
652
682
|
(0, _0_control_js_1.UNREACHABLE)();
|
|
653
683
|
}
|
|
654
684
|
let seqNo = this.state.seqNo * 2;
|
|
@@ -658,7 +688,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
658
688
|
}
|
|
659
689
|
const messageId = this.lastMsgId = (0, _0_message_js_1.getMessageId)(this.lastMsgId);
|
|
660
690
|
const message = new _6_message_js_1.Message(messageId, seqNo, function_);
|
|
661
|
-
await this.transport.send(await (0, _0_message_js_1.encryptMessage)(message, this.auth.key, this.auth.id, this.state.salt, this.sessionId));
|
|
691
|
+
await this.transport.transport.send(await (0, _0_message_js_1.encryptMessage)(message, this.auth.key, this.auth.id, this.state.salt, this.sessionId));
|
|
662
692
|
d("invoked %s", function_.constructor.name);
|
|
663
693
|
if (noWait) {
|
|
664
694
|
return;
|
|
@@ -710,222 +740,160 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
710
740
|
}
|
|
711
741
|
}
|
|
712
742
|
}
|
|
713
|
-
async
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
if (
|
|
717
|
-
(
|
|
718
|
-
(update instanceof types.UpdateReadHistoryInbox) ||
|
|
719
|
-
(update instanceof types.UpdateReadHistoryOutbox) ||
|
|
720
|
-
(update instanceof types.UpdateWebPage) ||
|
|
721
|
-
(update instanceof types.UpdateReadMessagesContents) ||
|
|
722
|
-
(update instanceof types.UpdateEditMessage) ||
|
|
723
|
-
(update instanceof types.UpdateFolderPeers) ||
|
|
724
|
-
(update instanceof types.UpdatePinnedMessages) ||
|
|
725
|
-
(update instanceof types.UpdatePinnedChannelMessages) ||
|
|
726
|
-
(update instanceof types.UpdateShortMessage) ||
|
|
727
|
-
(update instanceof types.UpdateShortChatMessage) ||
|
|
728
|
-
(update instanceof types.UpdateShortSentMessage)) {
|
|
729
|
-
if (update.pts != 0 && update.ptsCount != 0) {
|
|
730
|
-
const localState = await this.getLocalState();
|
|
731
|
-
if (localState.pts + update.ptsCount > update.pts) {
|
|
732
|
-
// the update is already applied
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
else if (localState.pts + update.ptsCount < update.pts) {
|
|
736
|
-
// there is an update gap that needs to be filled
|
|
737
|
-
throw UPDATE_GAP;
|
|
738
|
-
}
|
|
739
|
-
localState.pts = update.pts;
|
|
740
|
-
d("applied update with pts %d", update.pts);
|
|
741
|
-
await this.storage.setState(localState);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
else if (usePts &&
|
|
745
|
-
((update instanceof types.UpdateNewChannelMessage) ||
|
|
746
|
-
(update instanceof types.UpdateDeleteChannelMessages) ||
|
|
747
|
-
(update instanceof types.UpdateEditChannelMessage) ||
|
|
748
|
-
(update instanceof types.UpdateChannelWebPage))) {
|
|
749
|
-
const channelId = update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateEditChannelMessage ? update.message.peerId[_1_tl_object_js_1.as](types.PeerChannel).channelId : update.channelId;
|
|
750
|
-
let localPts = await this.storage.getChannelPts(channelId);
|
|
751
|
-
if (!localPts) {
|
|
752
|
-
localPts = update.pts - update.ptsCount;
|
|
753
|
-
}
|
|
754
|
-
if (localPts + update.ptsCount > update.pts) {
|
|
755
|
-
// already applied
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
else if (localPts + update.ptsCount < update.pts) {
|
|
759
|
-
// should call channelGetDifference
|
|
760
|
-
throw UPDATE_GAP;
|
|
761
|
-
}
|
|
762
|
-
d("applied update with pts %d", update.pts);
|
|
763
|
-
await this.storage.setChannelPts(channelId, update.pts);
|
|
743
|
+
async checkGap(pts, ptsCount, assertNoGap) {
|
|
744
|
+
const localState = await this.getLocalState();
|
|
745
|
+
if (localState.pts + ptsCount < pts) {
|
|
746
|
+
if (assertNoGap) {
|
|
747
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
764
748
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
await this.storage.setMessage((0, _0_utilities_js_1.peerToChatId)(update.message.peerId), update.message.id, update.message);
|
|
768
|
-
}
|
|
749
|
+
else {
|
|
750
|
+
await this.recoverUpdateGap("processUpdates");
|
|
769
751
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
async checkChannelGap(channelId, pts, ptsCount, assertNoGap) {
|
|
755
|
+
let localPts = await this.storage.getChannelPts(channelId);
|
|
756
|
+
if (!localPts) {
|
|
757
|
+
localPts = pts - ptsCount;
|
|
758
|
+
}
|
|
759
|
+
if (localPts + ptsCount < pts) {
|
|
760
|
+
if (assertNoGap) {
|
|
761
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
774
762
|
}
|
|
775
|
-
else
|
|
776
|
-
|
|
777
|
-
const chatId = await this.storage.getMessageChat(message);
|
|
778
|
-
if (chatId) {
|
|
779
|
-
await this.storage.setMessage(chatId, message, null);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
763
|
+
else {
|
|
764
|
+
await this.recoverChannelUpdateGap(channelId, "processUpdates");
|
|
782
765
|
}
|
|
783
|
-
// apply update (call listeners)
|
|
784
|
-
this.updateHandler?.(this, update);
|
|
785
|
-
}
|
|
786
|
-
finally {
|
|
787
|
-
release();
|
|
788
766
|
}
|
|
789
767
|
}
|
|
790
|
-
async
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
768
|
+
async processUpdates(updates_, assertNoGap = false) {
|
|
769
|
+
/// First, individual updates (Update[1]) and updateShort* are extracted from Updates.[2]
|
|
770
|
+
///
|
|
771
|
+
/// If an updatesTooLong[3] was received, an update gap recovery is initiated and no further action will be taken.
|
|
772
|
+
///
|
|
773
|
+
/// [1]: https://core.telegram.org/type/Update
|
|
774
|
+
/// [2]: https://core.telegram.org/type/Updates
|
|
775
|
+
/// [3]: https://core.telegram.org/constructor/updatesTooLong
|
|
776
|
+
let updates;
|
|
777
|
+
if (updates_ instanceof types.UpdatesCombined || updates_ instanceof types.Updates) {
|
|
778
|
+
updates = updates_.updates;
|
|
779
|
+
}
|
|
780
|
+
else if (updates_ instanceof types.UpdateShort) {
|
|
781
|
+
updates = [updates_.update];
|
|
782
|
+
}
|
|
783
|
+
else if (updates_ instanceof types.UpdateShortMessage ||
|
|
784
|
+
updates_ instanceof types.UpdateShortChatMessage ||
|
|
785
|
+
updates_ instanceof types.UpdateShortSentMessage) {
|
|
786
|
+
updates = [updates_];
|
|
787
|
+
}
|
|
788
|
+
else if (updates_ instanceof types.UpdatesTooLong) {
|
|
789
|
+
await this.recoverUpdateGap("updatesTooLong");
|
|
790
|
+
return;
|
|
797
791
|
}
|
|
798
|
-
if (
|
|
799
|
-
|
|
800
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
792
|
+
else if (updates_ instanceof types.TypeUpdate) {
|
|
793
|
+
updates = [updates_];
|
|
801
794
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
try {
|
|
805
|
-
await this.applyUpdateNoGap(update);
|
|
806
|
-
release();
|
|
795
|
+
else {
|
|
796
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
807
797
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
798
|
+
/// Then, we go through each Update and updateShort*, and see if they are order-sensitive.
|
|
799
|
+
/// If they were, we check the local state to see if it is OK to process them right away.
|
|
800
|
+
///
|
|
801
|
+
/// If we there was a gap, a recovery process will be initiated and the processing will be postponed.
|
|
802
|
+
let localState = null;
|
|
803
|
+
let originalPts = null;
|
|
804
|
+
const channelPtsMap = new Map();
|
|
805
|
+
for (const update of updates) {
|
|
806
|
+
if ((0, _0_utilities_js_1.hasPts)(update)) {
|
|
807
|
+
if (update.pts == 0) {
|
|
808
|
+
continue;
|
|
817
809
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
(update instanceof types.UpdateReadMessagesContents) ||
|
|
824
|
-
(update instanceof types.UpdateEditMessage) ||
|
|
825
|
-
(update instanceof types.UpdateFolderPeers) ||
|
|
826
|
-
(update instanceof types.UpdatePinnedMessages) ||
|
|
827
|
-
(update instanceof types.UpdatePinnedChannelMessages) ||
|
|
828
|
-
(update instanceof types.UpdateShortMessage) ||
|
|
829
|
-
(update instanceof types.UpdateShortChatMessage) ||
|
|
830
|
-
(update instanceof types.UpdateShortSentMessage)) {
|
|
831
|
-
await this.recoverUpdateGap("applyUpdate");
|
|
810
|
+
await this.checkGap(update.pts, update.ptsCount, assertNoGap);
|
|
811
|
+
localState ??= await this.getLocalState();
|
|
812
|
+
originalPts ??= localState.pts;
|
|
813
|
+
if (localState.pts + update.ptsCount > update.pts) {
|
|
814
|
+
updates = updates.filter((v) => v != update);
|
|
832
815
|
}
|
|
833
816
|
else {
|
|
834
|
-
|
|
835
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
817
|
+
localState.pts = update.pts;
|
|
836
818
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
819
|
+
}
|
|
820
|
+
else if ((0, _0_utilities_js_1.hasChannelPts)(update)) {
|
|
821
|
+
if (update.pts == 0) {
|
|
822
|
+
continue;
|
|
841
823
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
824
|
+
const ptsCount = "ptsCount" in update ? update.ptsCount : 1;
|
|
825
|
+
const channelId = update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateEditChannelMessage ? update.message.peerId[_1_tl_object_js_1.as](types.PeerChannel).channelId : update.channelId;
|
|
826
|
+
await this.checkChannelGap(channelId, update.pts, ptsCount, assertNoGap);
|
|
827
|
+
let currentPts = channelPtsMap.get(channelId);
|
|
828
|
+
if (currentPts === undefined) {
|
|
829
|
+
currentPts = await this.storage.getChannelPts(channelId);
|
|
830
|
+
}
|
|
831
|
+
currentPts ??= update.pts;
|
|
832
|
+
if (currentPts + ptsCount > update.pts) {
|
|
833
|
+
updates = updates.filter((v) => v != update);
|
|
850
834
|
}
|
|
851
|
-
|
|
852
|
-
|
|
835
|
+
else {
|
|
836
|
+
channelPtsMap.set(channelId, update.pts);
|
|
853
837
|
}
|
|
854
838
|
}
|
|
855
|
-
|
|
856
|
-
|
|
839
|
+
}
|
|
840
|
+
if (!assertNoGap) {
|
|
841
|
+
if (localState != null && originalPts != null && localState.pts != originalPts) {
|
|
842
|
+
await this.storage.setState(localState);
|
|
843
|
+
}
|
|
844
|
+
for (const [channelId, pts] of channelPtsMap.entries()) {
|
|
845
|
+
await this.storage.setChannelPts(channelId, pts);
|
|
857
846
|
}
|
|
858
847
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
updates instanceof types.UpdateShortSentMessage) {
|
|
875
|
-
await this.setUpdateStateDate(updates.date);
|
|
876
|
-
await this.applyUpdate(updates);
|
|
877
|
-
}
|
|
878
|
-
else if (updates instanceof types.UpdatesTooLong) {
|
|
879
|
-
await this.recoverUpdateGap("updatesTooLong");
|
|
880
|
-
}
|
|
881
|
-
else if (updates instanceof types.UpdatesCombined) {
|
|
882
|
-
await this.setUpdateStateDate(updates.date);
|
|
883
|
-
await this.processChats(updates.chats);
|
|
884
|
-
await this.processUsers(updates.users);
|
|
885
|
-
for (const update of updates.updates) {
|
|
886
|
-
await this.processUpdates(update, release);
|
|
887
|
-
}
|
|
888
|
-
}
|
|
848
|
+
/// We process the updates when we are sure there is no gap.
|
|
849
|
+
if (updates_ instanceof types.Updates || updates_ instanceof types.UpdatesCombined) {
|
|
850
|
+
await this.processChats(updates_.chats);
|
|
851
|
+
await this.processUsers(updates_.users);
|
|
852
|
+
await this.setUpdateStateDate(updates_.date);
|
|
853
|
+
}
|
|
854
|
+
else if (updates_ instanceof types.UpdateShort) {
|
|
855
|
+
await this.setUpdateStateDate(updates_.date);
|
|
856
|
+
}
|
|
857
|
+
const updatesToHandle = new Array();
|
|
858
|
+
for (const update of updates) {
|
|
859
|
+
if (update instanceof types.UpdateShortMessage ||
|
|
860
|
+
update instanceof types.UpdateShortChatMessage ||
|
|
861
|
+
update instanceof types.UpdateShortSentMessage) {
|
|
862
|
+
await this.setUpdateStateDate(update.date);
|
|
889
863
|
}
|
|
890
|
-
else if (
|
|
891
|
-
if (
|
|
892
|
-
await this.storage.setChannelPts(
|
|
864
|
+
else if (update instanceof types.UpdateChannelTooLong) {
|
|
865
|
+
if (update.pts != undefined) {
|
|
866
|
+
await this.storage.setChannelPts(update.channelId, update.pts);
|
|
893
867
|
}
|
|
894
|
-
await this.recoverChannelUpdateGap(
|
|
868
|
+
await this.recoverChannelUpdateGap(update.channelId, "updateChannelTooLong");
|
|
895
869
|
}
|
|
896
|
-
else {
|
|
897
|
-
|
|
898
|
-
|
|
870
|
+
else if (update instanceof types.UpdateUserName) {
|
|
871
|
+
await this.storage.updateUsernames("user", update.userId, update.usernames.map((v) => v[_1_tl_object_js_1.as](types.Username)).map((v) => v.username));
|
|
872
|
+
}
|
|
873
|
+
else if (update instanceof types.UpdatePtsChanged) {
|
|
874
|
+
await this.fetchState("updatePtsChanged");
|
|
875
|
+
if (this.updateState) {
|
|
876
|
+
await this.storage.setState(this.updateState);
|
|
899
877
|
}
|
|
900
|
-
else
|
|
901
|
-
|
|
902
|
-
if (this.updateState) {
|
|
903
|
-
await this.storage.setState(this.updateState);
|
|
904
|
-
}
|
|
905
|
-
else {
|
|
906
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
907
|
-
}
|
|
878
|
+
else {
|
|
879
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
908
880
|
}
|
|
909
|
-
|
|
881
|
+
}
|
|
882
|
+
/// If there were any Update, they will be passed to the update handling queue.
|
|
883
|
+
if (update instanceof types.TypeUpdate) {
|
|
884
|
+
updatesToHandle.push(update);
|
|
910
885
|
}
|
|
911
886
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
}
|
|
887
|
+
this.handleUpdateQueue.add(async () => {
|
|
888
|
+
for (const update of updatesToHandle) {
|
|
889
|
+
await this.handleUpdate(update);
|
|
890
|
+
}
|
|
891
|
+
});
|
|
918
892
|
}
|
|
919
893
|
async setUpdateStateDate(date) {
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
localState.date = date;
|
|
924
|
-
await this.storage.setState(localState);
|
|
925
|
-
}
|
|
926
|
-
finally {
|
|
927
|
-
release();
|
|
928
|
-
}
|
|
894
|
+
const localState = await this.getLocalState();
|
|
895
|
+
localState.date = date;
|
|
896
|
+
await this.storage.setState(localState);
|
|
929
897
|
}
|
|
930
898
|
async getLocalState() {
|
|
931
899
|
let localState = await this.storage.getState();
|
|
@@ -949,7 +917,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
949
917
|
}
|
|
950
918
|
async recoverUpdateGap(source) {
|
|
951
919
|
dGap("recovering from update gap [%s]", source);
|
|
952
|
-
|
|
920
|
+
await this.propagateConnectionState("updating");
|
|
953
921
|
try {
|
|
954
922
|
let state = await this.getLocalState();
|
|
955
923
|
while (true) {
|
|
@@ -958,10 +926,10 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
958
926
|
await this.processChats(difference.chats);
|
|
959
927
|
await this.processUsers(difference.users);
|
|
960
928
|
for (const message of difference.newMessages) {
|
|
961
|
-
await this.
|
|
929
|
+
await this.processUpdates(new types.UpdateNewMessage({ message, pts: 0, ptsCount: 0 }), true);
|
|
962
930
|
}
|
|
963
931
|
for (const update of difference.otherUpdates) {
|
|
964
|
-
await this.
|
|
932
|
+
await this.processUpdates(update, true);
|
|
965
933
|
}
|
|
966
934
|
if (difference instanceof types.UpdatesDifference) {
|
|
967
935
|
await this.storage.setState(difference.state[_1_tl_object_js_1.as](types.UpdatesState));
|
|
@@ -976,6 +944,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
976
944
|
}
|
|
977
945
|
}
|
|
978
946
|
else if (difference instanceof types.UpdatesDifferenceTooLong) {
|
|
947
|
+
// TODO: we actually do now
|
|
979
948
|
// stored messages should be invalidated in case we store messages in the future
|
|
980
949
|
state.pts = difference.pts;
|
|
981
950
|
dGap("received differenceTooLong");
|
|
@@ -991,61 +960,55 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
991
960
|
}
|
|
992
961
|
}
|
|
993
962
|
finally {
|
|
994
|
-
|
|
963
|
+
this.stateChangeHandler(this.connected);
|
|
995
964
|
}
|
|
996
965
|
}
|
|
997
966
|
async recoverChannelUpdateGap(channelId, source) {
|
|
998
967
|
dGapC("recovering channel update gap [%o, %s]", channelId, source);
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
await this.
|
|
1014
|
-
for (const message of difference.newMessages) {
|
|
1015
|
-
await this.applyUpdateNoGap(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), false);
|
|
1016
|
-
}
|
|
1017
|
-
for (const update of difference.otherUpdates) {
|
|
1018
|
-
await this.applyUpdateNoGap(update, false);
|
|
1019
|
-
}
|
|
1020
|
-
await this.storage.setChannelPts(channelId, difference.pts);
|
|
1021
|
-
dGapC("recovered from update gap [%o, %s]", channelId, source);
|
|
1022
|
-
break;
|
|
968
|
+
const pts_ = await this.storage.getChannelPts(channelId);
|
|
969
|
+
let pts = pts_ == null ? 1 : pts_;
|
|
970
|
+
while (true) {
|
|
971
|
+
const { accessHash } = await this.getInputPeer(constants_js_1.ZERO_CHANNEL_ID + -Number(channelId)).then((v) => v[_1_tl_object_js_1.as](types.InputPeerChannel));
|
|
972
|
+
const difference = await this.invoke(new functions.UpdatesGetChannelDifference({
|
|
973
|
+
pts,
|
|
974
|
+
channel: new types.InputChannel({ channelId, accessHash: accessHash }),
|
|
975
|
+
filter: new types.ChannelMessagesFilterEmpty(),
|
|
976
|
+
limit: await this.storage.getAccountType() == "user" ? constants_js_1.CHANNEL_DIFFERENCE_LIMIT_USER : constants_js_1.CHANNEL_DIFFERENCE_LIMIT_BOT,
|
|
977
|
+
}));
|
|
978
|
+
if (difference instanceof types.UpdatesChannelDifference) {
|
|
979
|
+
await this.processChats(difference.chats);
|
|
980
|
+
await this.processUsers(difference.users);
|
|
981
|
+
for (const message of difference.newMessages) {
|
|
982
|
+
await this.processUpdates(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), true);
|
|
1023
983
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
dGapC("received channelDifferenceTooLong");
|
|
1027
|
-
await this.processChats(difference.chats);
|
|
1028
|
-
await this.processUsers(difference.users);
|
|
1029
|
-
for (const message of difference.messages) {
|
|
1030
|
-
await this.applyUpdateNoGap(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), false);
|
|
1031
|
-
}
|
|
1032
|
-
const pts_ = difference.dialog[_1_tl_object_js_1.as](types.Dialog).pts;
|
|
1033
|
-
if (pts_ != undefined) {
|
|
1034
|
-
pts = pts_;
|
|
1035
|
-
}
|
|
1036
|
-
else {
|
|
1037
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
1038
|
-
}
|
|
1039
|
-
dGapC("processed channelDifferenceTooLong");
|
|
984
|
+
for (const update of difference.otherUpdates) {
|
|
985
|
+
await this.processUpdates(update, true);
|
|
1040
986
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
987
|
+
await this.storage.setChannelPts(channelId, difference.pts);
|
|
988
|
+
dGapC("recovered from update gap [%o, %s]", channelId, source);
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
991
|
+
else if (difference instanceof types.UpdatesChannelDifferenceTooLong) {
|
|
992
|
+
// invalidate messages
|
|
993
|
+
dGapC("received channelDifferenceTooLong");
|
|
994
|
+
await this.processChats(difference.chats);
|
|
995
|
+
await this.processUsers(difference.users);
|
|
996
|
+
for (const message of difference.messages) {
|
|
997
|
+
await this.processUpdates(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), true);
|
|
998
|
+
}
|
|
999
|
+
const pts_ = difference.dialog[_1_tl_object_js_1.as](types.Dialog).pts;
|
|
1000
|
+
if (pts_ != undefined) {
|
|
1001
|
+
pts = pts_;
|
|
1044
1002
|
}
|
|
1003
|
+
else {
|
|
1004
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
1005
|
+
}
|
|
1006
|
+
dGapC("processed channelDifferenceTooLong");
|
|
1007
|
+
}
|
|
1008
|
+
else if (difference instanceof types.UpdatesChannelDifferenceEmpty) {
|
|
1009
|
+
dGapC("there was no update gap");
|
|
1010
|
+
break;
|
|
1045
1011
|
}
|
|
1046
|
-
}
|
|
1047
|
-
finally {
|
|
1048
|
-
release();
|
|
1049
1012
|
}
|
|
1050
1013
|
}
|
|
1051
1014
|
async getInputPeer(id) {
|
|
@@ -1362,7 +1325,8 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
1362
1325
|
langPack: this.langPack,
|
|
1363
1326
|
systemLangCode: this.systemLangCode,
|
|
1364
1327
|
systemVersion: this.systemVersion,
|
|
1365
|
-
|
|
1328
|
+
cdn: true,
|
|
1329
|
+
});
|
|
1366
1330
|
let dc = String(dcId);
|
|
1367
1331
|
if (this.dcId < 0) {
|
|
1368
1332
|
dc += "-test";
|
|
@@ -1473,5 +1437,69 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
1473
1437
|
}
|
|
1474
1438
|
return (0, _1_user_js_1.constructUser)(users[0][_1_tl_object_js_1.as](types.User));
|
|
1475
1439
|
}
|
|
1440
|
+
async handleUpdate(update) {
|
|
1441
|
+
if (update instanceof types.UpdateNewMessage || update instanceof types.UpdateNewMessage || update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateNewChannelMessage) {
|
|
1442
|
+
if (update.message instanceof types.Message || update.message instanceof types.MessageService) {
|
|
1443
|
+
await this.storage.setMessage((0, _0_utilities_js_1.peerToChatId)(update.message.peerId), update.message.id, update.message);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
else if (update instanceof types.UpdateDeleteChannelMessages) {
|
|
1447
|
+
for (const message of update.messages) {
|
|
1448
|
+
await this.storage.setMessage((0, _0_utilities_js_1.getChannelChatId)(update.channelId), message, null);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
else if (update instanceof types.UpdateDeleteMessages) {
|
|
1452
|
+
for (const message of update.messages) {
|
|
1453
|
+
const chatId = await this.storage.getMessageChat(message);
|
|
1454
|
+
if (chatId) {
|
|
1455
|
+
await this.storage.setMessage(chatId, message, null);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
if (update instanceof types.UpdateNewMessage ||
|
|
1460
|
+
update instanceof types.UpdateNewChannelMessage ||
|
|
1461
|
+
update instanceof types.UpdateEditMessage ||
|
|
1462
|
+
update instanceof types.UpdateEditChannelMessage) {
|
|
1463
|
+
const key = update instanceof types.UpdateNewMessage || update instanceof types.UpdateNewChannelMessage ? "message" : "editedMessage";
|
|
1464
|
+
const message = await (0, _3_message_js_1.constructMessage)(update.message, this[exports.getEntity].bind(this), this.getMessage.bind(this), this[exports.getStickerSetName].bind(this));
|
|
1465
|
+
await this.handler({ [key]: message }, resolve);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
use(middleware) {
|
|
1469
|
+
const handler = this.handler;
|
|
1470
|
+
this.handler = async (upd, next) => {
|
|
1471
|
+
let called = false;
|
|
1472
|
+
await middleware(upd, async () => {
|
|
1473
|
+
if (called)
|
|
1474
|
+
return;
|
|
1475
|
+
called = true;
|
|
1476
|
+
await handler(upd, next);
|
|
1477
|
+
});
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
on(filter, handler) {
|
|
1481
|
+
const type = typeof filter === "string" ? filter : filter[0];
|
|
1482
|
+
const keys = Array.isArray(filter) ? filter.slice(1) : [];
|
|
1483
|
+
this.use((update, next) => {
|
|
1484
|
+
if (type in update) {
|
|
1485
|
+
if (keys.length > 0) {
|
|
1486
|
+
for (const key of keys) {
|
|
1487
|
+
// deno-lint-ignore ban-ts-comment
|
|
1488
|
+
// @ts-ignore
|
|
1489
|
+
if (!(key in update[type])) {
|
|
1490
|
+
return next();
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
// deno-lint-ignore ban-ts-comment
|
|
1495
|
+
// @ts-ignore
|
|
1496
|
+
return handler(update, next);
|
|
1497
|
+
}
|
|
1498
|
+
else {
|
|
1499
|
+
return next();
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1476
1503
|
}
|
|
1477
1504
|
exports.Client = Client;
|
|
1505
|
+
const resolve = () => Promise.resolve();
|