Телеграм-бот на NodeJS. 4. Развёртывание на Amazon web service (AWS).
Tags: telegram, node, aws
Published: 2021-01-04 12:48:26

У нашего бота есть один недостаток: Как только мы прервём выполнение скрипта, то бот перестанет работать. Поэтому неплохо было бы опубликовать его на каком-нибудь сервере, который поддерживает работу с Node.JS. В этой заметке будет описана работа с [AWS](https://aws.amazon.com/ru/) . Я предполагаю, что Вы уже зарегистрировались на этом ресурсе, у Вас все секретные ключи. Если нет, то [вот здесь](https://www.msp360.com/resources/blog/how-to-find-your-aws-access-key-id-and-secret-access-key/) описано, как его получить. У меня есть безплатный ключ скором на один год, а дальше посмотрим, как сложится.
После получения ключа установите пакет 
```
npm install -g serverless
```
Запишите этот ключ:
```
serverless config credentials --provider provider --key key --secret secret
```
Следующий шаг: создание функции AWS Lambda, которая будет запускаться через Telegram HTTP webhook. Эта функция будет отвечать за вызов Telegram API отправку результата пользователю. Чтобы создать лямбда-функцию, просто создайте новую папку на компьютере, перейдите внутрь нее, откройте окно терминала и введите следующее:
```
serverless create --template aws-nodejs
```
Как вы, вероятно, догадались, это создаст очень простой шаблон для будущих функций Node.js . Шаблон фактически состоит из двух файлов: handler.js и serverless.yml. handler.js - точка ввода кода функции, а serverless.yml - файл конфигурации сервера, в котором можно объявить триггер сервера и другие параметры. Больше прочитать о конфигурации - [ссылка](https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/) .
Вот как я предлагаю настроить будущий сервер:
```
service: short-bot

useDotenv: true

plugins:
  - serverless-dotenv-plugin

frameworkVersion: "2"

provider:
  name: aws
  runtime: nodejs12.x

  region: eu-west-1

  apiGateway:
    shouldStartNameWithService: true
  lambdaHashingVersion: "20201221"

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: webhook
          method: post
          cors: true

```
В каталоге этого проекта сделайте команды:
```
npm init -y
npm i --save dotenv node-fetch telegraf
npm i --save-dev serverless serverless-dotenv-plugin
```
Мы сейчас сделали очень многое: сделали шаблон проекта, который можно будет опубликовать на амазоне. Для публикации нам понадобится пакет serverless, а для разработки - serverless-dotenv-plugin, который поможет нам во время развертывания подхватывать переменные из файла .env.
Теперь в этот проект скопируйте все файлы из каталога, где у нас был телеграм-бот и давайте немного изменим файл handler.js:
```js
"use strict";

const { bot } = require("./bot.js");
const { getResponseHeaders } = require("./lib/common");

exports.getResponseHeaders = () => {
  return {
    "Access-Control-Allow-Origin": "*",
  };
};

/**
 * Вебхук для бота
 */
module.exports.hello = async (event) => {
  try {
    let body =
      event.body[0] === "{"
        ? JSON.parse(event.body)
        : JSON.parse(Buffer.from(event.body, "base64"));
    await bot.handleUpdate(body);
    return { statusCode: 200, body: "" };
  } catch (err) {
    return {
      statusCode: err.statusCode ? err.statusCode : 500,
      headers: getResponseHeaders(),
      body: JSON.stringify({
        error: err.name ? err.name : "Exception",
        message: err.message ? err.message : "Unknown error",
      }),
    };
  }
};

/**
 * Устновка веб-хука.
 * Если вызвать этот метод, то хук вступит в силу
 */
module.exports.setWebhook = async (event) => {
  try {
    const url = `https://${event.headers.Host}/${event.requestContext.stage}/webhook`;
    await bot.telegram.setWebhook(url);
    return {
      statusCode: 200,
      headers: getResponseHeaders(),
      body: JSON.stringify({ url }),
    };
  } catch (err) {
    return {
      statusCode: err.statusCode ? err.statusCode : 500,
      headers: getResponseHeaders(),
      body: JSON.stringify({
        error: err.name ? err.name : "Exception",
        message: err.message ? err.message : "Unknown error",
      }),
    };
  }
};
```

Функция getResponseHeaders формирует заголовки ответа.
Функция hello, о которой говорилось в файле serverless.yml это и есть тот самый веб-хук, который будет отвечать за работу нашего бота.
Функция setWebhook - это метод, который привязывает веб-хук к боту. Как вы поняли, ключевые строки в нём это 
```js
1 const url = `https://${event.headers.Host}/${event.requestContext.stage}/webhook`;
2 bot.telegram.setWebhook(url);
```
В первой строке мы получаем url нашего метода, когда он будет опубликован, вторая вызывает метод API телеграмм-бота.
Для публикации нужно слегка изменить файл bot.js. Поскольку наш бот будет теперь запущен не на локальной машине, нужно закомментировать строку `bot.launch();` и ниже написать:
```js
module.exports = {
  bot,
};
```
У себя в проекте файл bot.js я переместил в каталог telegramBot, изменил пути в require.
Далее в секции scripts в package.json добавим:
```
{
  "deploy": "sls deploy",
  "logs": "sls logs --function hello -t"
}
```
С помощью команды `npm run local` можно будет запустить функцию локально, `deploy` - задеплоить в amazon, `logs` - для вывода потока логов в консоль.
#### Деплой
Командой `npm run deploy` можно задеплоить функцию в AWS. В терминале вы будете видеть весь процесс деплоя лямбды (все файлы складываются в zip архив и заливаются в S3). В итоге вы получите постоянный эндпоинт, что-то типа: https://sg2bxp8khj.execute-api.us-east-2.amazonaws.com/dev/, его нужно установить в качестве вебхука для телеграма. 
Для установки хука нужно отправить POST-запрос на адрес функции SetWebhook, который мы получили после развёртывания:
![setWebhook](https://dev-to-uploads.s3.amazonaws.com/i/bsmt0gcq85itvf2hsen6.png)
Запрос можно отправить используя команду `curl -X POST https://address` либо используя программу Postman. Если всё прошло без ошибок, то Ваш бот теперь обосновался на сервере амазон, поздравляю!

#### Ссылки
Вот какие материалы мне помогли в развёртывании на амазоне:
* https://amorgunov.com/posts/2019-03-26-create-telegram-echo-bot-with-serverless/
* https://muhannad0.github.io/post/serverless-telegram-bot-on-aws/
* https://iamondemand.com/blog/building-your-first-serverless-telegram-bot/