From bda101687273507911b7c829b78aab503ff6d158 Mon Sep 17 00:00:00 2001
From: Danil Nemov <d.nemov@corp.vk.com>
Date: Sat, 26 Aug 2023 12:28:14 +0300
Subject: [PATCH] =?UTF-8?q?=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D0=B8?=
 =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B?=
 =?UTF-8?q?=D1=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md | 102 +++++++++++++++++++-----------------------------------
 1 file changed, 36 insertions(+), 66 deletions(-)

diff --git a/README.md b/README.md
index 1154ec0..063612d 100644
--- a/README.md
+++ b/README.md
@@ -77,41 +77,32 @@ __Long Polling__ — это технология, которая позволя
 
 `server`, `key` и `ts` получаются методом [`messages.getLongPollServer`](https://dev.vk.com/method/messages.getLongPollServer)
 
-Важные параметры при вызове метода:
-- в `need_pts` следует указать `1`
-- в `lp_version` следует указать актуальную версию - 19
-
-* `server` - Домен лонгполла. Индивидуален для каждого пользователя, а так же может различаться у некоторых приложений
+* `server` - Домен лонгполла. Индивидуален для каждого пользователя. Может отличаться у некоторых приложений, от имени которых получался токен
 * `key` - Ключ для идентификации активной сессии. Протухает через час и привязан к айпи адресу
 * `ts` - Номер последнего события. Лонгполл будет возвращать события, следующие за ним
-* `version` - Версия LongPoll, актуальная версия - 19.  
-Поведение предыдущих версий может измениться или их поддержка может быть прекращена
+* `version` - Версия лонгполла
 * `wait` - Время ожидания нового события в секундах, максимум `90`. Рекомендуемое значение: `20`
 * `mode` - Настройка формата ответа. Рекомендуемое значение:  
 `(1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9) | (1 << 10)`
 
-TODO: информация о бизнес-уведомлениях
-
 | Бит       | Описание                                                                                              |
 |-----------|-------------------------------------------------------------------------------------------------------|
 | `1 << 1`  | Возвращать кладжи (секции `additional` и `attachments` в [структуре сообщения](#структура-сообщения)) |
 | `1 << 3`  | Возвращать расширенную информацию в [114], [115] и [119] событиях                                     |
 | `1 << 5`  | Возвращать `pts`                                                                                      |
-| `1 << 6`  | **[deprecated]** Возвращать события изменения онлайна друзей: [8] и [9]                               |
+| `1 << 6`  | **[неактуально]** Возвращать события изменения онлайна друзей: [8] и [9]                              |
 | `1 << 7`  | Возвращать [`random_id`](#зачем-нужен-random_id)                                                      |
 | `1 << 9`  | Возвращать события о бизнес-уведомлениях                                                              |
 | `1 << 10` | Возвращать тип `online` для `marked_users` при упоминании через `@online`                             |
 
-**[deprecated]** у `1 << 6` бита выставлен, потому что события [8] и [9] больше не возвращаются из лонгполла
-
 После выполнения запроса сервер вернет ответ следующего вида:
 ```ts
 type LongPollResult =
   // pts приходит, если в mode выставлен бит (1 << 5)
   // updates - массив событий, которые описаны в разделе "Описание событий"
   | { ts: number, pts: number, updates: unknown[] }
-  // ts слишком маленький (отстал более чем на 256 событий) или слишком большой.
-  // Необходимо воспользоваться переданным ts (лонгполл возвращает номер последнего события).
+  // ts слишком маленький (отстал более чем на 256 событий) или слишком большой (больше последнего существующего).
+  // Необходимо воспользоваться переданным ts (возвращается номер последнего события).
   // Как получить пропущенные события можно узнать в разделе "Получение истории событий" чуть ниже
   | { failed: 1, ts: number }
   // Ключ инвалидировался. Необходимо получить новый key, используя метод messages.getLongPollServer
@@ -122,42 +113,17 @@ type LongPollResult =
 
 После обработки ответа нужно повторить запрос, но с новым значением `ts`.
 
-Также необходимо сохранить полученный `pts`, чтобы при получении ошибки от лонгполла иметь возможность
-[получить пропущенные события](#получение-истории-событий).
-
-Очень важно обработать описанные ошибки, потому что вы с ними обязательно столкнетесь.  
-Напомню, что время жизни ключа лонгполла всего час, и после его протухания придет 2 ошибка.  
-А с 1 ошибкой вы столкнетесь, когда на некоторое время приостановите походы в лонгполл, например когда
-система уйдет в спящий режим, либо пропадет соединение с сетью по иным причинам.
-
 ## Получение истории событий
 
-Получать историю событий необходимо в том случае, когда лонгполл вернул `failed: 1` из-за слишком большого числа новых событий.
+Если лонгполл вернул `failed: 1`, у вас все еще есть возможность получить пропущенные события.
 
-Для получения истории событий нам необходим `pts` последнего известного вам события. С этим параметром нужно вызвать метод
-[`messages.getLongPollHistory`](https://dev.vk.com/method/messages.getLongPollHistory).
+1) Включите получение `pts` при [подключении](#подключение) к лонгполлу, добавив флаг `1 << 5` в `mode`
+2) Всегда сохраняйте возвращаемый лонгполлом `pts`
+3) С использованием `pts` и некоторых других параметров, описанных в документации, вызовите метод
+   [`messages.getLongPollHistory`](https://dev.vk.com/method/messages.getLongPollHistory).
 
-Ответ выглядит следующим образом:
-```ts
-// TODO: новые тайпинги
-// Описание типов:
-// https://github.com/danyadev/vk-types#объекты
-interface LongPollHistoryResult {
-  history: any[][]
-  from_pts: number
-  new_pts: number
-  conversations: VKConversation[]
-  messages: {
-    count: number
-    items: VKMessage[]
-  }
-  profiles?: VKUser[]
-  groups?: VKGroup[]
-  more?: true
-}
-```
-
-TODO: рассказать подробнее про обработку поля `history`
+Формат ответа метода описан здесь:
+https://github.com/VKCOM/api-schema-typescript/blob/master/src/methods/messages.ts#L773
 
 Поле `history` похоже на поле `updates` из лонгполла, но в нем будут находиться только персистентные события.  
 Так же события из этого списка придут в урезанном виде:
@@ -166,9 +132,12 @@ TODO: рассказать подробнее про обработку поля
 - `5` - [Редактирование сообщения](#событие-10005-редактирование-сообщения)
 - `18` - [Обновление сообщения](#событие-10018-обновление-сообщения)
 
+Как можно заметить, вместо `10000 + eventId` событий приходят события 3, 4, 5 и 18.
+Соответственно вместо `conversationMessageId` приходит просто `messageId`.
+Сам `conversationMessageId` при необходимости можно достать из поля `messages` в ответе метода.
+
 Структура этих событий выглядит так:
 ```ts
-// TODO: да, здесь приходят такие события, а не 10000 + type
 type LongPollHistoryMessageEvent = [
   type: 3 | 4 | 5 | 18,
   messageId: number,
@@ -192,8 +161,6 @@ type LongPollHistoryMessageEvent = [
 - [Вложения](#вложения)
 - [random_id](#зачем-нужен-random_id)
 
-> Структура описывает массив, ключи используются для упрощения визуального восприятия
-
 ```ts
 type LongPollMessage = [
   type: 10003 | 10004 | 10005 | 10018,
@@ -204,6 +171,7 @@ type LongPollMessage = [
   minorId?: number,
   peerId: number,
   timestamp: number,
+  // Переносы строк обозначаются как <br>, а символы " & < > экранируются
   text: string,
 
   // Объект приходит только при указании флага 2 при подключении к LongPoll
@@ -271,8 +239,6 @@ type LongPollMessage = [
 ];
 ```
 
-Стоит отметить, что в поле `text` переносы строк обозначаются как `<br>`, а символы `"`, `&`, `<` и `>` экранируются.
-
 ### Короткий кортеж сообщения
 
 Существует возможность возвращения укороченного кортежа с сообщением.
@@ -282,7 +248,7 @@ type LongPollMessage = [
 `random_id`, то с этим событием определенно возникнут проблемы, потому что в нем отсутствует
 `random_id`. Чтобы получить `random_id`, нужно запросить сообщение через апи:
 в случае `10004` события по `minorId` (в данном случае это синоним `message_id`),
-или в случае остальных событий по `cmid` (`conversationMessageId`) и `peerId`.
+или в случае остальных событий по `conversationMessageId` и `peerId`.
 Далее, если сообщение было не нашим, апи вернет ошибку и мы ее проигнорируем, а если сообщение
 было нашим - вернет сообщение с полем `deleted: 1` и искомым `random_id`.
 
@@ -526,6 +492,7 @@ type Event10013 = [
 ```
 
 ### Событие 10018. Обновление сообщения
+[10018]: #событие-10018-обновление-сообщения
 
 Приходит при следующих событиях:
 1. Добавился сниппет (ссылка) - к вложениям добавляется `link`.
@@ -599,9 +566,9 @@ type Event21 = [
 
 ### Событие 50. Перевод сообщения
 
-Это событие приходит, если пользователь запросил перевод сообщения. Для этого надо выполнить метод `messages.translate` (доступен только официальным клиентам, параметры см. ниже). Метод возвращает `1`.
+Это событие приходит, если пользователь запросил перевод сообщения.
 
-Если для определённого сообщения перевод запрашивается в первый раз, то вместе с событием `50` приходит и [событие `10018`](#событие-10018-обновление-сообщения), где в объекте `additional` будет поле `is_translated`.
+Если для определённого сообщения перевод запрашивается в первый раз, то вместе с событием `50` приходит и событие [10018], где в объекте `additional` будет поле `is_translated`.
 
 ```ts
 type Event50 = [
@@ -615,16 +582,13 @@ type Event50 = [
 ];
 ```
 
-Пример события:
-
-```js
-[50, {"peer_id": 2000000026, "cmid":476587, "translation":"There are 253 reactions", "language":"ru-en"}]
-```
-
-Поле `language` представляет собой языковую пару, который выглядит так: `ru-en`. Перед дефисом прописан исходный язык переводимого текста, после дефиса — язык, на который будет переведён текст.
+Поле `language` представляет собой языковую пару, который выглядит так: `ru-en`.
+Перед дефисом прописан исходный язык переводимого текста, после дефиса — язык, на который будет переведён текст.
 
 Список поддерживаемых языковых пар можно получить, выполнив метод `account.getInfo`. В ответе будет поле `messages_translation_language_pairs`.
 
+Чтобы запросить перевод сообщения, нужно выполнить метод `messages.translate` (доступен только официальным клиентам).
+
 Параметры метода `messages.translate`:
 ```ts
 interface MessagesTranslateParams {
@@ -661,7 +625,7 @@ type Event51 = [
 | 7   | Выход из беседы                                                | `id` вышедшего              |
 | 8   | Исключение из беседы                                           | `id` исключенного           |
 | 9   | Разжалован администратор                                       | `id` бывшего админа         |
-| 10  | Изменился баннер (какая-то инфа под шапкой в личке)            | `0`                         |
+| 10  | Изменился баннер                                               | `0`                         |
 | 11  | Появление или скрытие клавиатуры                               | `peerId`                    |
 | 12  | Отозвано / подтверждено / отклонено / пришло приглашение в чат | `0` / `1` / `2` / `3`       |
 | 13  | Контакт был сконвертирован в юзера (`contactId` -> `userId`)   | `contactId`                 |
@@ -673,6 +637,11 @@ type Event51 = [
 | 19  | Начало или окончание группового звонка                         | `1` в начале, `0` в конце   |
 | 22  | Чат больше не новый: пришло первое сообщение (только в лс)     | `0`                         |
 | 23  | Изменено оформление чата                                       | `0`                         |
+| 24  | Изменилось описание чата                                       | `0`                         |
+| 25  | Изменилось состояние `chat_settings.short_poll_reactions`      | `0` / `1`                   |
+| 26  | _soon_                                                         | _soon_                      |
+| 27  | _soon_                                                         | _soon_                      |
+| 28  | _soon_                                                         | _soon_                      |
 
 При изменении названия (`1`) и обновлении аватарки беседы (`2`) нужные данные можно взять из
 [сервисного сообщения](#сервисные-сообщения) в [4 событии](#событие-4-новое-сообщение).
@@ -680,7 +649,6 @@ type Event51 = [
 ```ts
 type Event52 = [
   type: 52,
-  // 0-19, 22, 23
   updateType: number,
   peerId: number,
   extra: number
@@ -1191,7 +1159,10 @@ interface LongPollKeyboard {
 
 #### Список существующих вложений
 
-Список известных на данный момент вложений: `geo`, `doc`, `link`, `poll`, `wall`, `call`, `gift`, `story`, `photo`, `audio`, `video`, `event`, `market`, `artist`, `widget`, `sticker`, `article`, `podcast`, `curator`, `graffiti`, `mini_app`, `narrative`, `wall_reply`, `audio_message`, `money_request`, `audio_playlist`, `group_call_in_progress`.
+Список известных на данный момент вложений:
+`geo`, `doc`, `link`, `poll`, `wall`, `call`, `gift`, `story`, `photo`, `audio`, `video`, `event`, `market`, `artist`, `widget`, `sticker`,
+`article`, `podcast`, `curator`, `graffiti`, `mini_app`, `narrative`, `wall_reply`, `audio_message`, `money_request`, `audio_playlist`,
+`group_call_in_progress`.
 
 Однако названия вложений, полученных через LongPoll, могут не совпадать с теми, что приходят через API:
 - `event`, приходящий в API, в LongPoll обозначается как `group`
@@ -1228,8 +1199,7 @@ const longpollAttachments = {
 и анализа списка вложений, чтобы в случае необходимости получить сообщение через [API](https://dev.vk.com/method/messages.getById).
 
 <details>
-<summary markdown="span">Пример кода для получения массива с названиями вложений
-</summary>
+<summary markdown="span">Пример кода для получения массива с названиями вложений</summary>
 
 ```js
 function getAttachments(data) {