电报机器人(除了常规聊天机器人)外,还可以用作“仪表板”。身份验证已经存在,以及用于发送命令以接收特定数据的UI。另一个选择是实现一个执行一些命令并向用户发送响应的Cronjob。与其他平台相比,设置机器人的速度要快得多。
先决条件
- Telegram应用程序已安装
电报设置
查找BotFather
帐户并发送/newbot
命令。选择名称和用户名,之后,您将获得新创建的机器人的访问令牌。要为其添加默认命令,请按说明中所述的/setcommands
命令并发送命令。
开发环境的设置
引导机器人
Bottender是开发机器人的绝佳框架,它支持多个平台。从以下命令开始,然后选择平台和会话存储。使用BotFather
发送的访问令牌更新.env
文件。
npx create-bottender-app <bot-name>
cd <bot-name>
npm i express body-parser cron ngrok shelljs pino
npm i nodemon -D
公开暴露的URL
电报机器人需要Webhooks公开可用的URL。 Ngrok在Bottender启用Webhook集成时,创建了指向本地服务器的安全公共URL。要自动化此过程,必须实现自定义服务器。
服务器设置
Bellow实现启动了Cronjob和自定义服务器,并具有与隧道和Webhook URL设置的自动连接。
// server.js
const { bottender } = require('bottender');
const ngrok = require('ngrok');
const shell = require('shelljs');
const { setupCustomServer } = require('./src/custom-server');
const { logger } = require('./src/logger');
const { setupScheduler } = require('./src/scheduler');
const app = bottender({
dev: process.env.NODE_ENV !== 'production',
});
const setWebhookUrl = (url) =>
shell.exec(`npm run telegram-webhook:set ${url}/webhooks/telegram`);
const connectToTunnel = async (port) => {
const url = await ngrok.connect({
addr: port,
onStatusChange: (status) => {
switch (status) {
case 'connected': {
logger.info('Connected to tunnel...');
break;
}
case 'closed': {
logger.warn('Connection to tunnel is closed...');
logger.info('Reconnecting...');
return connectToTunnel(port);
}
}
},
});
setWebhookUrl(url);
};
(async () => {
try {
await app.prepare();
const port = Number(process.env.PORT) || 5000;
setupCustomServer(app, port);
if (process.env.NODE_ENV !== 'production') {
await connectToTunnel(port);
}
setupScheduler();
} catch (error) {
logger.error(error, 'Setting up failed...');
}
})();
Webhook的自定义服务器实现
// src/custom-server.js
const bodyParser = require('body-parser');
const express = require('express');
const { logger } = require('./logger');
const setupCustomServer = (app, port) => {
// the request handler of the bottender app
const handle = app.getRequestHandler();
const server = express();
const verify = (req, _, buf) => {
req.rawBody = buf.toString();
};
server.use(bodyParser.json({ verify }));
server.use(bodyParser.urlencoded({ extended: false, verify }));
// route for webhook request
server.all('*', (req, res) => {
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
logger.info(`Ready on http://localhost:${port}`);
});
};
module.exports = {
setupCustomServer,
};
自定义调度程序
// src/scheduler.js
const { getClient } = require('bottender');
const { CronJob } = require('cron');
const { CHAT_ID, CRONJOB_INTERVAL, replyMarkup, TIMEZONE } = require('./constants');
const { executeCustomCommand } = require('./services');
const client = getClient('telegram');
const setupScheduler = () =>
new CronJob(
CRONJOB_INTERVAL,
async function () {
const response = await executeCustomCommand();
await client.sendMessage(CHAT_ID, response, {
parseMode: 'HTML',
replyMarkup,
});
},
null,
true,
TIMEZONE,
);
module.exports = {
setupScheduler,
};
NPM脚本
// package.json
{
// ...
"scripts": {
"dev": "nodemon server.js",
"lint": "eslint . ",
"lint:fix": "npm run lint -- --fix",
"start": "node server.js",
"telegram-webhook:set": "echo 'Y' | bottender telegram webhook set -w $1",
"test": "jest"
}
// ...
}
林特
ESLINT配置中的ecmaVersion
字段更新为2021
。
记录器
const logger = require('pino')();
module.exports = {
logger,
};
机器人开发
以下是机器人入口点,可以指定多个处理程序。
// src/index.js
const { router, telegram } = require('bottender/router');
const { HandleMessage } = require('./handlers/message-handler');
module.exports = async function App() {
return router([telegram.message(HandleMessage)]);
};
Bellow是基本消息处理程序实现。限制对机器人的访问可以通过聊天ID完成。对于具有HTML内容的消息,应将parseMode
参数设置为HTML
。可以在replyMarkup
字段中添加快速答复。接收到的bot命令具有类型的bot_command
。
// src/handlers/message-handler.js
const { ADMIN_CHAT_ID } = require('../constants');
const { handleCustomLogic } = require('../services');
async function HandleMessage(context) {
const chatId = context.event._rawEvent.message?.chat?.id;
if (chatId !== ADMIN_CHAT_ID) {
await context.sendMessage('Access denied!');
return;
}
const isBotCommand = !!context.event._rawEvent.message?.entities?.find(
(entity) => entity.type === 'bot_command'
);
const message = isBotCommand
? context.event.text.replace('/', '')
: context.event.text;
const response = await handleCustomLogic(message);
await context.sendMessage(response, {
parseMode: 'HTML',
replyMarkup: {
keyboard: [
[
{
text: '/command',
},
],
],
},
});
}
module.exports = {
HandleMessage,
};
部署
部署电报机器人的选项之一是Heroku(必须将Heroku CLI作为先决条件安装)运行以下命令进行设置和部署。
// Procfile
web: npm start
heroku create -a <PROJECT_NAME>
git init
heroku git:remote -a <PROJECT_NAME>
git add .
git commit -m "Initial commit"
git push heroku master
heroku config:set TELEGRAM_ACCESS_TOKEN=<ACCESS_TOKEN>
npm run telegram:webhook-set https://<PROJECT_NAME>.herokuapp.com/webhooks/telegram