@imessaging/telegram-mtproto 0.8.20 → 0.8.21
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imessaging/telegram-mtproto",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.21",
|
|
4
4
|
"description": "Telegram MTProto user-account transport for imessaging",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"messaging",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"test": "bun test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@imessaging/core": "^0.8.
|
|
34
|
+
"@imessaging/core": "^0.8.17",
|
|
35
35
|
"big-integer": "^1.6.52"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
PhoneLookupOptions,
|
|
7
7
|
PhoneLookupTransport,
|
|
8
8
|
PhoneMatch,
|
|
9
|
+
DraftReaderTransport,
|
|
9
10
|
DraftTransport,
|
|
10
11
|
MessageDraft,
|
|
11
12
|
OutgoingObserverTransport,
|
|
@@ -34,6 +35,7 @@ import type {
|
|
|
34
35
|
OutboundDocument,
|
|
35
36
|
SendResult,
|
|
36
37
|
SentPart,
|
|
38
|
+
StoredDraft,
|
|
37
39
|
TelegramPeerStore,
|
|
38
40
|
TelegramRecipient,
|
|
39
41
|
TransportStatus,
|
|
@@ -164,6 +166,7 @@ export class TelegramMtprotoTransport
|
|
|
164
166
|
implements
|
|
165
167
|
CommandMenuTransport,
|
|
166
168
|
ContactTransport,
|
|
169
|
+
DraftReaderTransport,
|
|
167
170
|
DraftTransport,
|
|
168
171
|
EditableMessageTransport,
|
|
169
172
|
EditedMessageTransport,
|
|
@@ -445,15 +448,60 @@ export class TelegramMtprotoTransport
|
|
|
445
448
|
: {}),
|
|
446
449
|
}),
|
|
447
450
|
);
|
|
451
|
+
await this.withPeerRetry(draft.recipient, save);
|
|
452
|
+
this.lastActivityAt = new Date();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Черновик в поле ввода — перед saveDraft, чтобы не затереть набранное человеком. Тема форума хранит свой
|
|
457
|
+
* черновик в ForumTopic, общий чат — в Dialog. undefined — черновика нет.
|
|
458
|
+
*/
|
|
459
|
+
async readDraft(
|
|
460
|
+
recipient: MessageRecipient,
|
|
461
|
+
options: { threadId?: number } = {},
|
|
462
|
+
): Promise<StoredDraft | undefined> {
|
|
463
|
+
this.assertConnected();
|
|
464
|
+
if (!isTelegramRecipient(recipient)) {
|
|
465
|
+
throw new Error(`Telegram MTProto cannot read a draft for ${recipient.type}`);
|
|
466
|
+
}
|
|
467
|
+
const { threadId } = options;
|
|
468
|
+
if (threadId !== undefined && (!Number.isSafeInteger(threadId) || threadId <= 0)) {
|
|
469
|
+
throw new Error(`Telegram thread id must be a positive integer: ${threadId}`);
|
|
470
|
+
}
|
|
471
|
+
const read = async (peer: Api.TypeInputPeer): Promise<Api.TypeDraftMessage | undefined> => {
|
|
472
|
+
if (threadId !== undefined) {
|
|
473
|
+
const result = await this.client.invoke(
|
|
474
|
+
new Api.messages.GetForumTopicsByID({ peer, topics: [threadId] }),
|
|
475
|
+
);
|
|
476
|
+
const topic = result.topics.find(
|
|
477
|
+
(t): t is Api.ForumTopic => t instanceof Api.ForumTopic && t.id === threadId,
|
|
478
|
+
);
|
|
479
|
+
// Нет темы — не «пустое поле»: иначе черновик ушёл бы в General поверх набранного там.
|
|
480
|
+
if (!topic) throw new Error(`Telegram forum topic not found: ${threadId}`);
|
|
481
|
+
return topic.draft;
|
|
482
|
+
}
|
|
483
|
+
// InputPeer, а не InputDialogPeer: клиент при отправке сам оборачивает пир (_getInputDialog).
|
|
484
|
+
const result = await this.client.invoke(new Api.messages.GetPeerDialogs({ peers: [peer] }));
|
|
485
|
+
const dialog = result.dialogs.find((d): d is Api.Dialog => d instanceof Api.Dialog);
|
|
486
|
+
return dialog?.draft;
|
|
487
|
+
};
|
|
488
|
+
const draft = await this.withPeerRetry(recipient, read);
|
|
489
|
+
this.lastActivityAt = new Date();
|
|
490
|
+
return toStoredDraft(draft, threadId);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/** Как у send: устаревший пир из хранилища — забыть и разрешить заново, один раз. */
|
|
494
|
+
private async withPeerRetry<T>(
|
|
495
|
+
recipient: MessageRecipient,
|
|
496
|
+
call: (peer: Api.TypeInputPeer) => Promise<T>,
|
|
497
|
+
): Promise<T> {
|
|
448
498
|
try {
|
|
449
|
-
await
|
|
499
|
+
return await call(await this.getInputPeer(recipient));
|
|
450
500
|
} catch (error: unknown) {
|
|
451
|
-
// Как у send: устаревший пир из хранилища — забыть и разрешить заново, один раз.
|
|
452
501
|
if (!this.isInvalidPeerError(error)) throw error;
|
|
453
|
-
await this.peerStore.delete(this.options.accountId,
|
|
454
|
-
|
|
502
|
+
await this.peerStore.delete(this.options.accountId, recipient);
|
|
503
|
+
return call(await this.getInputPeer(recipient));
|
|
455
504
|
}
|
|
456
|
-
this.lastActivityAt = new Date();
|
|
457
505
|
}
|
|
458
506
|
|
|
459
507
|
/** Свои новые исходящие — отправленное человеком с другого устройства; отправленное через send помечено sentByTransport. */
|
|
@@ -1263,6 +1311,29 @@ export class TelegramMtprotoTransport
|
|
|
1263
1311
|
}
|
|
1264
1312
|
}
|
|
1265
1313
|
|
|
1314
|
+
/**
|
|
1315
|
+
* DraftMessage → StoredDraft. В теме saveDraft без ответа ставит ответ на корень темы — это не ответ человеку.
|
|
1316
|
+
*/
|
|
1317
|
+
function toStoredDraft(
|
|
1318
|
+
draft: Api.TypeDraftMessage | undefined,
|
|
1319
|
+
threadId?: number,
|
|
1320
|
+
): StoredDraft | undefined {
|
|
1321
|
+
if (!(draft instanceof Api.DraftMessage)) return undefined;
|
|
1322
|
+
const r = draft.replyTo instanceof Api.InputReplyToMessage ? draft.replyTo : undefined;
|
|
1323
|
+
// Ответ в другой чат (replyToPeerId) — чужой id сообщения, здесь он не годится.
|
|
1324
|
+
const replyTo = r && !r.replyToPeerId ? r.replyToMsgId : undefined;
|
|
1325
|
+
const reply = replyTo !== undefined && replyTo !== threadId ? String(replyTo) : undefined;
|
|
1326
|
+
// Очистка в теме оставляет только ответ на корень. Что-то кроме этого (медиа, чужой ответ) — черновик есть.
|
|
1327
|
+
const onlyRoot =
|
|
1328
|
+
!draft.replyTo || (r !== undefined && !r.replyToPeerId && r.replyToMsgId === threadId);
|
|
1329
|
+
if (draft.message === "" && onlyRoot && !draft.media && !draft.richMessage) return undefined;
|
|
1330
|
+
return {
|
|
1331
|
+
text: draft.message,
|
|
1332
|
+
...(reply !== undefined ? { replyToMessageId: reply } : {}),
|
|
1333
|
+
date: new Date(draft.date * 1000),
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1266
1337
|
/** Параллельных частей при загрузке: с одной 25 МБ идут по 512 КБ за круг. */
|
|
1267
1338
|
const UPLOAD_WORKERS = 4;
|
|
1268
1339
|
|