Alojamiento: Heroku

Asumimos que tienes los conocimientos básicos sobre la creación de bots usando grammY. Si aún no estás preparado, ¡no dudes en dirigirte a nuestra amigable Guía! :cohete:

Este tutorial te guiará en cómo desplegar un bot de Telegram en Herokuopen in new window usando webhooks o long polling. También asumimos que ya tienes una cuenta en Heroku.

Requisitos previos

Primero, instala algunas dependencias:

# Crear un directorio de proyecto.
mkdir grammy-bot
cd grammy-bot
npm init --y

# Instalar las dependencias principales.
npm install grammy express

# Instala las dependencias de desarrollo.
npm install -D typescript @types/express @types/node

# Crear la configuración de TypeScript.
npx tsc --init

Almacenaremos nuestros archivos TypeScript dentro de una carpeta src, y nuestros archivos compilados en una carpeta dist. Crea las carpetas en el directorio raíz del proyecto. Luego, dentro de la carpeta src, crea un nuevo archivo llamado bot.ts. Nuestra estructura de carpetas debería ser así:

.
├── node_modules/
├── dist/
├── src/
│   └── bot.ts
├── package.json
├── package-lock.json
└── tsconfig.json

Después, abre tsconfig.json y cámbialo para usar esta configuración:

{
  "compilerOptions": {
    "target": "ESNEXT",
    "module": "esnext", // cambiado de commonjs a esnext
    "lib": ["ES2021"],
    "outDir": "./dist/",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src"]
}



 










Debido a que la opción module anterior se ha establecido de commonjs a esnext, tenemos que añadir "type": "module" a nuestro package.json. Nuestro package.json debería ser ahora similar a esto:

{
  "name": "grammy-bot",
  "version": "0.0.1",
  "description": "",
  "main": "dist/app.js",
  "type": "module", // añadir propiedad "type": "module"
  "scripts": {
    "dev-build": "tsc"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "grammy": "^1.2.0",
    "express": "^4.17.1"
  },
  "devDependencies": {
    "typescript": "^4.3.5",
    "@types/express": "^4.17.13",
    "@types/node": "^16.3.1"
  },
  "keywords": []
}





 
















Como hemos mencionado anteriormente, tenemos dos opciones para recibir datos de Telegram: los webhooks y el long polling. ¡Puedes aprender más sobre las dos ventajas y luego decidir cuál es la adecuada en estos increíbles consejos!

Webhooks

Si decides usar el long polling en su lugar, puedes saltarte esta sección y pasar a la sección sobre long polling. 🚀

En resumen, a diferencia del long polling, los webhooks no se ejecutan continuamente para comprobar los mensajes entrantes de Telegram. Esto reducirá la carga del servidor y nos ahorrará un montón de horas de dynoopen in new window, especialmente si utiliza el plan Eco. 😁

Bien, ¡continuemos! ¿Recuerdas que hemos creado bot.ts antes? No vamos a volcar todo el código allí, y dejar la codificación del bot hasta usted. En su lugar, vamos a hacer que app.ts sea nuestro principal punto de entrada. Eso significa que cada vez que Telegram (o cualquier otra persona) visite nuestro sitio, express decide qué parte de tu servidor será responsable de manejar la petición. Esto es útil cuando estás desplegando tanto el sitio web como el bot en el mismo dominio. Además, al dividir los códigos en diferentes archivos, hace que nuestro código se vea ordenado. ✨

Express y su Middleware

Ahora crea app.ts dentro de la carpeta src y escribe este código dentro:

import express from "express";
import { webhookCallback } from "grammy";
import { bot } from "./bot";

const domain = String(process.env.DOMAIN);
const secretPath = String(process.env.BOT_TOKEN);
const app = express();

app.use(express.json());
app.use(`/${secretPath}`, webhookCallback(bot, "express"));

app.listen(Number(process.env.PORT), async () => {
  // ¡Asegúrate de que es `https` y no `http`!
  await bot.api.setWebhook(`https://${domain}/${secretPath}`);
});

Echemos un vistazo a nuestro código anterior:

  • process.env: Recuerda, ¡nunca almacenes credenciales en nuestro código! Para crear variables de entornoopen in new window en Heroku, dirígete a esta guíaopen in new window.
  • secretPath: Puede ser nuestro BOT_TOKEN o cualquier cadena aleatoria. Es una buena práctica ocultar la ruta de nuestro bot, tal y como se explica en Telegram (https://core.telegram.org/bots/api#setwebhook).

⚡ Optimización (opcional)

bot.api.setWebhook en la línea 14 siempre se ejecutará cuando Heroku inicie su servidor de nuevo. Para los bots de bajo tráfico, esto será para cada solicitud. Sin embargo, no necesitamos que este código se ejecute cada vez que llega una petición. Por lo tanto, podemos eliminar esta parte completamente, y ejecutar el GET sólo una vez manualmente. Abre este enlace en tu navegador web después de desplegar nuestro bot:

https://api.telegram.org/bot<bot_token>/setWebhook?url=<webhook_url>

Ten en cuenta que algunos navegadores requieren que codifiques manualmente (https://en.wikipedia.org/wiki/Percent-encoding#Reserved_characters) la webhook_url antes de pasarla. Por ejemplo, si tenemos el token bot abcd:1234 y la URL https://grammybot.herokuapp.com/secret_path, entonces nuestro enlace debería tener este aspecto:

https://api.telegram.org/botabcd:1234/setWebhook?url=https%3A%2F%2Fgrammybot.herokuapp.com%2Fsecret_path

Optimización (opcional)

Utilice Webhook Reply para una mayor eficiencia.

Creando bot.ts

Siguiente paso, dirígete a bot.ts:

import { Bot } from "grammy";

if (process.env.BOT_TOKEN == null) throw Error("Falta BOT_TOKEN.");
export const bot = new Bot(`${process.env.BOT_TOKEN}`);

bot.command("start", (ctx) => ctx.reply("¡Hola!"));
bot.on("message", (ctx) => ctx.reply("¡Tengo otro mensaje!"));

Bien. Ya hemos terminado de codificar nuestros archivos principales. Pero antes de ir a los pasos de despliegue, podemos optimizar nuestro bot un poco. Como siempre, esto es opcional.

⚡ Optimización (opcional)

Cada vez que tu servidor se inicie, grammY solicitará información sobre el botopen in new window a Telegram para proporcionarla en el objeto de contexto bajo ctx.me. Podemos establecer la información sobre el botopen in new window para evitar un exceso de llamadas a getMe.

  1. Abre este enlace https://api.telegram.org/bot<bot_token>/getMe en tu navegador web favorito. Se recomienda usar Firefoxopen in new window ya que muestra muy bien el formato json.
  2. Cambia nuestro código en la línea 4 de arriba y rellena el valor de acuerdo con los resultados de getMe:
export const bot = new Bot(`${process.env.BOT_TOKEN}`, {
  botInfo: {
    id: 111111111,
    is_bot: true,
    first_name: "xxxxxxxxx",
    username: "xxxxxxbot",
    can_join_groups: true,
    can_read_all_group_messages: false,
    supports_inline_queries: false,
  },
});

¡Genial! ¡Es hora de preparar nuestro entorno de despliegue! ¡Directamente a la Sección de Despliegue todo el mundo! 💪

Long Polling

Su script se ejecutará de forma continua cuando utilice el sondeo largo

A menos que sepa cómo manejar este comportamiento, asegúrese de que tiene suficientes horas de dynoopen in new window.

¿Considerar el uso de webhooks? Vaya a la sección webhooks. 🚀

Usar long polling en tu servidor no es siempre una mala idea. A veces, es adecuado para los bots de recolección de datos que no necesitan responder rápidamente y manejar muchos datos. Si quieres hacerlo una vez por hora, puedes hacerlo fácilmente. Eso es algo que no puedes controlar con los webhooks. Si tu bot se inunda de mensajes, verás muchas peticiones de webhooks, sin embargo, puedes limitar más fácilmente la tasa de actualizaciones a procesar con un long polling.

Creando bot.ts

Abramos el archivo bot.ts que hemos creado anteriormente. Que contenga estas líneas de código:

import { Bot } from "grammy";

if (process.env.BOT_TOKEN == null) throw new Error("Falta BOT_TOKEN.");
const bot = new Bot(process.env.BOT_TOKEN);

bot.command(
  "start",
  (ctx) => ctx.reply("¡Estoy corriendo en Heroku usando long polling!"),
);

bot.start();

¡Ya está! Estamos listos para desplegarlo. Bastante sencillo, ¿verdad? 😃 Si crees que es demasiado fácil, ¡consulta nuestra Lista de verificación de despliegue! 🚀

Despliegue

No… nuestro Rocket Bot no está listo para ser lanzado todavía. ¡Completa estas etapas primero!

Compilar Archivos

Ejecute este código en su terminal para compilar los archivos TypeScript a JavaScript:

npx tsc

Si se ejecuta con éxito y no imprime ningún error, nuestros archivos compilados deberían estar en la carpeta dist con extensiones .js.

Configurar el Procfile

Por el momento, Heroku tiene varios tipos de dynosopen in new window. Dos de ellos son:

  • Web dynos:
    Web dynos son dynos del proceso “web” que reciben tráfico HTTP de los routers. Este tipo de dyno tiene un tiempo de espera de 30 segundos para ejecutar código. Además, se suspenderá si no hay ninguna petición que atender en un periodo de 30 minutos. Este tipo de dyno es muy adecuado para los webhooks.

  • Worker dynos:
    Worker dynos se utilizan normalmente para trabajos en segundo plano. NO tiene un tiempo de espera, y NO dormirá si no maneja ninguna petición web. Se adapta al long polling.

Crear un archivo llamado Procfile sin extensión de archivo en el directorio raíz de nuestro proyecto. Por ejemplo, Procfile.txt y procfile no son válidos. A continuación, escriba este formato de código de una sola línea:

<tipo de dyno>: <omando para ejecutar nuestro archivo de entrada principal>

Para nuestro caso debería serlo:

web: node dist/app.js
worker: node dist/bot.js

Configurar Git

Vamos a desplegar nuestro bot usando Git y Heroku Cliopen in new window. Aquí está el enlace para la instalación:

Suponiendo que ya los tienes en tu máquina, y tienes una terminal abierta en la raíz del directorio de nuestro proyecto. Ahora inicializa un repositorio git local ejecutando este código en tu terminal:

git init

A continuación, tenemos que evitar que los archivos innecesarios lleguen a nuestro servidor de producción, en este caso Heroku. Crea un archivo llamado .gitignore en la raíz del directorio de nuestro proyecto. Luego añade esta lista:

node_modules/
src/
tsconfig.json

Nuestra estructura final de carpetas debería tener este aspecto:

.
├── .git/
├── node_modules/
├── dist/
│   ├── bot.js
│   └── app.js
├── src/
│   ├── bot.ts
│   └── app.ts
├── package.json
├── package-lock.json
├── tsconfig.json
├── Procfile
└── .gitignore
.
├── .git/
├── node_modules/
├── dist/
│   └── bot.js
├── src/
│   └── bot.ts
├── package.json
├── package-lock.json
├── tsconfig.json
├── Procfile
└── .gitignore

Confirmar los archivos a nuestro repositorio git:

git add .
git commit -m "My first commit"

Configurar un Heroku Remote

Si ya has creado una aplicación Herokuopen in new window, pasa el nombre de tu Aplicación existente en <miApp> a continuación, y ejecuta el código. De lo contrario, ejecute Nueva aplicación.

heroku create
git remote -v
heroku git:remote -a <myApp>

Despliegue del código

Finalmente, pulsa el botón rojo y ¡despega! 🚀

git push heroku main

Si no funciona, es probable que nuestra rama git no sea main sino master. Pulsa este botón azul en su lugar:

git push heroku master