@mtkruto/node 0.0.986 → 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 +314 -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/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 +313 -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/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
|
@@ -53,12 +53,12 @@ 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
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");
|
|
56
57
|
const d = (0, deps_js_1.debug)("Client");
|
|
57
58
|
const dGap = (0, deps_js_1.debug)("Client/recoverUpdateGap");
|
|
58
59
|
const dGapC = (0, deps_js_1.debug)("Client/recoverChannelUpdateGap");
|
|
59
60
|
const dAuth = (0, deps_js_1.debug)("Client/authorize");
|
|
60
61
|
const dRecv = (0, deps_js_1.debug)("Client/receiveLoop");
|
|
61
|
-
const UPDATE_GAP = Symbol();
|
|
62
62
|
exports.getEntity = Symbol();
|
|
63
63
|
exports.getStickerSetName = Symbol();
|
|
64
64
|
exports.handleMigrationError = Symbol();
|
|
@@ -77,8 +77,8 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
77
77
|
* @param apiHash App's API hash from [my.telegram.org/apps](https://my.telegram.org/apps). Defaults to empty string (unset).
|
|
78
78
|
* @param params Other parameters.
|
|
79
79
|
*/
|
|
80
|
-
constructor(storage = new _1_storage_memory_js_1.StorageMemory(), apiId = 0, apiHash = "", params
|
|
81
|
-
super(params
|
|
80
|
+
constructor(storage = new _1_storage_memory_js_1.StorageMemory(), apiId = 0, apiHash = "", params) {
|
|
81
|
+
super(params);
|
|
82
82
|
Object.defineProperty(this, "storage", {
|
|
83
83
|
enumerable: true,
|
|
84
84
|
configurable: true,
|
|
@@ -133,12 +133,6 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
133
133
|
writable: true,
|
|
134
134
|
value: void 0
|
|
135
135
|
});
|
|
136
|
-
Object.defineProperty(this, "updateHandler", {
|
|
137
|
-
enumerable: true,
|
|
138
|
-
configurable: true,
|
|
139
|
-
writable: true,
|
|
140
|
-
value: null
|
|
141
|
-
});
|
|
142
136
|
Object.defineProperty(this, "parseMode", {
|
|
143
137
|
enumerable: true,
|
|
144
138
|
configurable: true,
|
|
@@ -193,12 +187,26 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
193
187
|
writable: true,
|
|
194
188
|
value: void 0
|
|
195
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
|
+
});
|
|
196
198
|
Object.defineProperty(this, "storageInited", {
|
|
197
199
|
enumerable: true,
|
|
198
200
|
configurable: true,
|
|
199
201
|
writable: true,
|
|
200
202
|
value: false
|
|
201
203
|
});
|
|
204
|
+
Object.defineProperty(this, "connectMutex", {
|
|
205
|
+
enumerable: true,
|
|
206
|
+
configurable: true,
|
|
207
|
+
writable: true,
|
|
208
|
+
value: new deps_js_1.Mutex()
|
|
209
|
+
});
|
|
202
210
|
Object.defineProperty(this, "connectionInited", {
|
|
203
211
|
enumerable: true,
|
|
204
212
|
configurable: true,
|
|
@@ -217,23 +225,25 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
217
225
|
writable: true,
|
|
218
226
|
value: 0n
|
|
219
227
|
});
|
|
220
|
-
Object.defineProperty(this, "
|
|
228
|
+
Object.defineProperty(this, "handleUpdateQueue", {
|
|
221
229
|
enumerable: true,
|
|
222
230
|
configurable: true,
|
|
223
231
|
writable: true,
|
|
224
|
-
value: new
|
|
232
|
+
value: new _0_queue_js_1.Queue()
|
|
225
233
|
});
|
|
226
|
-
Object.defineProperty(this, "
|
|
234
|
+
Object.defineProperty(this, "processUpdatesQueue", {
|
|
227
235
|
enumerable: true,
|
|
228
236
|
configurable: true,
|
|
229
237
|
writable: true,
|
|
230
|
-
value: new
|
|
238
|
+
value: new _0_queue_js_1.Queue()
|
|
231
239
|
});
|
|
232
|
-
Object.defineProperty(this, "
|
|
240
|
+
Object.defineProperty(this, "handler", {
|
|
233
241
|
enumerable: true,
|
|
234
242
|
configurable: true,
|
|
235
243
|
writable: true,
|
|
236
|
-
value:
|
|
244
|
+
value: (_upd, next) => {
|
|
245
|
+
next();
|
|
246
|
+
}
|
|
237
247
|
});
|
|
238
248
|
this.parseMode = params?.parseMode ?? ParseMode.None;
|
|
239
249
|
this.appVersion = params?.appVersion ?? constants_js_1.APP_VERSION;
|
|
@@ -245,6 +255,9 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
245
255
|
this.publicKeys = params?.publicKeys;
|
|
246
256
|
this.autoStart = params?.autoStart ?? true;
|
|
247
257
|
}
|
|
258
|
+
propagateConnectionState(connectionState) {
|
|
259
|
+
return this.handler({ connectionState }, resolve);
|
|
260
|
+
}
|
|
248
261
|
/**
|
|
249
262
|
* Sets the DC and resets the auth key stored in the session provider
|
|
250
263
|
* if the stored DC was not the same as the `dc` parameter.
|
|
@@ -274,38 +287,47 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
274
287
|
* Before establishing the connection, the session is saved.
|
|
275
288
|
*/
|
|
276
289
|
async connect() {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
this.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
+
}
|
|
284
316
|
const dc = await this.storage.getDc();
|
|
285
317
|
if (dc != null) {
|
|
286
|
-
|
|
318
|
+
await this.setDc(dc);
|
|
287
319
|
}
|
|
288
|
-
await
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
this.
|
|
294
|
-
|
|
295
|
-
else {
|
|
296
|
-
await this.setAuth(authKey);
|
|
297
|
-
}
|
|
298
|
-
const dc = await this.storage.getDc();
|
|
299
|
-
if (dc != null) {
|
|
300
|
-
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());
|
|
301
327
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
await this.storage.setDc(this.transportProvider.initialDc);
|
|
328
|
+
finally {
|
|
329
|
+
release();
|
|
305
330
|
}
|
|
306
|
-
d("encrypted client connected");
|
|
307
|
-
(0, _1_misc_js_1.drop)(this.receiveLoop());
|
|
308
|
-
(0, _1_misc_js_1.drop)(this.pingLoop());
|
|
309
331
|
}
|
|
310
332
|
async fetchState(source) {
|
|
311
333
|
const state = await this.invoke(new functions.UpdatesGetState());
|
|
@@ -379,7 +401,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
379
401
|
params = (0, _1_misc_js_1.mustPrompt)("Bot token:");
|
|
380
402
|
}
|
|
381
403
|
else {
|
|
382
|
-
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:") };
|
|
383
405
|
}
|
|
384
406
|
}
|
|
385
407
|
dAuth("authorizing with %s", typeof params === "string" ? "bot token" : params instanceof types.AuthExportedAuthorization ? "exported authorization" : "AuthorizeUserParams");
|
|
@@ -539,7 +561,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
539
561
|
await this.authorize(params);
|
|
540
562
|
}
|
|
541
563
|
async receiveLoop() {
|
|
542
|
-
if (!this.auth) {
|
|
564
|
+
if (!this.auth || !this.transport) {
|
|
543
565
|
throw new Error("Not connected");
|
|
544
566
|
}
|
|
545
567
|
while (this.connected) {
|
|
@@ -548,7 +570,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
548
570
|
await this.send(new types.MsgsAck({ msgIds: [...this.toAcknowledge] }));
|
|
549
571
|
this.toAcknowledge.clear();
|
|
550
572
|
}
|
|
551
|
-
const buffer = await this.transport.receive();
|
|
573
|
+
const buffer = await this.transport.transport.receive();
|
|
552
574
|
let decrypted;
|
|
553
575
|
try {
|
|
554
576
|
decrypted = await ((0, _0_message_js_1.decryptMessage)(buffer, this.auth.key, this.auth.id, this.sessionId));
|
|
@@ -565,8 +587,8 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
565
587
|
body = new _3_tl_reader_js_1.TLReader((0, deps_js_1.gunzip)(body.packedData)).readObject();
|
|
566
588
|
}
|
|
567
589
|
dRecv("received %s", body.constructor.name);
|
|
568
|
-
if (body instanceof types.
|
|
569
|
-
(
|
|
590
|
+
if (body instanceof types.TypeUpdates || body instanceof types.TypeUpdate) {
|
|
591
|
+
this.processUpdatesQueue.add(() => this.processUpdates(body));
|
|
570
592
|
}
|
|
571
593
|
else if (message.body instanceof _5_rpc_result_js_1.RPCResult) {
|
|
572
594
|
let result = message.body.result;
|
|
@@ -593,7 +615,10 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
593
615
|
}
|
|
594
616
|
};
|
|
595
617
|
if (result instanceof types.TypeUpdates || result instanceof types.TypeUpdate) {
|
|
596
|
-
this.
|
|
618
|
+
this.processUpdatesQueue.add(async () => {
|
|
619
|
+
await this.processUpdates(result);
|
|
620
|
+
resolvePromise();
|
|
621
|
+
});
|
|
597
622
|
}
|
|
598
623
|
else {
|
|
599
624
|
await this.processResult(result);
|
|
@@ -645,7 +670,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
645
670
|
}
|
|
646
671
|
}
|
|
647
672
|
async invoke(function_, noWait) {
|
|
648
|
-
if (!this.auth) {
|
|
673
|
+
if (!this.auth || !this.transport) {
|
|
649
674
|
if (this.autoStart && !this.autoStarted) {
|
|
650
675
|
await this.start();
|
|
651
676
|
}
|
|
@@ -653,7 +678,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
653
678
|
throw new Error("Not connected");
|
|
654
679
|
}
|
|
655
680
|
}
|
|
656
|
-
if (!this.auth) {
|
|
681
|
+
if (!this.auth || !this.transport) {
|
|
657
682
|
(0, _0_control_js_1.UNREACHABLE)();
|
|
658
683
|
}
|
|
659
684
|
let seqNo = this.state.seqNo * 2;
|
|
@@ -663,7 +688,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
663
688
|
}
|
|
664
689
|
const messageId = this.lastMsgId = (0, _0_message_js_1.getMessageId)(this.lastMsgId);
|
|
665
690
|
const message = new _6_message_js_1.Message(messageId, seqNo, function_);
|
|
666
|
-
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));
|
|
667
692
|
d("invoked %s", function_.constructor.name);
|
|
668
693
|
if (noWait) {
|
|
669
694
|
return;
|
|
@@ -715,222 +740,160 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
715
740
|
}
|
|
716
741
|
}
|
|
717
742
|
}
|
|
718
|
-
async
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
if (
|
|
722
|
-
(
|
|
723
|
-
(update instanceof types.UpdateReadHistoryInbox) ||
|
|
724
|
-
(update instanceof types.UpdateReadHistoryOutbox) ||
|
|
725
|
-
(update instanceof types.UpdateWebPage) ||
|
|
726
|
-
(update instanceof types.UpdateReadMessagesContents) ||
|
|
727
|
-
(update instanceof types.UpdateEditMessage) ||
|
|
728
|
-
(update instanceof types.UpdateFolderPeers) ||
|
|
729
|
-
(update instanceof types.UpdatePinnedMessages) ||
|
|
730
|
-
(update instanceof types.UpdatePinnedChannelMessages) ||
|
|
731
|
-
(update instanceof types.UpdateShortMessage) ||
|
|
732
|
-
(update instanceof types.UpdateShortChatMessage) ||
|
|
733
|
-
(update instanceof types.UpdateShortSentMessage)) {
|
|
734
|
-
if (update.pts != 0 && update.ptsCount != 0) {
|
|
735
|
-
const localState = await this.getLocalState();
|
|
736
|
-
if (localState.pts + update.ptsCount > update.pts) {
|
|
737
|
-
// the update is already applied
|
|
738
|
-
return;
|
|
739
|
-
}
|
|
740
|
-
else if (localState.pts + update.ptsCount < update.pts) {
|
|
741
|
-
// there is an update gap that needs to be filled
|
|
742
|
-
throw UPDATE_GAP;
|
|
743
|
-
}
|
|
744
|
-
localState.pts = update.pts;
|
|
745
|
-
d("applied update with pts %d", update.pts);
|
|
746
|
-
await this.storage.setState(localState);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
else if (usePts &&
|
|
750
|
-
((update instanceof types.UpdateNewChannelMessage) ||
|
|
751
|
-
(update instanceof types.UpdateDeleteChannelMessages) ||
|
|
752
|
-
(update instanceof types.UpdateEditChannelMessage) ||
|
|
753
|
-
(update instanceof types.UpdateChannelWebPage))) {
|
|
754
|
-
const channelId = update instanceof types.UpdateNewChannelMessage || update instanceof types.UpdateEditChannelMessage ? update.message.peerId[_1_tl_object_js_1.as](types.PeerChannel).channelId : update.channelId;
|
|
755
|
-
let localPts = await this.storage.getChannelPts(channelId);
|
|
756
|
-
if (!localPts) {
|
|
757
|
-
localPts = update.pts - update.ptsCount;
|
|
758
|
-
}
|
|
759
|
-
if (localPts + update.ptsCount > update.pts) {
|
|
760
|
-
// already applied
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
else if (localPts + update.ptsCount < update.pts) {
|
|
764
|
-
// should call channelGetDifference
|
|
765
|
-
throw UPDATE_GAP;
|
|
766
|
-
}
|
|
767
|
-
d("applied update with pts %d", update.pts);
|
|
768
|
-
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)();
|
|
769
748
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
await this.storage.setMessage((0, _0_utilities_js_1.peerToChatId)(update.message.peerId), update.message.id, update.message);
|
|
773
|
-
}
|
|
749
|
+
else {
|
|
750
|
+
await this.recoverUpdateGap("processUpdates");
|
|
774
751
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
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)();
|
|
779
762
|
}
|
|
780
|
-
else
|
|
781
|
-
|
|
782
|
-
const chatId = await this.storage.getMessageChat(message);
|
|
783
|
-
if (chatId) {
|
|
784
|
-
await this.storage.setMessage(chatId, message, null);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
763
|
+
else {
|
|
764
|
+
await this.recoverChannelUpdateGap(channelId, "processUpdates");
|
|
787
765
|
}
|
|
788
|
-
// apply update (call listeners)
|
|
789
|
-
this.updateHandler?.(this, update);
|
|
790
|
-
}
|
|
791
|
-
finally {
|
|
792
|
-
release();
|
|
793
766
|
}
|
|
794
767
|
}
|
|
795
|
-
async
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
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;
|
|
802
791
|
}
|
|
803
|
-
if (
|
|
804
|
-
|
|
805
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
792
|
+
else if (updates_ instanceof types.TypeUpdate) {
|
|
793
|
+
updates = [updates_];
|
|
806
794
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
try {
|
|
810
|
-
await this.applyUpdateNoGap(update);
|
|
811
|
-
release();
|
|
795
|
+
else {
|
|
796
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
812
797
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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;
|
|
822
809
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
(update instanceof types.UpdateReadMessagesContents) ||
|
|
829
|
-
(update instanceof types.UpdateEditMessage) ||
|
|
830
|
-
(update instanceof types.UpdateFolderPeers) ||
|
|
831
|
-
(update instanceof types.UpdatePinnedMessages) ||
|
|
832
|
-
(update instanceof types.UpdatePinnedChannelMessages) ||
|
|
833
|
-
(update instanceof types.UpdateShortMessage) ||
|
|
834
|
-
(update instanceof types.UpdateShortChatMessage) ||
|
|
835
|
-
(update instanceof types.UpdateShortSentMessage)) {
|
|
836
|
-
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);
|
|
837
815
|
}
|
|
838
816
|
else {
|
|
839
|
-
|
|
840
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
817
|
+
localState.pts = update.pts;
|
|
841
818
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
819
|
+
}
|
|
820
|
+
else if ((0, _0_utilities_js_1.hasChannelPts)(update)) {
|
|
821
|
+
if (update.pts == 0) {
|
|
822
|
+
continue;
|
|
846
823
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
throw err;
|
|
854
|
-
}
|
|
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);
|
|
855
830
|
}
|
|
856
|
-
|
|
857
|
-
|
|
831
|
+
currentPts ??= update.pts;
|
|
832
|
+
if (currentPts + ptsCount > update.pts) {
|
|
833
|
+
updates = updates.filter((v) => v != update);
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
channelPtsMap.set(channelId, update.pts);
|
|
858
837
|
}
|
|
859
838
|
}
|
|
860
|
-
|
|
861
|
-
|
|
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);
|
|
862
846
|
}
|
|
863
847
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
updates instanceof types.UpdateShortSentMessage) {
|
|
880
|
-
await this.setUpdateStateDate(updates.date);
|
|
881
|
-
await this.applyUpdate(updates);
|
|
882
|
-
}
|
|
883
|
-
else if (updates instanceof types.UpdatesTooLong) {
|
|
884
|
-
await this.recoverUpdateGap("updatesTooLong");
|
|
885
|
-
}
|
|
886
|
-
else if (updates instanceof types.UpdatesCombined) {
|
|
887
|
-
await this.setUpdateStateDate(updates.date);
|
|
888
|
-
await this.processChats(updates.chats);
|
|
889
|
-
await this.processUsers(updates.users);
|
|
890
|
-
for (const update of updates.updates) {
|
|
891
|
-
await this.processUpdates(update, release);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
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);
|
|
894
863
|
}
|
|
895
|
-
else if (
|
|
896
|
-
if (
|
|
897
|
-
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);
|
|
898
867
|
}
|
|
899
|
-
await this.recoverChannelUpdateGap(
|
|
868
|
+
await this.recoverChannelUpdateGap(update.channelId, "updateChannelTooLong");
|
|
900
869
|
}
|
|
901
|
-
else {
|
|
902
|
-
|
|
903
|
-
|
|
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);
|
|
904
877
|
}
|
|
905
|
-
else
|
|
906
|
-
|
|
907
|
-
if (this.updateState) {
|
|
908
|
-
await this.storage.setState(this.updateState);
|
|
909
|
-
}
|
|
910
|
-
else {
|
|
911
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
912
|
-
}
|
|
878
|
+
else {
|
|
879
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
913
880
|
}
|
|
914
|
-
|
|
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);
|
|
915
885
|
}
|
|
916
886
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
}
|
|
887
|
+
this.handleUpdateQueue.add(async () => {
|
|
888
|
+
for (const update of updatesToHandle) {
|
|
889
|
+
await this.handleUpdate(update);
|
|
890
|
+
}
|
|
891
|
+
});
|
|
923
892
|
}
|
|
924
893
|
async setUpdateStateDate(date) {
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
localState.date = date;
|
|
929
|
-
await this.storage.setState(localState);
|
|
930
|
-
}
|
|
931
|
-
finally {
|
|
932
|
-
release();
|
|
933
|
-
}
|
|
894
|
+
const localState = await this.getLocalState();
|
|
895
|
+
localState.date = date;
|
|
896
|
+
await this.storage.setState(localState);
|
|
934
897
|
}
|
|
935
898
|
async getLocalState() {
|
|
936
899
|
let localState = await this.storage.getState();
|
|
@@ -954,7 +917,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
954
917
|
}
|
|
955
918
|
async recoverUpdateGap(source) {
|
|
956
919
|
dGap("recovering from update gap [%s]", source);
|
|
957
|
-
|
|
920
|
+
await this.propagateConnectionState("updating");
|
|
958
921
|
try {
|
|
959
922
|
let state = await this.getLocalState();
|
|
960
923
|
while (true) {
|
|
@@ -963,10 +926,10 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
963
926
|
await this.processChats(difference.chats);
|
|
964
927
|
await this.processUsers(difference.users);
|
|
965
928
|
for (const message of difference.newMessages) {
|
|
966
|
-
await this.
|
|
929
|
+
await this.processUpdates(new types.UpdateNewMessage({ message, pts: 0, ptsCount: 0 }), true);
|
|
967
930
|
}
|
|
968
931
|
for (const update of difference.otherUpdates) {
|
|
969
|
-
await this.
|
|
932
|
+
await this.processUpdates(update, true);
|
|
970
933
|
}
|
|
971
934
|
if (difference instanceof types.UpdatesDifference) {
|
|
972
935
|
await this.storage.setState(difference.state[_1_tl_object_js_1.as](types.UpdatesState));
|
|
@@ -981,6 +944,7 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
981
944
|
}
|
|
982
945
|
}
|
|
983
946
|
else if (difference instanceof types.UpdatesDifferenceTooLong) {
|
|
947
|
+
// TODO: we actually do now
|
|
984
948
|
// stored messages should be invalidated in case we store messages in the future
|
|
985
949
|
state.pts = difference.pts;
|
|
986
950
|
dGap("received differenceTooLong");
|
|
@@ -996,61 +960,55 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
996
960
|
}
|
|
997
961
|
}
|
|
998
962
|
finally {
|
|
999
|
-
|
|
963
|
+
this.stateChangeHandler(this.connected);
|
|
1000
964
|
}
|
|
1001
965
|
}
|
|
1002
966
|
async recoverChannelUpdateGap(channelId, source) {
|
|
1003
967
|
dGapC("recovering channel update gap [%o, %s]", channelId, source);
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
await this.
|
|
1019
|
-
for (const message of difference.newMessages) {
|
|
1020
|
-
await this.applyUpdateNoGap(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), false);
|
|
1021
|
-
}
|
|
1022
|
-
for (const update of difference.otherUpdates) {
|
|
1023
|
-
await this.applyUpdateNoGap(update, false);
|
|
1024
|
-
}
|
|
1025
|
-
await this.storage.setChannelPts(channelId, difference.pts);
|
|
1026
|
-
dGapC("recovered from update gap [%o, %s]", channelId, source);
|
|
1027
|
-
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);
|
|
1028
983
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
dGapC("received channelDifferenceTooLong");
|
|
1032
|
-
await this.processChats(difference.chats);
|
|
1033
|
-
await this.processUsers(difference.users);
|
|
1034
|
-
for (const message of difference.messages) {
|
|
1035
|
-
await this.applyUpdateNoGap(new types.UpdateNewChannelMessage({ message, pts: 0, ptsCount: 0 }), false);
|
|
1036
|
-
}
|
|
1037
|
-
const pts_ = difference.dialog[_1_tl_object_js_1.as](types.Dialog).pts;
|
|
1038
|
-
if (pts_ != undefined) {
|
|
1039
|
-
pts = pts_;
|
|
1040
|
-
}
|
|
1041
|
-
else {
|
|
1042
|
-
(0, _0_control_js_1.UNREACHABLE)();
|
|
1043
|
-
}
|
|
1044
|
-
dGapC("processed channelDifferenceTooLong");
|
|
984
|
+
for (const update of difference.otherUpdates) {
|
|
985
|
+
await this.processUpdates(update, true);
|
|
1045
986
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
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_;
|
|
1002
|
+
}
|
|
1003
|
+
else {
|
|
1004
|
+
(0, _0_control_js_1.UNREACHABLE)();
|
|
1049
1005
|
}
|
|
1006
|
+
dGapC("processed channelDifferenceTooLong");
|
|
1007
|
+
}
|
|
1008
|
+
else if (difference instanceof types.UpdatesChannelDifferenceEmpty) {
|
|
1009
|
+
dGapC("there was no update gap");
|
|
1010
|
+
break;
|
|
1050
1011
|
}
|
|
1051
|
-
}
|
|
1052
|
-
finally {
|
|
1053
|
-
release();
|
|
1054
1012
|
}
|
|
1055
1013
|
}
|
|
1056
1014
|
async getInputPeer(id) {
|
|
@@ -1367,7 +1325,8 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
1367
1325
|
langPack: this.langPack,
|
|
1368
1326
|
systemLangCode: this.systemLangCode,
|
|
1369
1327
|
systemVersion: this.systemVersion,
|
|
1370
|
-
|
|
1328
|
+
cdn: true,
|
|
1329
|
+
});
|
|
1371
1330
|
let dc = String(dcId);
|
|
1372
1331
|
if (this.dcId < 0) {
|
|
1373
1332
|
dc += "-test";
|
|
@@ -1478,5 +1437,69 @@ class Client extends _1_client_abstract_js_1.ClientAbstract {
|
|
|
1478
1437
|
}
|
|
1479
1438
|
return (0, _1_user_js_1.constructUser)(users[0][_1_tl_object_js_1.as](types.User));
|
|
1480
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
|
+
}
|
|
1481
1503
|
}
|
|
1482
1504
|
exports.Client = Client;
|
|
1505
|
+
const resolve = () => Promise.resolve();
|