@imessaging/telegram-mtproto 0.6.0 → 0.6.2
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 +1 -1
- package/src/incoming.ts +19 -0
- package/src/telegram-mtproto-transport.ts +38 -0
package/package.json
CHANGED
package/src/incoming.ts
CHANGED
|
@@ -18,6 +18,22 @@ export type MtprotoMessageLike = {
|
|
|
18
18
|
fromId?: MtprotoPeerLike;
|
|
19
19
|
media?: MtprotoMediaLike;
|
|
20
20
|
replyTo?: { replyToMsgId?: number | string };
|
|
21
|
+
/**
|
|
22
|
+
* Отправитель целиком — его приносит обновление вместе с `accessHash`.
|
|
23
|
+
*
|
|
24
|
+
* Нужен не ради имени: по одному номеру ответить нельзя, пока собеседник клиенту неизвестен, а
|
|
25
|
+
* `accessHash` живёт только здесь. Поле необязательное: в обновлении его может не быть.
|
|
26
|
+
*/
|
|
27
|
+
sender?: { username?: string; accessHash?: { toString(): string } | string | number };
|
|
28
|
+
/**
|
|
29
|
+
* Пир отправителя ВМЕСТЕ с `accessHash` — так его отдаёт само обновление.
|
|
30
|
+
*
|
|
31
|
+
* Без него ответить по одному номеру нельзя: клиент знает только тех, кого уже разрешал, а
|
|
32
|
+
* `accessHash` из обновления больше нигде не хранится.
|
|
33
|
+
*/
|
|
34
|
+
getInputSender?: () => Promise<{ userId?: { toString(): string }; accessHash?: { toString(): string } } | undefined>;
|
|
35
|
+
/** Отправитель целиком. Обращение к сущностям обновления, а не поход в сеть. */
|
|
36
|
+
getSender?: () => Promise<{ username?: string } | undefined>;
|
|
21
37
|
};
|
|
22
38
|
|
|
23
39
|
export type MtprotoMediaLike = {
|
|
@@ -110,6 +126,9 @@ export function toIncomingMessage(
|
|
|
110
126
|
chatId,
|
|
111
127
|
chatType,
|
|
112
128
|
senderId,
|
|
129
|
+
// Имя отправителя: по нему отвечают, когда номер клиенту неизвестен, и по нему же продукты
|
|
130
|
+
// связывают человека со своей учётной записью.
|
|
131
|
+
senderUsername: message.sender?.username,
|
|
113
132
|
messageId: String(message.id),
|
|
114
133
|
text: message.message ?? "",
|
|
115
134
|
attachments: collectAttachments(message, chatId),
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
TypingTransport,
|
|
18
18
|
} from "@imessaging/core";
|
|
19
19
|
import { isTelegramRecipient, MemoryPeerStore } from "@imessaging/core";
|
|
20
|
+
import { peerToChat } from "./incoming";
|
|
20
21
|
import bigInt from "big-integer";
|
|
21
22
|
import { Api, TelegramClient } from "telegram";
|
|
22
23
|
import { CustomFile } from "telegram/client/uploads";
|
|
@@ -167,12 +168,49 @@ export class TelegramMtprotoTransport
|
|
|
167
168
|
const message = (event as { message?: MtprotoMessageLike }).message;
|
|
168
169
|
if (!message) return;
|
|
169
170
|
this.lastActivityAt = new Date();
|
|
171
|
+
// Собеседника запоминаем СРАЗУ: ответить ему по одному номеру нельзя, `accessHash` приносит
|
|
172
|
+
// только это обновление, и к следующему ходу его уже негде взять.
|
|
173
|
+
void this.rememberSender(message);
|
|
170
174
|
void this.incoming.dispatch(message, this.id, this.options.accountId);
|
|
171
175
|
};
|
|
172
176
|
this.incomingListener = listener;
|
|
173
177
|
this.client.addEventHandler(listener, new NewMessage({}));
|
|
174
178
|
}
|
|
175
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Запомнить написавшего нам человека.
|
|
182
|
+
*
|
|
183
|
+
* Отказ здесь ничего не ломает и не сообщается: приём сообщения важнее, чем возможность
|
|
184
|
+
* ответить по номеру, а без записи остаётся ответ по имени.
|
|
185
|
+
*/
|
|
186
|
+
private async rememberSender(message: MtprotoMessageLike): Promise<void> {
|
|
187
|
+
try {
|
|
188
|
+
const { chatId, chatType } = peerToChat(message.peerId);
|
|
189
|
+
// Спрашиваем ПИР ОБНОВЛЕНИЯ, а не поле `sender`: у живого сообщения gramJS оно ленивое и
|
|
190
|
+
// чаще всего пустое, а `getInputSender` берёт собеседника из карты сущностей обновления.
|
|
191
|
+
const input = await message.getInputSender?.();
|
|
192
|
+
const hash = input?.accessHash ?? message.sender?.accessHash;
|
|
193
|
+
if (hash === undefined || hash === null) return;
|
|
194
|
+
// В группе отправитель и чат — разные пиры, и запись сложила бы одно вместо другого.
|
|
195
|
+
if (chatType !== "user") return;
|
|
196
|
+
const recipient = { type: "user", id: chatId } as const;
|
|
197
|
+
await this.peerStore.set(
|
|
198
|
+
this.options.accountId,
|
|
199
|
+
recipient,
|
|
200
|
+
{
|
|
201
|
+
type: "user",
|
|
202
|
+
id: chatId,
|
|
203
|
+
accessHash: String(hash),
|
|
204
|
+
username: message.sender?.username ?? (await message.getSender?.())?.username,
|
|
205
|
+
resolvedAt: new Date().toISOString(),
|
|
206
|
+
},
|
|
207
|
+
this.options.peerTtlSeconds,
|
|
208
|
+
);
|
|
209
|
+
} catch {
|
|
210
|
+
// приём важнее записи
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
176
214
|
private stopListeningIfIdle(): void {
|
|
177
215
|
if (this.incoming.size > 0 || this.incomingListener === null) return;
|
|
178
216
|
this.client.removeEventHandler(this.incomingListener, new NewMessage({}));
|