
Подробнее о хостинге для размещения Телеграм бота можно узнать из статьи
Ранее мной был написан бот обратной связи на PHP, статья про него есть в ленте на сайте. Сейчас я практикуюсь в Node.js и решил переписать бот с использованием "Современного фреймворка для Телеграм Бот на Node.js" это Telegraf.js. Принцип работы бота остался тем же.
Не стал разбивать на отдельные файлы весь код, для наглядности оставил в одном листинге.
В настройках необходимо указать свои параметры, так как бот будет работать через webHook, то нужно указать путь до сертификатов для https соединения.
Ниже приведены 3 варианта с использованием бота через webHook и вариант через getUpdates
//////////////////////
//// Запускаем webHook
//////////////////////
// Подключаем модули
let fs = require('fs');
let Telegraf = require('telegraf');
/**
* Настройки
* @type token: string - Токен бота
* @type path: string - относительный путь до директории с сертификатами
* @type key: string - приватный ключ
* @type cert: string - сертификат сервера
* @type ca: string - сертификат клиента
* @type port: number - порт
* @type domain: string - домен
* @type whpath: string - путь
* @type admin: number - id владельца бота
*/
let config = {
"token": "YOUR_TOKEN",
"path": "./certs/",
"key": "file.key",
"cert": "file.crt",
"ca": "file.ca",
"port": 8443,
"domain": "domain.com",
"whpath": "/secret-path",
"admin": 123456789
};
// Создаем объект Telegraf.js
let bot = new Telegraf(config.token);
// TLS options
let tlsOptions = {
key: fs.readFileSync(config.path + config.key),
cert: fs.readFileSync(config.path + config.cert),
ca: [
// This is necessary only if the client uses the self-signed certificate.
fs.readFileSync(config.path + config.ca)
]
};
// Установливаем webHook
bot.telegram.setWebhook('https://' + config.domain + ':' + config.port + config.whpath);
// Запускаем https webhook
bot.startWebhook(config.whpath, tlsOptions, config.port);
/**
* Значения текстовых ответов
* @type helloAdmin: string - Приветствие для админа
* @type helloUser: string - Приветствие для пользователя
* @type replyWrong: string - Если админ написал сам себе, уведомляем его
*/
let replyText = {
"helloAdmin": "Привет админ, ждем сообщения от пользователей",
"helloUser": "Приветствую, отправьте мне сообщение. Постараюсь ответить в ближайшее время.",
"replyWrong": "Для ответа пользователю используйте функцию Ответить/Reply."
};
/**
* Проверяем пользователя на права
* @param userId {number}
* @returns {boolean}
*/
let isAdmin = (userId) => {
return userId == config.admin;
};
/**
* Перенаправляем админу от пользователя или уведомляем админа об ошибке
* @param ctx
*/
let forwardToAdmin = (ctx) => {
if (isAdmin(ctx.message.from.id)) {
ctx.reply(replyText.replyWrong);
} else {
ctx.forwardMessage(config.admin, ctx.from.id, ctx.message.id);
}
};
/**
* Старт бота
*/
bot.start((ctx) => {
ctx.reply(isAdmin(ctx.message.from.id)
? replyText.helloAdmin
: replyText.helloUser);
});
//////////////////////
//// Основа 1
//////////////////////
/**
* Текст
*/
bot.on('text', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendMessage(
ctx.message.reply_to_message.forward_from.id,
ctx.message.text
);
} else {
forwardToAdmin(ctx);
}
});
/**
* Стикер
*/
bot.on('sticker', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendSticker(
ctx.message.reply_to_message.forward_from.id,
ctx.message.sticker.file_id
);
} else {
forwardToAdmin(ctx);
}
});
/**
* 1 фотография - не медиагруппа
*/
bot.on('photo', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
let file = ctx.message.photo.length - 1;
ctx.telegram.sendPhoto(
ctx.message.reply_to_message.forward_from.id,
ctx.message.photo[file].file_id,
{
'caption': ctx.message.caption
});
} else {
forwardToAdmin(ctx);
}
});
/**
* Документ
*/
bot.on('document', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendDocument(
ctx.message.reply_to_message.forward_from.id,
ctx.message.document.file_id,
{
'caption': ctx.message.caption
});
} else {
forwardToAdmin(ctx);
}
});
/**
* Голосовая заметка
*/
bot.on('voice', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendVoice(
ctx.message.reply_to_message.forward_from.id,
ctx.message.voice.file_id,
{
'caption': ctx.message.caption
});
} else {
forwardToAdmin(ctx);
}
});
/**
* Видео заметка
*/
bot.on('video_note', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendVideoNote(
ctx.message.reply_to_message.forward_from.id,
ctx.message.video_note.file_id
);
} else {
forwardToAdmin(ctx);
}
});
/**
* 1 видео ролик - не медиагруппа
*/
bot.on('video', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendVideo(
ctx.message.reply_to_message.forward_from.id,
ctx.message.video.file_id,
{
'caption': ctx.message.caption
}
);
} else {
forwardToAdmin(ctx);
}
});
/**
* Аудио ролик
*/
bot.on('audio', (ctx) => {
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
ctx.telegram.sendAudio(
ctx.message.reply_to_message.forward_from.id,
ctx.message.audio.file_id,
{
'caption': ctx.message.caption
});
} else {
forwardToAdmin(ctx);
}
});
Упрощаем код, ставим прослушку на общий метод Message. В соответствиис подтипом сообщения вызывая нужный метод отправляем сообщение пользователю.
//////////////////////
//// ... Здесь запускаем webHook из первого варианта
//////////////////////
//////////////////////
//// Основа 2
//////////////////////
/**
* Слушаем на наличие объекта message
*/
bot.on('message', (ctx) => {
// убеждаемся что это админ ответил на сообщение пользователя
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
// кому отправляем
let userId = ctx.message.reply_to_message.forward_from.id;
// проверяем что пришло и отправляем соответствующим методом
switch (ctx.updateSubTypes[0]) {
case 'text':
ctx.telegram.sendMessage(
userId,
ctx.message.text
);
break;
case 'sticker':
ctx.telegram.sendSticker(
userId,
ctx.message.sticker.file_id
);
break;
case 'photo':
let file = ctx.message.photo.length - 1;
ctx.telegram.sendPhoto(
userId,
ctx.message.photo[file].file_id,
{
'caption': ctx.message.caption
}
);
break;
case 'document':
ctx.telegram.sendDocument(
userId,
ctx.message.document.file_id,
{
'caption': ctx.message.caption
}
);
break;
case 'voice':
ctx.telegram.sendVoice(
userId,
ctx.message.voice.file_id,
{
'caption': ctx.message.caption
}
);
break;
case 'video_note':
ctx.telegram.sendVideoNote(
userId,
ctx.message.video_note.file_id
);
break;
case 'video':
ctx.telegram.sendVideo(
userId,
ctx.message.video.file_id,
{
'caption': ctx.message.caption
}
);
break;
case 'audio':
ctx.telegram.sendAudio(
userId,
ctx.message.audio.file_id,
{
'caption': ctx.message.caption
}
);
break;
default:
console.log('other');
}
} else {
forwardToAdmin(ctx);
}
});
Максимально упростим код и используя метод sendCopy - просто отправляем копию сообщения от админа пользователю.
//////////////////////
//// ... Здесь запускаем webHook из первого варианта
//////////////////////
//////////////////////
//// Основа 3
//////////////////////
/**
* Слушаем на наличие объекта message
*/
bot.on('message', (ctx) => {
// убеждаемся что это админ ответил на сообщение пользователя
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
// отправляем копию пользователю
ctx.telegram.sendCopy(ctx.message.reply_to_message.forward_from.id, ctx.message);
} else {
// перенаправляем админу
forwardToAdmin(ctx);
}
});
Этот вариант можно запустить без настройки webHook, также не нужны домен и ssl-сертификат. Его можно спокойно запустить на локальной машине, при необходимости можно настроить соединение через прокси.
Файл index.js
// Подключаем модули
const Telegraf = require('telegraf');
// const HttpsProxyAgent = require('https-proxy-agent');
// Общие настройки
let config = {
"token": "YOUR_TOKEN", // Токен бота
"admin": 0 // id владельца бота
};
// Создаем объект бота
const bot = new Telegraf(config.token, {
// Если надо ходить через прокси - укажите: user, pass, host, port
// telegram: { agent: new HttpsProxyAgent('http://user:pass@host:port') }
}
);
// Текстовые настройки
let replyText = {
"helloAdmin": "Привет админ, ждем сообщения от пользователей",
"helloUser": "Приветствую, отправьте мне сообщение. Постараюсь ответить в ближайшее время.",
"replyWrong": "Для ответа пользователю используйте функцию Ответить/Reply."
};
// Проверяем пользователя на права
let isAdmin = (userId) => {
return userId == config.admin;
};
// Перенаправляем админу от пользователя или уведомляем админа об ошибке
let forwardToAdmin = (ctx) => {
if (isAdmin(ctx.message.from.id)) {
ctx.reply(replyText.replyWrong);
} else {
ctx.forwardMessage(config.admin, ctx.from.id, ctx.message.id);
}
};
// Старт бота
bot.start((ctx) => {
ctx.reply(isAdmin(ctx.message.from.id)
? replyText.helloAdmin
: replyText.helloUser);
});
// Слушаем на наличие объекта message
bot.on('message', (ctx) => {
// убеждаемся что это админ ответил на сообщение пользователя
if (ctx.message.reply_to_message
&& ctx.message.reply_to_message.forward_from
&& isAdmin(ctx.message.from.id)) {
// отправляем копию пользователю
ctx.telegram.sendCopy(ctx.message.reply_to_message.forward_from.id, ctx.message);
} else {
// перенаправляем админу
forwardToAdmin(ctx);
}
});
// запускаем бот
bot.launch();
Файл package.json
{
"name": "telegramFeedBack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "iMakeBots.ru",
"license": "",
"dependencies": {
"https-proxy-agent": "^2.2.1",
"telegraf": "^3.26.0"
}
}
Авторизуйтесь через Telegram, чтобы оставить комментарий.
Откройте бот @SiteAuthBot,
нажмите кнопку Старт/Start. Следуйте инструкциям бота.