UNPKG

umbot

Version:

Мультиплатформенный фреймворк для создания голосовых навыков и чат-ботов с единой бизнес-логикой. Встроенная поддержка ВКонтакте, Telegram, Viber, MAX, Яндекс Алисы, Маруси и Сбера SmartApp. Архитектура на адаптерах позволяет подключать любые другие платф

433 lines (432 loc) 16.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VkRequest = void 0; const index_1 = require("../../../index"); const constants_1 = require("../VK/constants"); const constants_2 = require("./constants"); /** * Версия VK API по умолчанию */ const VK_API_VERSION = '5.103'; /** * Базовый URL для всех методов VK API */ const VK_API_ENDPOINT = 'https://api.vk.ru/method/'; /** * Класс для взаимодействия с API ВКонтакте * Предоставляет методы для отправки сообщений, загрузки файлов и работы с другими функциями API * @see (https://vk.ru/dev/bots_docs) Смотри тут * * @example * ```ts * import { VkRequest } from './api/VkRequest'; * * // Создание экземпляра * const vk = new VkRequest(); * vk.initToken('your-vk-token'); * * // Отправка простого сообщения * await vk.messagesSend(12345, 'Привет!'); * * // Отправка сообщения с клавиатурой * const keyboard = { * one_time: true, * buttons: [[{ * action: { * type: 'text', * label: 'Кнопка', * payload: '{"button": 1}' * }, * color: 'primary' * }]] * }; * * await vk.messagesSend(12345, 'Выберите действие:', { * keyboard: JSON.stringify(keyboard) * }); * * // Загрузка и отправка фото * const server = await vk.photosGetMessagesUploadServer(12345); * if (server) { * const upload = await vk.upload(server.upload_url, 'path/to/photo.jpg'); * if (upload) { * const photo = await vk.photosSaveMessagesPhoto( * upload.photo, * upload.server, * upload.hash * ); * if (photo) { * await vk.messagesSend(12345, 'Фото:', { * attachments: [`photo${photo.owner_id}_${photo.id}`] * }); * } * } * } * ``` */ class VkRequest { /** * Текущая используемая версия VK API */ #vkApiVersion; /** * Экземпляр класса для выполнения HTTP-запросов */ _request; /** * Текст последней возникшей ошибки */ _error; /** * Токен доступа к VK API */ token; /** * Флаг для прямой передачи содержимого файла * По умолчанию: false */ isAttachContent; /** * Контекст приложения. */ _appContext; /** * Создает экземпляр класса для работы с API ВКонтакте * Устанавливает токен из конфигурации приложения, если он доступен */ constructor(appContext) { this._request = new index_1.Request(appContext); this._request.header = { 'Content-Type': 'application/x-www-form-urlencoded', }; this._request.maxTimeQuery = 5500; this.isAttachContent = false; this._appContext = appContext; if (appContext.appConfig.tokens[constants_1.T_VK]?.api_version) { this.#vkApiVersion = appContext.appConfig.tokens[constants_1.T_VK].api_version; } else { this.#vkApiVersion = VK_API_VERSION; } this.token = null; this._error = null; if (appContext.appConfig.tokens[constants_1.T_VK]?.token) { this.initToken(appContext.appConfig.tokens[constants_1.T_VK].token); } } /** * Инициализирует токен доступа к VK API * @param token Токен доступа к VK API */ initToken(token) { this.token = token; } /** * Выполняет вызов метода VK API * @param method Название метода VK API * @returns Результат выполнения метода или null при ошибке */ async call(method) { if (this.token) { if (!this._request.attach) { // vk принимает post только в таком формате this._request.header = { 'Content-Type': 'application/x-www-form-urlencoded', }; } this._request.post ??= {}; if (!(this._request.post instanceof FormData)) { this._request.post.access_token = this.token; this._request.post.v = this.#vkApiVersion; if (!this._request.attach) { // vk принимает post только в таком формате this._request.postInString = (0, index_1.httpBuildQuery)(this._request.post); } } const data = await this._request.send(VK_API_ENDPOINT + method); if (data.status && data.data) { this._error = data.err || []; if (data.data.error !== undefined) { this._error = data; this._log('call() Запрос к платформе вернулся с ошибкой.'); return null; } return data.data.response || data.data; } this._log(data.err); } else { this._log((0, constants_2.getErrorToken)(constants_1.T_VK, 'call')); } return null; } /** * Загружает файл на сервера ВКонтакте * @param url URL для загрузки файла * @param file Путь к файлу или его содержимое * @returns Информация о загруженном файле или null при ошибке * * @remarks * Для фотографий возвращает: * - photo: строка, содержащая информацию о фото * - server: строка, идентификатор сервера * - hash: строка, хеш загруженного файла * * Для документов возвращает: * - file: строка, информация о загруженном файле * * @example * ```ts * // Загрузка фото * const server = await vk.photosGetMessagesUploadServer(12345); * if (server) { * const upload = await vk.upload(server.upload_url, 'photo.jpg'); * if (upload) { * const photo = await vk.photosSaveMessagesPhoto( * upload.photo, * upload.server, * upload.hash * ); * } * } * * // Загрузка документа * const server = await vk.docsGetMessagesUploadServer(12345, 'doc'); * if (server) { * const upload = await vk.upload(server.upload_url, 'document.pdf'); * if (upload) { * const doc = await vk.docsSave( * upload.file, * 'Документ', * 'тег1,тег2' * ); * } * } * ``` */ async upload(url, file) { this._request.attach = file; this._request.isAttachContent = this.isAttachContent; this._request.header = index_1.Request.HEADER_FORM_DATA; const data = await this._request.send(url); if (data.status && data.data) { if (data.data.error !== undefined) { this._error = data; this._log(); return null; } return data.data; } this._log(data.err); return null; } /** * Отправляет сообщение пользователю или в чат * @param peerId Идентификатор получателя: * - ID пользователя (например, "12345") * - ID чата: 2000000000 + chat_id (например, для чата 1: 2000000001) * - ID сообщества: -ID сообщества (например, "-123456789") * @param message Текст сообщения * @param params Дополнительные параметры: * - random_id: уникальный ID для избежания повторов * - attachment: медиавложения в формате "<type><owner_id>_<media_id>" * Примеры: * - Фото: "photo123456_789" * - Документ: "doc123456_789" * - Аудио: "audio123456_789" * - Видео: "video123456_789" * - keyboard: клавиатура в JSON формате или строкой * - template: шаблон карусели в JSON формате или строкой * * @example * ```ts * // Простое сообщение * await vk.messagesSend(12345, 'Привет!'); * * // Сообщение с вложениями * await vk.messagesSend(12345, 'Фото:', { * attachments: ['photo123_456', 'doc123_456'] * }); * * // Сообщение с клавиатурой * const keyboard = { * one_time: true, * buttons: [[{ * action: { * type: 'text', * label: 'Кнопка', * payload: '{"button": 1}' * }, * color: 'primary' * }]] * }; * await vk.messagesSend(12345, 'Выберите:', { * keyboard: JSON.stringify(keyboard) * }); * * // Сообщение с каруселью * const template = { * type: 'carousel', * elements: [{ * title: 'Заголовок', * description: 'Описание', * photo_id: '-123456_789', * buttons: [{ * action: { * type: 'text', * label: 'Кнопка', * payload: '{"button": 1}' * } * }] * }] * }; * await vk.messagesSend(12345, '', { * template: JSON.stringify(template) * }); * ``` * * @returns Информация об отправленном сообщении или null при ошибке */ async messagesSend(peerId, message, params = null) { const method = 'messages.send'; this._request.post = { peer_id: peerId, message, }; if (typeof peerId !== 'number') { this._request.post.domain = peerId; this._request.post.peer_id = undefined; } if (params) { if (params.random_id === undefined) { this._request.post.random_id = Date.now(); } else { this._request.post.random_id = params.random_id; } if (params.attachments !== undefined) { this._request.post.attachment = params.attachments.join(','); params.attachments = undefined; } if (params.template !== undefined) { if (typeof params.template !== 'string') { params.template = JSON.stringify(params.template); } this._request.post.template = params.template; params.template = undefined; } if (params.keyboard !== undefined) { if (this._request.post.template !== undefined) { // await this.call<IVKSendMessage>(method); this._request.post.template = undefined; } if (typeof params.keyboard !== 'string') { params.keyboard = JSON.stringify(params.keyboard); } this._request.post.keyboard = params.keyboard; params.keyboard = undefined; } if ((0, index_1.keysCount)(params)) { this._request.post = { ...params, ...this._request.post }; } } return await this.call(method); } /** * Получает информацию о пользователе или списке пользователей * @param userId ID пользователя или массив ID * @param params Дополнительные параметры запроса * @returns Информация о пользователях или null при ошибке */ async usersGet(userId, params = null) { if (typeof userId === 'number') { this._request.post = { user_id: userId }; } else { this._request.post = { user_ids: userId }; } if (params) { this._request.post = { ...this._request.post, ...params }; } return this.call('users.get'); } /** * Получает URL для загрузки фотографий в сообщения * @param peerId ID получателя сообщения * @returns Данные для загрузки или null при ошибке */ async photosGetMessagesUploadServer(peerId) { this._request.post = { peer_id: peerId }; return this.call('photos.getMessagesUploadServer'); } /** * Сохраняет загруженную фотографию в сообщениях * @param photo Идентификатор фотографии * @param server Идентификатор сервера * @param hash Хэш-сумма фотографии * @returns Информация о сохраненной фотографии или null при ошибке */ async photosSaveMessagesPhoto(photo, server, hash) { this._request.post = { photo, server, hash, }; return (await this.call('photos.saveMessagesPhoto')); } /** * Получает URL для загрузки документов в сообщения * @param peerId ID получателя сообщения * @param type Тип документа: * - 'doc': обычный документ (PDF, ZIP и т.д.) * - 'audio_message': голосовое сообщение * - 'graffiti': граффити * @returns Данные для загрузки или null при ошибке * * @example * ```ts * // Загрузка обычного документа * const server = await vk.docsGetMessagesUploadServer(12345, 'doc'); * * // Загрузка голосового сообщения * const server = await vk.docsGetMessagesUploadServer(12345, 'audio_message'); * * // Загрузка граффити * const server = await vk.docsGetMessagesUploadServer(12345, 'graffiti'); * ``` */ async docsGetMessagesUploadServer(peerId, type) { this._request.post = { peer_id: peerId, type, }; return this.call('docs.getMessagesUploadServer'); } /** * Сохраняет загруженный документ * @param file Идентификатор документа * @param title Название документа * @param tags Теги документа * @returns Информация о сохраненном документе или null при ошибке */ async docsSave(file, title, tags = null) { this._request.post = { file, title, }; if (tags) { this._request.post.tags = tags; } return this.call('docs.save'); } /** * Записывает информацию об ошибках в лог-файл * @param error Текст ошибки для логирования */ _log(error = '') { this._appContext.logError((0, constants_2.getErrorMsg)(error, 'VkRequest', this._request.url), { error: this._error, }); } } exports.VkRequest = VkRequest;