- Отказ от ответственности
- Подключение
- Возвращаемые ошибки
- Получение истории событий
- Структура сообщения
- Описание событий
- Событие 2. Установка флагов сообщения
- Событие 3. Сброс флагов сообщения
- Событие 4. Новое сообщение
- Событие 5. Редактирование сообщения
- Событие 6. Прочтение входящих сообщений
- Событие 7. Прочтение исходящих сообщений
- Событие 8. Друг появился в сети
- Событие 9. Друг вышел из сети
- Событие 10. Сброс флагов беседы
- Событие 12. Установка флагов беседы
- Событие 13. Удаление всех сообщений в диалоге
- Событие 18. Изменение сообщения
- Событие 19. Сброс кеша сообщения
- Событие 21. Неизвестно
- Событие 51. Изменение данных чата (не следует использовать)
- Событие 52. Изменение данных чата
- Событие 63. Статус набора сообщения
- Событие 64. Статус записи голосового сообщения
- Событие 80. Изменение количества непрочитанных диалогов
- Событие 81. Изменение состояния невидимки друга
- Событие 114. Изменение настроек пуш-уведомлений в беседе
- Событие 115. Звонок
- Событие 119. Ответ callback-кнопки
- Дополнительная информация
Документация написана для 10 версии LongPoll.
Последняя версия LongPoll - 13, но я не рекомендую использовать версии выше 10, так как они не содержат полезных изменений.
Автор не несет ответственности за точность, полноту или качество предоставленной информации. Используйте последующую информацию на свой страх и риск.
Правила пользования сайтом, пункт 6.7:
6.7. Создаваемые Пользователями приложения API должны использовать только опубликованные на Сайте методы API, а также ID, защищенный ключ и сервисный ключ доступа, указанные в настройках данных приложений. Использование других методов API, а также ID, защищенного ключа и сервисного ключа доступа приложений API третьих лиц, в т.ч. приложения API Администрации Сайта, строго запрещено. Пользователь обязуется регулярно проверять перечень разрешённых методов и незамедлительно вносить корректировки в функциональность своих приложений API в соответствии с изменениями перечня. За нарушение настоящего пункта Пользователь несет предусмотренную применимым законодательством, настоящими Правилами и иными документами Администрации Сайта ответственность. Администрация Сайта при этом оставляет за собой право на защиту собственных прав и законных интересов.
Long Polling - это технология, используемая для получения событий в реальном времени, которая основана на бесконечной цепочке запрос - ответ - запрос... При подаче запроса сервер возвращает ответ не сразу, а когда придет новое событие или истечет время ожидания. Подробнее про данную технологию можно прочитать здесь.
Ссылка для запроса составляется следующим образом:
https://
server
?act=a_check&key=key
&ts=ts
&wait=wait
&mode=mode
&version=version
server
,key
иts
получаются методомmessages.getLongPollServer
version
- Версия LongPollwait
- Время ожидания нового события в секундах, максимум90
, рекомендую от10
до25
mode
- Дополнительные опции ответа:2
- Возвращать вложения и дополнительные данные сообщения (data[6]
иdata[7]
в структуре сообщения)8
- Возвращать данные в 114, 115 и 119 событиях32
- Возвращатьpts
64
- Возвращать данные о платформе в событии онлайна друга128
- Возвращатьrandom_id
Настоятельно рекомендую использовать в mode
все возможные опции.
В Node.js
ссылку можно составить следующим образом:
// server, key и ts нужно получить заранее с помощью метода messages.getLongPollServer.
const link = `https://${server}?` + require('querystring').stringify({
act: 'a_check',
key: key,
ts: ts,
wait: 10,
mode: 2 | 8 | 32 | 64 | 128,
version: 10
});
После выполнения запроса сервер вернет ответ следующего вида:
interface LongPollResult {
// Приходит, если нет ошибок или при failed: 1
ts?: number
// Приходит, если нет ошибок и при наличии флага 32
pts?: number
// Приходит, если нет ошибок
updates?: any[]
failed?: 1 | 2 | 3 | 4
// Приходят только при failed: 4
min_version?: 0
max_version?: 13
}
После обработки ответа нужно повторить запрос, перед этим заменив ts
и pts
на новые из ответа.
Иногда вместо поля updates
в ответе может прийти поле failed
. Чаще всего приходит 2
ошибка, но могут прийти и другие:
- Устарела история событий. Решается получением истории событий и использованием переданного
ts
далее. - Истекло время действия ключа. Решается получением нового
key
из методаmessages.getLongPollServer
. - Информация о пользователе утрачена. Решается получением истории событий и получением
key
иts
из методаmessages.getLongPollServer
. - Передана неправильная версия. В ответе приходят поля
min_version
иmax_version
, которые обозначают минимальную и максимальную версию.
Чтобы получить историю событий, нам необходим pts
, получение которого включается полем need_pts: 1
в messages.getLongPollServer
и добавлением в mode
флага 32
при выполнении запроса.
Для получения истории мы будем использовать метод messages.getLongPollHistory
с указанием следующих параметров:
pts
- Последний полученныйpts
из LongPollmsgs_limit
- Максимальное количество передаваемых сообщений. Минимум200
, рекомендую500
, максимум1000
onlines
-1
если возвращать события8
и9
(онлайн и оффлайн друга),0
если нетlp_version
- Версия LongPollfields
- Поля пользователей и групп, которые могут прийти вместе с историей
Ответ выглядит следующим образом:
// Все приведенные типы:
// https://github.com/danyadev/vk-desktop/tree/typescript/src/types
interface LongPollHistoryResult {
// Здесь содержатся некоторые события из LongPoll,
// но вся информация действительно является только числами:
// [event_id, msg_id, flag, peer_id] или что-то похожее
history: number[][]
from_pts: number
new_pts: number
conversations: VKConversation[]
messages: {
count: number
items: VKMessage[]
}
profiles?: VKUser[]
groups?: VKGroup[]
more?: true
}
Поле history
идентично полю updates
, которое приходит из LongPoll, за исключением удаления некоторых лишних событий (т.к. приходит просто измененный объект беседы или сообщения) и сокращения некоторых событий:
3
- Сброс флагов сообщения4
- Новое сообщение5
- Редактирование сообщения18
- Добавление сниппета к сообщению
Структура этих событий выглядит так (все с типом number
):
[event_id, msg_id, flags, peer_id]
Всю информацию о сообщениях и беседах можно взять из полей messages
и conversations
, где содержатся данные из API.
Если в ответе придет поле more
, то после обработки всех событий нужно будет повторить запрос, указав в поле pts
пришедший new_pts
.
Структура сообщения встречается сразу в 4 событиях (3
, 4
, 5
и 18
), поэтому было решено описать ее отдельно.
Подробное описание некоторых элементов этой структуры можно почитать здесь:
При обращении к этой структуре в документации индексация начинается с нуля (т.е. data[0] соответствует значению event_id и так далее)
[
event_id: 3 | 4 | 5 | 18,
msg_id: number,
flags: number,
peer_id: number,
timestamp: number,
text: string,
// Объект приходит только при указании флага 2 при подключении к LongPoll
{
// ' ... ' приходит только в лс
// '' приходит при редактировании любого сообщения
// string приходит при написании в лс через vk.com с указанием темы
// Устаревшее поле, не следует использовать
title?: ' ... ' | '' | string
// Наличие emoji
emoji?: '1'
// id автора сообщения. Приходит только в беседах
from?: string
// Наличие шаблона (для получения шаблона нужно получить сообщение из API)
has_template?: '1'
// 1: Список упомянутых людей прямо или через @online; Ответ на сообщение от [user_id]; @all
// 2: Исчезающее сообщение в обычном чате
marked_users?: [
| [1, number[] | 'all']
| [2, 'all']
]
// Клавиатура для ботов (в том числе и инлайн)
keyboard?: MessageKeyboard
// Количество секунд до исчезновения сообщения в обычном чате
expire_ttl?: string
// Количество секунд до исчезновения сообщения в фантомном чате
ttl?: number
// Сообщение исчезло, приходит в 18 событии
is_expired?: '1'
// Приходит, если при отправке сообщения указать параметр payload.
// Возвращает всегда JSON, который может содержать любую информацию.
// Там может содержаться отладочная информация, которая может пригодиться разработчику.
payload?: string
// Сервисное сообщение
...action
},
// Объект приходит только при указании флага 2 при подключении к LongPoll
{
// Есть пересланное сообщение или ответ на сообщение
fwd?: '0_0'
// Ответ на сообщение: '{"conversation_message_id":number}'
reply?: string
// Количество вложений в поле attachments
// Число в строке
attachments_count?: string
// JSON с массивом вложений
// Приходит только для некоторых типов вложений
attachments?: string
// Описание вложений вида { attach1_type, attach1, ... }
// Все значения здесь имеют тип строки (и могут быть объектом в строке по типу '{"id":1}')
...attachments
},
// Возвращается, если в mode есть флаг 128
random_id: number,
// id сообщения относительно беседы
conversation_message_id: number,
// 0 (не редактировалось) или timestamp (время редактирования)
edit_time: number
]
Стоит отметить, что в поле text
переносы строк обозначаются как <br>
, а символы "
, &
, <
и >
экранируются.
Возможные значения флагов сообщения:
- Пометка важным (
8 important
) - Пометка как спам (
64 spam
) - Удаление сообщения (
128 deleted
) - Удаление для всех (
128 deleted
и131072 deleted_all
) - Прослушивание голосового сообщения (
4096 audio_listened
)
В случае прослушивания голосового сообщения событие приходит как при прослушивании собеседником вашего голосового сообщения, так и при прослушивании вами голосового сообщения собеседника.
Вручную прослушать голосовое сообщение собеседника можно с помощью метода messages.markAsListened
с параметром message_id
.
Метод вернет 1
при первом прослушивании голосового сообщения, а 0
при последующих или при попытке прослушать свое сообщение.
// [msg_id, flags, peer_id]
type LongPollEvent2 = [number, number, number];
Возможные значения флагов сообщения:
- Прочитано сообщение (
1 unread
). Не рекомендую использовать, потому что иногда этот флаг не приходит - Отмена пометки важным (
8 important
) - Отмена пометки сообщения как спам (
64 spam
и32768 cancel_spam
) - Восстановление удаленного сообщения (
128 deleted
)
В 3 и 4 случаях возвращается сообщение.
// [msg_id, flags, peer_id]
type LongPollEvent3 = [number, number, number] | LongPollMessage;
Данное событие возвращает новое сообщение.
type LongPollEvent4 = LongPollMessage;
Данное событие возвращает отредактированное сообщение.
type LongPollEvent5 = LongPollMessage;
Вы прочитали в диалоге peer_id
сообщения до msg_id
включительно.
count
- количество непрочитанных в диалоге сообщений.
// [peer_id, msg_id, count]
type LongPollEvent6 = [number, number, number];
Собеседник прочитал в диалоге peer_id
сообщения до msg_id
включительно.
count
- количество ваших непрочитанных сообщений в диалоге.
// [peer_id, msg_id, count]
type LongPollEvent7 = [number, number, number];
Структура: [-user_id, platform, timestamp, app_id]
user_id
-id
другаplatform
- Тип устройства, с которого онлайн друг:1
-m.vk.com
или неизвестное мобильное приложение2
- iPhone3
- iPad4
- Android5
- Windows Phone6
- Windows 87
-vk.com
или неизвестное десктопное приложение
timestamp
- Время онлайна в секундахapp_id
-id
приложения, с которого онлайн друг
// [-user_id, platform, timestamp, app_id, 0 | 1, 0]
type LongPollEvent8 = [number, number, number, number, 0 | 1, 0];
Структура: [-user_id, isTimeout, timestamp, app_id]
user_id
-id
другаisTimeout
-1
если бездействовал 5 минут,0
если покинул сайтtimestamp
- Время наступления оффлайна в секундахapp_id
-id
приложения, с которого был онлайн друг
// [-user_id, isTimeout, timestamp, app_id, 0, 0]
type LongPollEvent9 = [number, 0 | 1, number, number, 0, 0];
Приходит при следующих действиях: (+ приходящий флаг)
- Просмотрено упоминание (ответ на сообщение, пуш или
@all
) -17408
(1024
+16384
) - Просмотрено исчезающее сообщение -
17408
(1024
+16384
) - Беседа была отмечена прочитанной -
1048576
Кроме этих действий есть еще одно, но пока неясно, что именно его вызывает. Его флаг - 537919488
(1048576
, 536870912
).
Так же это событие приходит когда удаляется сообщение, создавшее этот флаг.
Событие означает удаление у беседы соответствующего значка, то есть:
- для 1 и 2 пункта событие придет только при просмотре всех сообщений такого рода
- для 3 пункта событие придет только при прочтении сообщений после ручной пометки беседы как непрочитанной
// [peer_id, flags]
type LongPollEvent10 = [number, number];
Приходит при следующих событиях: (+ приходящий флаг)
- Появилось упоминание (ответ на сообщение, пуш или @all) -
16384
- Появилось исчезающее сообщение -
16384
- Беседа была отмечена непрочитанной -
1048576
Событие означает добавление к беседе соответствующего значка, то есть:
- для 1 и 2 пункта событие придет только для первого сообщения в таком роде
- для 3 пункта событие придет только при самостоятельной пометке беседы как непрочитанной
// [peer_id, flags]
type LongPollEvent12 = [number, number];
В беседе peer_id
были удалены все сообщения до last_msg_id
включительно.
// [peer_id, last_msg_id]
type LongPollEvent13 = [number, number];
Приходит при следующих событиях:
- Добавился сниппет (ссылка) - к вложениям добавляется
link
. - Сообщение исчезло - удаляется текст и все вложения, добавляется ключ
is_expired: true
. - Пришел перевод голосового сообщения.
В общем это событие работает как редактирование сообщения со стороны ВКонтакте, так что обрабатывать его нужно так же, как и обычное редактирование сообщения.
Данное событие возвращает сообщение.
type LongPollEvent18 = LongPollMessage;
Приходит в двух случаях:
- По какой-либо причине изменилось сообщение (без явного редактирования). Необходимо переполучить сообщение через API.
- Сообщение исчезло. В данном случае можно игнорировать это событие, если вы обработали исчезновение сообщения в 18 событии.
ВАЖНО: если вы собираетесь обрабатывать исчезновение сообщений, то я рекомендую игнорировать 19 событие и обрабатывать
только 18 событие. Однако сначала приходит 19 событие, а потом уже 18, поэтому нужно сначала дождаться, пока обработается
18 событие и там к сообщению добавится поле is_expired
, и только затем здесь проверять это сообщение на наличие этого поля.
Дождаться обработки можно либо с помощью таймаутов, а можно воспользоваться событиями об окончании обработки события
(в зависимости от реализации).
// [msg_id]
type LongPollEvent19 = [number];
// [peer_id, msg_id]
type LongPollEvent21 = [number, number];
Событие означает, что в беседе chat_id
изменились какие-то данные.
Более подробно все расписано в 52 событии.
// [chat_id]
type LongPollEvent51 = [number];
Структура: [type, peer_id, extra]
peer_id
-id
беседы, в которой произошло событиеextra
- Дополнительная информация, которая зависит отtype
type
- Тип действия:1
- Изменилось название беседы- Основная информация приходит в сервисном сообщении в 4 событии
extra
=0
2
- Обновилась аватарка беседы- Основная информация приходит в сервисном сообщении в 4 событии
extra
=0
3
- Назначен новый администраторextra
=id
нового администратора
4
- Изменение прав в беседе
Полеextra
является маской, которая может включать следующие флаги:1
- Приглашать участников в беседу могут только администраторы2
- Неизвестно4
- Менять закрепленное сообщение могут только администраторы8
- Редактировать информацию беседы (фото, название) могут только администраторы16
- Добавлять администраторов кроме создателя могут и другие администраторы
5
- Закрепление или открепление сообщенияextra
=conversation_message_id
сообщения при закреплении и0
при откреплении
6
- Вступление в беседу (по ссылке, приглашение или возвращение в беседу)extra
=id
добавленного юзера
7
- Выход из беседыextra
=id
вышедшего из беседы
8
- Исключение из беседыextra
=id
исключенного из беседы
9
- Разжалован администраторextra
=id
разжалованного из администраторов
11
- Появление и скрытие клавиатурыextra
=id
диалога, в котором произошло действие
19
- Начало и окончание группового звонкаextra
=1
при начале, а0
при конце звонка- Может приходить несколько раз для одного и того же звонка с
extra
=1
// [type, peer_id, extra]
type LongPollEvent52 = [number, number, number];
Означает, что в беседе peer_id
начали писать текст from_ids_count
людей. Их id
записаны в from_ids
.
В массиве from_ids
иногда может появиться и ваш id
, так что нужно проверять и удалять его из списка.
// [peer_id, from_ids[], from_ids_count, timestamp]
type LongPollEvent63 = [number, number[], number, number];
Идентичен событию 63, но вызывается в случае записи голосового сообщения, а не при наборе текста.
Структура: [count, count_with_notifications]
count
- Количество непрочитанных диалоговcount_with_notifications
- Количество непрочитанных сообщений со включенными уведомлениями
// [count, count_with_notifications, 0, 0]
type LongPollEvent80 = [number, number, 0, 0];
Структура: [-user_id, state, timestamp]
user_id
-id
другаstate
-1
если включена,0
если выключенаtimestamp
- время последнего онлайна друга
// [-user_id, state, timestamp, -1, 0]
type LongPollEvent81 = [number, number, number, -1, 0];
Для работы необходимо использовать в mode
флаг 8
при выполнении запроса.
Структура: [{ peer_id, sound, disabled_until }]
peer_id
-id
беседы, в которой включили или выключили уведомленияsound
- нестабильный параметр, не рекомендую его обрабатыватьdisabled_until
может быть трех видов:0
- Уведомления включены-1
- Уведомления выключеныnumber, > 0
, - Уведомления выключены до определенного времени, гдеnumber
- дата включения уведомлений
type LongPollEvent114 = [{
peer_id: number
sound: 0 | 1
disabled_until: 0 | -1 | number
}];
Для работы необходимо использовать в mode
флаг 8
при выполнении запроса.
¯\_(ツ)_/¯
Для работы необходимо использовать в mode
флаг 8
при выполнении запроса.
Callback-кнопки работают следующим образом:
- Бот отправляет клавиатуру (обычную или инлайн), где находится callback-кнопка;
- Пользователь нажимает на эту кнопку и клиент вызывает метод
messages.sendMessageEvent
(параметры см. ниже). Метод же возвращает строку, которая являетсяevent_id
; - Бот получает событие
message_event
и вызывает метод messages.sendMessageEventAnswer; - Этот метод вызывает
119
событие LongPoll у пользователя, где вaction
прописано действие, которое необходимо выполнить клиенту.
Параметры метода messages.sendMessageEvent
:
interface MessagesSendMessageEventParams {
peer_id: number
// Находится в кнопке клавиатуры
payload: string
// Нужно передать один из двух параметров,
// если это инлайн клавиатура в сообщении или карусели
message_id?: number
conversation_message_id?: number
// Находится в объекте клавиатуры беседы
// Нужно передать, если это клавиатура беседы
author_id?: number
}
После получения event_id
на 2 стадии нужно начать ждать 119
событие LongPoll с нужным event_id
.
Если за минуту бот так и не пришлет событие, то ожидание ответа следует прекратить.
type LongPollEvent119 = [{
// Отрицательный ID бота, который ответил на клик по кнопке
owner_id: number
// ID беседы, в которой находится сообщение
peer_id: number
// Уникальный ID события, действующий 1 минуту.
// Нужен для идентификации кликнутой кнопки
event_id: string
// Не приходит, если не нужно выполнять никакое действие
// т.е. бот отправил пустой payload или неизвестный тип действия
action?:
// Показать снекбар с текстом `text`
| { type: 'show_snackbar', text: string }
// Открыть ссылку `link`
| { type: 'open_link', link: string }
// Открыть приложение по ссылке
// https://vk.com/app${app_id}_${owner_id}#${hash}
// https://vk.com/app${app_id}_${owner_id} (если hash = '')
// https://vk.com/app${app_id} (если owner_id = undefined и hash = '')
| { type: 'open_app', app_id: number, owner_id?: number, hash: string }
}];
Маской называют сумму некоторых флагов (степеней двойки), которую можно использовать как хорошую замену для объектов или массивов.
// Обычно маску записывают подобным образом:
const mask = 1 | 2 | 8 | 64 | 1024;
// Но можно воспользоваться и обычным сложением:
const mask = 1 + 2 + 8 + 64 + 1024;
// А еще можно не писать большие цифры, а записывать степени двойки в таком формате:
const mask = 1 << 11 | 1 << 15;
Для того, чтобы не запутаться в больших значениях степеней двойки,
можно использовать 1 << n
, что означает 2
в степени n
.
Название | Описание | Значение | Как число |
---|---|---|---|
unread | Непрочитанное сообщение | 1 << 0 |
1 |
outbox | Исходящее сообщение | 1 << 1 |
2 |
important | Важное сообщение | 1 << 3 |
8 |
chat | Отправка сообщения в беседу через vk.com | 1 << 4 |
16 |
friends | Исходящее; входящее от друга в лс | 1 << 5 |
32 |
spam | Пометка сообщения как спам | 1 << 6 |
64 |
deleted | Удаление сообщения локально | 1 << 7 |
128 |
audio_listened | Прослушано голосовое сообщение | 1 << 12 |
4096 |
chat2 | Отправка сообщения в беседу | 1 << 13 |
8192 |
cancel_spam | Отмена пометки как спам | 1 << 15 |
32768 |
hidden | Приветственное сообщение от группы | 1 << 16 |
65536 |
deleted_all | Удаление сообщения для всех | 1 << 17 |
131072 |
chat_in | Входящее сообщение в беседе | 1 << 19 |
524288 |
silent | "Бесшумное" сообщение (без уведомления) | 1 << 20 |
1048576 |
reply_msg | Ответ на сообщение | 1 << 21 |
2097152 |
Бесшумное сообщение можно отправить, добавив к параметрам метода messages.send
ключ silent: true
:
- Такое сообщение отправится без уведомления пользователю, даже если у него включены уведомления
- Упоминание или ответ на сообщение тоже не отправит уведомления
- Сообщение о выходе из беседы автоматически приходит без уведомления
Пример определения наличия флага в маске:
const mask = 1 | 2 | 32; // = 35
8 & mask // вернет 0 (false)
2 & mask // вернет 2 (true)
Сервисное сообщение описывается ключом source_act
и ключами с дополнительными данными.
Вместе с некоторыми сервисными сообщениями приходит и текст сообщения по типу Сообщение не поддерживается Вашим приложением.
,
поэтому при обработке сервисных сообщений не нужно обрабатывать текст сообщения.
Вместе с сервисными сообщениями chat_title_update
и chat_photo_remove
в каналах приходит поле
source_is_channel: "1"
. Сервисное сообщение chat_photo_update
для каналов не приходит
(только 52 событие).
Возможные значения source_act
:
chat_create
- Создание беседыsource_text
- Название беседы
chat_photo_update
- Обновление фотографии беседы- Нет дополнительных ключей, но добавляет фотографию во вложениях
chat_photo_remove
- Удаление фотографии беседы- Нет дополнительных ключей
chat_title_update
- Обновление названия беседыsource_old_text
- Старое название беседы (но при получении сообщения из API его не будет)source_text
- Новое название беседы
chat_pin_message
- Закрепление сообщенияsource_mid
-id
закрепившего сообщениеsource_message
- обрезанное закрепляемое сообщениеsource_chat_local_id
-conversation_message_id
закрепляемого сообщения
chat_unpin_message
- Открепление сообщенияsource_mid
-id
открепившего сообщениеsource_chat_local_id
-conversation_message_id
открепляемого сообщения
chat_invite_user
- Вступление или возвращение в беседуsource_mid
-id
вступившего или вернувшегося- Если
source_mid
совпадает сfrom
, то он вернулся сам, иначе - его пригласили
chat_invite_user_by_link
- Вступление в беседу по ссылке- Нет дополнительных ключей
chat_kick_user
- Исключение или выход из беседыsource_mid
-id
исключенного или вышедшего- если
source_mid
совпадает сfrom
, то он вышел сам, иначе - его исключили
chat_screenshot
- Создание скриншота с фантомным сообщениемsource_mid
-id
создавшего скриншот
chat_group_call_started
- Начало группового звонка в беседеdeprecated
- Больше не приходит в LongPoll
- Вместо этого сервисного сообщения создается сообщение с вложением
group_call_in_progress
- Приходит для старых сообщений через API, но только при получении через токен VK для Android
chat_invite_user_by_call
- Приглашение пользователя в звонокsource_mid
-id
приглашенного пользователя
chat_invite_user_by_call_join_link
- Присоединение пользователя к звонку по ссылке- Нет дополнительных ключей
Пример описания сервисного сообщения:
{
source_act: 'chat_pin_message',
source_mid: '88262293',
source_message: 'Сообщение, которое будет в закрепе',
source_chat_local_id: '5517'
}
Клавиатура для ботов представляет собой объект с описанием ее типа и кнопок. Основная структура представлена ниже, остальную информацию можно узнать в документации.
// Типы у объекта клавиатуры:
// https://github.com/danyadev/vk-desktop/blob/typescript/src/types/VKKeyboard.ts
interface LongPollKeyboard {
// Приходит, если это клавиатура сообщения или карусели
inline?: true
// Скрывать ли клавиатуру при клике на кнопку (не работает для inline)
one_time: boolean
buttons?: VKKeyboardButton[][]
}
Список известных на данный момент вложений: geo
, doc
, link
, poll
, wall
, call
, gift
, story
, photo
, audio
, video
, event
, market
, artist
, sticker
, article
, podcast
, graffiti
, mini_app
, wall_reply
, audio_message
, money_request
, audio_playlist
, group_call_in_progress
.
Однако названия вложений, полученных через LongPoll, могут не совпадать с теми, что приходят через API:
event
, приходящий в API, в LongPoll обозначается какgroup
audio_message
иgraffiti
из LongPoll обозначаются какdoc
, но при этом добавляется ключattach*_kind
в ответе вложения со значениемaudiomsg
илиgraffiti
artist
,audio_playlist
иarticle
, которые приходят в LongPoll, через API отображаются какlink
Вложения artist
, audio_playlist
, article
и mini_app
приходят в API только через токен VK для Android.
Вложение geo
(прикрепленное местоположение) является еще одним исключением и приходит не как attach*
, а просто как ключи geo
и иногда geo_provider
. Также при получении сообщения через messages.getById
ключ geo
будет находиться не во вложениях, а в "корне" сообщения.
Сообщение с вложением group_call_in_progress
создается, когда пользователь начинает групповой звонок.
При окончании группового звонка сообщение с этим вложением удаляется и создается новое сообщение с вложением call
.
Пример вложений, состоящих из фотографии, документа и аудиозаписи:
{
attach1: '88262293_457290160',
attach1_type: 'photo',
attach2: '88262293_532324610',
attach2_type: 'doc',
attach3: '88262293_535133534',
attach3_kind: 'audiomsg',
attach3_type: 'doc'
}
Для того, чтобы вытащить их названия, нужно писать дополнительный код. Однако вытаскивать идентификаторы вложений нет смысла, потому что они не представляют никакой ценности. Чтобы получить нормальную информацию о вложениях, нужно получить сообщение через API, используя метод messages.getById
.
Пример кода для получения массива с названиями вложений на JavaScript
:
function getAttachments(data) {
const attachments = [];
if (data.geo) {
attachments.push('geo');
}
for (const key in data) {
const match = key.match(/attach(\d+)$/);
if (match) {
const id = match[1];
const kind = data[`attach${id}_kind`];
let type = data[`attach${id}_type`];
if (kind === 'audiomsg') type = 'audio_message';
if (kind === 'graffiti') type = 'graffiti';
if (type === 'group') type = 'event';
attachments.push(type);
}
}
return attachments;
}
Определить наличие ответа на сообщение можно с помощью data[7].reply
(структура)
или проверив наличие флага 2097152 reply_msg
.
В некоторых случаях получать сообщение через API для получения ответа на сообщение не нужно:
если сообщение, на которое пришло ответ, пришло недавно, то оно наверняка уже должно быть в локальном списке сообщений.
Найти сообщение можно с помощью conversation_message_id
из data[7].reply
.
Определить наличие пересланных сообщений можно с помощью проверки на отсутствие ответа на сообщения и на наличие data[7].fwd
.
ID пересланных сообщений, как и их количество, пока что не приходит через LongPoll.
Для получения некоторых вложений тоже не обязательно получать сообщение через API - в data[7]
приходят поля
attachments_count
и attachments
, где и содержатся уже готовые объекты вложений через API. К таким "халявным"
вложениям можно отнести голосовое сообщение и стикер. В будущем, возможно, этот список будет пополняться,
поэтому не нужно вытаскивать из attachments
только некоторые типы вложений, а смотреть там все, что есть.
При работе с вложениями можно попробовать найти необходимый элемент в документации, однако у некоторых вложений документация не обновлена или вовсе отсутствует.
Начнем с того, что random_id
начиная с версии API 5.90
стал обязательным параметром.
Но это не означает, что всем нужно генерировать уникальные значения для этого параметра.
Если вы его не собираетесь использовать, то можете указать в его значении число 0
.
Значение random_id
должно быть уникальным в течение одного часа в рамках app_id
, id
пользователя и peer_id
диалога.
Значение random_id
может принимать числа от -2147483648
(-(2^31)
) до 2147483647
(2^31 - 1
).
Если число будет больше или меньше данного порога, то из переданного числа отнимется этот лимит.
Основная задача этого параметра заключается в гарантировании идемпотентности API для отправки сообщений.
Это означает, что при отправке запросов с одинаковым random_id
и, чаще всего, одинаковыми параметрами,
сервер не будет создавать новое сообщение и вернет ID уже созданного.
Зачем все это нужно довольно детально описано в данной статье.
Наверняка вы уже видели, что во всех мессенджерах ВКонтакте при отправке сообщения само сообщение отображается сразу, но около сообщения некоторое время видно иконку часов. Эта иконка означает, что сообщение еще не пришло обратно через LongPoll.
Чтобы реализовать подобную фичу, нужно определить, какое именно сообщение, приходящее из LongPoll, было только что отправлено. Для этого нужно:
- Создать
random_id
и сохранить его в списке с отправляемыми сообщениями - Отправить сообщение
- Дождаться прихода из LongPoll сообщения с нашим
random_id
- Удалить
random_id
из списка, тем самым пометив сообщение как отправленное.