UNPKG

vvlad1973-telegram-framework

Version:
376 lines (326 loc) 13.2 kB
'use strict'; import FormData from 'form-data'; import fs from 'fs'; import { format as f } from 'util'; import got from 'got'; import { getValueByPathExt } from '@vvlad1973/utils'; import { TelegramBotApiMethodsWithMedia, MediaProperties, StatusCodes, UserLinks, UpdateTypes, MessageTypes, } from '../classes/enums.js'; const COMMAND_PATTERN = /^[\\/]([^@\s]+)(@([\S]+))?( (.*))?$/; const COMMAND_PART_INDEX = 1; const PARAMS_PART_INDEX = 5; const BOT_NAME_PART_INDEX = 3; export function parseCommand(string) { let result; if (typeof string === 'string') { let parts = string.match(COMMAND_PATTERN); if ( Array.isArray(parts) && parts.length > Math.max(COMMAND_PART_INDEX, PARAMS_PART_INDEX, BOT_NAME_PART_INDEX) ) { result = { command: parts[COMMAND_PART_INDEX], params: parts[PARAMS_PART_INDEX] ? parts[PARAMS_PART_INDEX] : '', botName: parts[BOT_NAME_PART_INDEX] ? parts[BOT_NAME_PART_INDEX] : '', }; } } return result; } export function getMessageType(message) { let result; if (typeof message === 'object') { result = UpdateTypes.MESSAGE; if (message.text) result = MessageTypes.TEXT; else if (message.photo) result = MessageTypes.PHOTO; else if (message.video) result = MessageTypes.VIDEO; else if (message.audio) result = MessageTypes.AUDIO; else if (message.document) result = MessageTypes.DOCUMENT; else if (message.animation) result = MessageTypes.ANIMATION; else if (message.voice) result = MessageTypes.VOICE; else if (message.video_note) result = MessageTypes.VIDEO_NOTE; else if (message.sticker) result = MessageTypes.STICKER; else if (message.location) result = MessageTypes.LOCATION; else if (message.poll) result = MessageTypes.POLL; else if (message.contact) result = MessageTypes.CONTACT; else if (message.dice) result = MessageTypes.DICE; else if (message.game) result = MessageTypes.GAME; else if (message.venue) result = MessageTypes.VENUE; else if (message.new_chat_members) result = MessageTypes.NEW_CHAT_MEMBER; else if (message.left_chat_members) result = MessageTypes.LEFT_CHAT_MEMBER; else if (message.invoice) result = MessageTypes.INVOICE; else if (message.pinned_message) result = MessageTypes.PINNED_MESSAGE; else if (message.successful_payment) result = MessageTypes.SUCCESSFUL_PAYMENT; else if (message.web_app_data) result = MessageTypes.WEB_APP_DATA; else if (message.migrate_chat) result = MessageTypes.MIGRATE_CHAT; else if (message.passport_data) result = MessageTypes.PASSPORT_DATA; } return result; } export function getFileId(object = {}) { let result; if (object.video) result = object.video.file_id; else if (object.video_note) result = object.video_note.file_id; else if (object.audio) result = object.audio.file_id; else if (object.document) result = object.document.file_id; else if (object.photo) result = object.photo[object.photo.length - 1].file_id; else if (object.voice) result = object.voice.file_id; else if (object.animation) result = object.animation.file_id; else if (object.sticker) result = object.sticker.file_id; return result; } // export function createFormData(data) { // let form = new FormData(); // if (Object.values(TelegramBotApiMethodsWithMedia).includes(data.method)) { // for (let item of Object.values(MediaProperties)) { // if (item === MediaProperties.MEDIA && data[item]) // for (let mediaItem of data[item]) { // if (mediaItem.media?.file) { // let fileName = mediaItem.media.file; // mediaItem.media.blob = fs.readFileSync(fileName); // } // if (mediaItem.thumbnail?.file) { // let fileName = mediaItem.thumbnail.file; // mediaItem.thumbnail.blob = fs.readFileSync(fileName); // } // } // else if (Object.keys(data).includes(item) && data[item].file) { // let fileName = data[item].file; // data[item].blob = fs.readFileSync(fileName); // } // } // } // for (let key of Object.keys(data)) { // if (key === MediaProperties.MEDIA) { // for (let [index, mediaItem] of data[key].entries()) { // if (typeof mediaItem.media === 'object') { // let mediaId = `media.${mediaItem.type}.${index}`; // form.append(mediaId, mediaItem.media.blob, mediaItem.media.file); // mediaItem.media = `attach://${mediaId}`; // } // if (typeof mediaItem.thumbnail === 'object') { // let thumbnailId = `media.${mediaItem.type}.thumb.${index}`; // form.append(thumbnailId, mediaItem.thumbnail.blob, mediaItem.thumbnail.file); // mediaItem.thumbnail = `attach://${thumbnailId}`; // } // } // form.append(key, JSON.stringify(data[key])); // } else if (typeof data[key]?.file === 'string') { // form.append(key, data[key].blob, data[key].file); // } else if (data[key]) { // if (typeof data[key] === 'object') { // form.append(key, JSON.stringify(data[key])); // } else { // form.append(key, String(data[key])); // } // } // } // return form; // } export function createFormData(data) { const form = new FormData(); if (Object.values(TelegramBotApiMethodsWithMedia).includes(data.method)) { for (const item of Object.values(MediaProperties)) { if (item === MediaProperties.MEDIA && data[item]) { for (const mediaItem of data[item]) { // media if (mediaItem.media?.buffer && mediaItem.media.filename) { mediaItem.media.blob = mediaItem.media.buffer; mediaItem.media.contentType = mediaItem.media.contentType || 'application/octet-stream'; } else if (mediaItem.media?.file) { const fileName = mediaItem.media.file; mediaItem.media.blob = fs.readFileSync(fileName); mediaItem.media.filename = fileName; mediaItem.media.contentType = 'application/octet-stream'; } // thumbnail if (mediaItem.thumbnail?.buffer && mediaItem.thumbnail.filename) { mediaItem.thumbnail.blob = mediaItem.thumbnail.buffer; mediaItem.thumbnail.contentType = mediaItem.thumbnail.contentType || 'application/octet-stream'; } else if (mediaItem.thumbnail?.file) { const fileName = mediaItem.thumbnail.file; mediaItem.thumbnail.blob = fs.readFileSync(fileName); mediaItem.thumbnail.filename = fileName; mediaItem.thumbnail.contentType = 'application/octet-stream'; } } } else if (data[item]) { if (data[item].buffer && data[item].filename) { data[item].blob = data[item].buffer; data[item].contentType = data[item].contentType || 'application/octet-stream'; } else if (data[item].file) { const fileName = data[item].file; data[item].blob = fs.readFileSync(fileName); data[item].filename = fileName; data[item].contentType = 'application/octet-stream'; } } } } for (const key of Object.keys(data)) { if (key === MediaProperties.MEDIA) { for (const [index, mediaItem] of data[key].entries()) { if (typeof mediaItem.media === 'object') { const mediaId = `media.${mediaItem.type}.${index}`; form.append(mediaId, mediaItem.media.blob, { filename: mediaItem.media.filename, contentType: mediaItem.media.contentType, }); mediaItem.media = `attach://${mediaId}`; } if (typeof mediaItem.thumbnail === 'object') { const thumbnailId = `media.${mediaItem.type}.thumb.${index}`; form.append(thumbnailId, mediaItem.thumbnail.blob, { filename: mediaItem.thumbnail.filename, contentType: mediaItem.thumbnail.contentType, }); mediaItem.thumbnail = `attach://${thumbnailId}`; } } form.append(key, JSON.stringify(data[key])); } else if (data[key]?.blob && data[key]?.filename) { form.append(key, data[key].blob, { filename: data[key].filename, contentType: data[key].contentType || 'application/octet-stream', }); } else if (data[key]) { form.append( key, typeof data[key] === 'object' ? JSON.stringify(data[key]) : String(data[key]) ); } } return form; } export function formatUserUrl(userId, username, templates = UserLinks) { let result; if (username) result = f(UserLinks.USERNAME, username); else if (userId) result = f(UserLinks.USER_ID, userId); return result; } export function getGotInstance() { const instance = got.extend({ handlers: [ (options, next) => { Error.captureStackTrace(options.context); return next(options); }, ], hooks: { beforeError: [ (error) => { error.source = error.options.context.stack.split('\n'); return error; }, ], }, }); return instance; } export function sendPostRequest(url, data, instance) { return new Promise(async (resolve, reject) => { let response; let result; try { response = await instance.post(url, data); if (data?.payload?.audio?.blob) data.payload.audio.blob = '<blob>'; if (data?.payload?.video?.blob) data.payload.video.blob = '<blob>'; if (data?.payload?.voice?.blob) data.payload.audio.voice = '<blob>'; if (data?.payload?.video_note?.blob) data.payload.video_note.blob = '<blob>'; if (data?.payload?.photo?.blob) data.payload.photo.blob = '<blob>'; if (data?.payload?.document?.blob) data.payload.document.blob = '<blob>'; if (data?.payload?.animation?.blob) data.payload.animation.blob = '<blob>'; if (data?.payload?.thumbnail?.blob) data.payload.thumbnail.blob = '<blob>'; result = { result: { ok: true, code: StatusCodes.OK, }, response: response.body, request: data, }; return resolve(result); } catch (error) { result = { message: error.response?.body?.description, result: { ok: false, code: error.response?.body?.error_code, description: error.response?.body?.description, }, response: error.response?.body, request: data, error: error, }; return reject(result); } }); } /** * Replaces placeholders in the template string with corresponding values from strings or data * @param {string} template - The template string containing placeholders like {{KEY}} * @param {Object} strings - An object containing predefined string resources * @param {Object} data - An object containing variable values, including nested properties (async supported) * @returns {Promise<string>} - A promise resolving to the formatted string with replaced values */ export async function replaceTemplate(template, strings, data) { // const matches = [...template.matchAll(/\{\{([\w.\[\]('"0-9\s]+)\}\}/g)]; const matches = [...template.matchAll(/\{\{([^}]+)\}\}/g)]; const replacements = await Promise.all( matches.map(async ([placeholder, path]) => { // Если ключ есть в strings — используем его напрямую if (typeof strings[path] === 'string') { return { placeholder, value: strings[path] }; } // Используем getValueByPath с поддержкой сложных путей и вызовов const value = await getValueByPathExt(data, path); return { placeholder, value: value !== undefined ? value : placeholder, }; }) ); return replacements.reduce( (str, { placeholder, value }) => str.replace(placeholder, value), template ); } /* export async function replaceTemplate(template, strings, data) { const matches = [...template.matchAll(/\{\{([\w.]+)\}\}/g)]; const replacements = await Promise.all( matches.map(async ([placeholder, path]) => { if (typeof strings[path] === 'string') { return { placeholder, value: strings[path] }; } const value = await path.split('.').reduce(async (obj, key) => { const resolvedObj = await obj; return resolvedObj && resolvedObj[key] !== undefined ? resolvedObj[key] : `{{${path}}}`; }, data); return { placeholder, value }; }) ); return replacements.reduce( (str, { placeholder, value }) => str.replace(placeholder, value), template ); } */