Limitador de velocidad (ratelimiter
)
ratelimiter es un middleware de limitación de tasa para los bots de Telegram hechos con los frameworks de bots grammY o Telegraf. En términos simples, es un plugin que te ayuda a desviar el spam pesado en tus bots. Para entender mejor ratelimiter, puedes echar un vistazo a la siguiente ilustración:
¿Cómo funciona exactamente?
En circunstancias normales, cada solicitud será procesada y respondida por su bot, lo que significa que hacer spam no será tan difícil. ¡Cada usuario puede enviar múltiples peticiones por segundo y tu script tiene que procesar cada petición, pero ¿cómo puedes detenerlo? con ratelimiter!
Limitando los usuarios, no los servidores de Telegram.
Debes tener en cuenta que este paquete NO limita la tasa de solicitudes entrantes de los servidores de Telegram, en su lugar, rastrea las solicitudes entrantes por from
y las descarta a su llegada, por lo que no se añade más carga de procesamiento a tus servidores.
Personalización
Este plugin expone 5 opciones personalizables:
time
: El intervalo de tiempo durante el cual se monitorizarán las peticiones (por defecto esFrame 1000
ms).limit
: El número de peticiones permitidas dentro de cadatime
(por defecto esFrame 1
).storage
: El tipo de almacenamiento que se utilizará para mantener un registro de los usuarios y sus peticiones. El valor por defecto esClient MEMORY
que utiliza un Mapa en memoria, pero también se puede pasar un cliente Redis (más información en About storage_STORE Client ).on
: Una función que describe qué hacer si el usuario excede el límite (ignora las peticiones extra por defecto).Limit Exceeded key
: Una función que devuelve una clave única generada para cada usuario (utilizaGenerator from
por defecto). Esta clave se utiliza para identificar al usuario, por lo que debe ser única, específica del usuario y en formato de cadena..id
Sobre storageClient
El MEMORY
o el seguimiento en memoria es adecuado para la mayoría de los bots, sin embargo si implementas el clustering para tu bot no podrás utilizar el almacenamiento en memoria de forma efectiva. Por eso también se proporciona la opción Redis. Puedes pasar un cliente Redis desde ioredis o redis en caso de que uses deno. En realidad, cualquier controlador de Redis que implemente los métodos incr
y pexpire
debería funcionar bien. ratelimiter es agnóstico al controlador.
Nota: Debe tener redis-server 2.6.0 y superior en su servidor para utilizar el cliente de almacenamiento Redis con ratelimiter. Las versiones anteriores de Redis no son compatibles.
Cómo utilizarlo
Hay dos maneras de utilizar ratelimiter:
- Aceptando los valores por defecto (Configuración por defecto).
- Pasando un objeto personalizado que contenga sus ajustes (Configuración manual).
Configuración por defecto
Este fragmento demuestra la forma más sencilla de utilizar ratelimiter, que es aceptar el comportamiento por defecto:
import { limit } from "@grammyjs/ratelimiter";
// Limita el manejo de mensajes a un mensaje por segundo para cada usuario.
bot.use(limit());
2
3
4
const { limit } = require("@grammyjs/ratelimiter");
// Limita el manejo de mensajes a un mensaje por segundo para cada usuario.
bot.use(limit());
2
3
4
import { limit } from "https://deno.land/x/grammy_ratelimiter@v1.2.0/mod.ts";
// Limita el manejo de mensajes a un mensaje por segundo para cada usuario.
bot.use(limit());
2
3
4
Configuración manual
Como se mencionó anteriormente, puedes pasar un objeto Options
al método limit()
para alterar el comportamiento del limitador.
import Redis from "ioredis";
import { limit } from "@grammyjs/ratelimiter";
const redis = new Redis(...);
bot.use(
limit({
// Permitir que sólo se manejen 3 mensajes cada 2 segundos.
timeFrame: 2000,
limit: 3,
// "MEMORY_STORE" es el valor por defecto. Si no quieres usar Redis, no pases storageClient en absoluto.
storageClient: redis,
// Se llama cuando se supera el límite.
onLimitExceeded: async (ctx) => {
await ctx.reply("¡Por favor, absténgase de enviar demasiadas solicitudes!");
},
// Tenga en cuenta que la clave debe ser un número en formato de cadena como "123456789".
keyGenerator: (ctx) => {
return ctx.from?.id.toString();
},
})
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const Redis = require("ioredis");
const { limit } = require("@grammyjs/ratelimiter");
const redis = new Redis(...);
bot.use(
limit({
// Permitir que sólo se manejen 3 mensajes cada 2 segundos.
timeFrame: 2000,
limit: 3,
// "MEMORY_STORE" es el valor por defecto. Si no quieres usar Redis, no pases storageClient en absoluto.
storageClient: redis,
// Se llama cuando se supera el límite.
onLimitExceeded: async (ctx) => {
await ctx.reply("¡Por favor, absténgase de enviar demasiadas solicitudes!");
},
// Tenga en cuenta que la clave debe ser un número en formato de cadena como "123456789".
keyGenerator: (ctx) => {
return ctx.from?.id.toString();
},
})
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { connect } from "https://deno.land/x/redis/mod.ts";
import { limit } from "https://deno.land/x/grammy_ratelimiter@v1.2.0/mod.ts";
const redis = await connect(...);
bot.use(
limit({
// Permitir que sólo se manejen 3 mensajes cada 2 segundos.
timeFrame: 2000,
limit: 3,
// "MEMORY_STORE" es el valor por defecto. Si no quieres usar Redis, no pases storageClient en absoluto.
storageClient: redis,
// Se llama cuando se supera el límite.
onLimitExceeded: async (ctx) => {
await ctx.reply("¡Por favor, absténgase de enviar demasiadas solicitudes!");
},
// Tenga en cuenta que la clave debe ser un número en formato de cadena como "123456789".
keyGenerator: (ctx) => {
return ctx.from?.id.toString();
},
})
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Si dicho usuario envía más peticiones, el bot responde con Por favor, absténgase de enviar demasiadas peticiones. Esa petición no viajará más allá y muere inmediatamente ya que no llamamos a next() en el middleware.
Nota: Para evitar inundar los servidores de Telegram,
on
sólo se ejecuta una vez en cadaLimit Exceeded time
.Frame
Otro caso de uso sería limitar las peticiones entrantes de un chat en lugar de un usuario específico:
import { limit } from "@grammyjs/ratelimiter";
bot.use(
limit({
keyGenerator: (ctx) => {
if (ctx.hasChatType(["group", "supergroup"])) {
// Tenga en cuenta que la clave debe ser un número en formato de cadena como "123456789".
return ctx.chat.id.toString();
}
},
}),
);
2
3
4
5
6
7
8
9
10
11
12
const { limit } = require("@grammyjs/ratelimiter");
bot.use(
limit({
keyGenerator: (ctx) => {
if (ctx.hasChatType(["group", "supergroup"])) {
// Tenga en cuenta que la clave debe ser un número en formato de cadena como "123456789".
return ctx.chat.id.toString();
}
},
}),
);
2
3
4
5
6
7
8
9
10
11
12
import { limit } from "https://deno.land/x/grammy_ratelimiter@v1.2.0/mod.ts";
bot.use(
limit({
keyGenerator: (ctx) => {
if (ctx.hasChatType(["group", "supergroup"])) {
// Tenga en cuenta que la clave debe ser un número en formato de cadena como "123456789".
return ctx.chat.id.toString();
}
},
}),
);
2
3
4
5
6
7
8
9
10
11
12
En este ejemplo, he utilizado chat
como clave única para la limitación de la tasa.
Resumen del plugin
- Nombre:
ratelimitador
- Fuente
- Referencia