vvlad1973-telegram-framework
Version:
Current version: *7.9.5*
376 lines (326 loc) • 13.2 kB
JavaScript
;
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
);
}
*/