From 462032a4e986b410faa91adb95eaf3bcf4bd4cd6 Mon Sep 17 00:00:00 2001 From: Bulat Kurbanov Date: Sat, 6 Aug 2022 20:43:52 +0300 Subject: [PATCH] Add limiter --- src/bots/factory/bots/approved/annotations.ts | 5 +- src/bots/factory/bots/approved/index.ts | 9 +++- .../bots/approved/services/book_library.ts | 2 +- src/bots/limiter/index.ts | 46 +++++++++++++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 src/bots/limiter/index.ts diff --git a/src/bots/factory/bots/approved/annotations.ts b/src/bots/factory/bots/approved/annotations.ts index f43ffee..7893d84 100644 --- a/src/bots/factory/bots/approved/annotations.ts +++ b/src/bots/factory/bots/approved/annotations.ts @@ -1,5 +1,5 @@ import { Context } from "telegraf"; -import { AuthorAnnnotation, BookAnnotation } from "./services/book_library"; +import { AuthorAnnotation, BookAnnotation } from "./services/book_library"; import { isNormalText } from "./utils"; import { getTextPaginationData } from './keyboard'; @@ -7,7 +7,7 @@ import Sentry from '@/sentry'; import { downloadImage } from "./services/downloader"; -export function getAnnotationHandler( +export function getAnnotationHandler( annotationGetter: (id: number) => Promise, callbackData: string ): (ctx: Context) => Promise { @@ -32,7 +32,6 @@ export function getAnnotationHandler { + if (await Limiter.isLimited(ctx.update.update_id)) return; + + await next(); + }); + bot.command(["start", `start@${me.username}`], async (ctx: Context) => { if (!ctx.message) { return; @@ -449,7 +456,7 @@ export async function createApprovedBot(token: string, state: BotState): Promise }); bot.catch((err, ctx: Context) => { - console.log(err, ctx); + console.log({err, ctx}); Sentry.captureException(err); }); diff --git a/src/bots/factory/bots/approved/services/book_library.ts b/src/bots/factory/bots/approved/services/book_library.ts index c7d4f14..e6664a8 100644 --- a/src/bots/factory/bots/approved/services/book_library.ts +++ b/src/bots/factory/bots/approved/services/book_library.ts @@ -88,7 +88,7 @@ export interface Sequence { } -export interface AuthorAnnnotation { +export interface AuthorAnnotation { id: number; title: string; text: string; diff --git a/src/bots/limiter/index.ts b/src/bots/limiter/index.ts new file mode 100644 index 0000000..57a3513 --- /dev/null +++ b/src/bots/limiter/index.ts @@ -0,0 +1,46 @@ +import { createClient, RedisClientType } from 'redis'; + +import env from '@/config'; + +import Sentry from '@/sentry'; + + +export default class Limiter { + static MAX_PROCESSING_COUNT: number = 3; + static _redisClient: RedisClientType | null = null; + + static async _getClient() { + if (this._redisClient === null) { + this._redisClient = createClient({ + url: `redis://${env.REDIS_HOST}:${env.REDIS_PORT}/${env.REDIS_DB}` + }); + + this._redisClient.on('error', (err) => { + console.log(err); + Sentry.captureException(err); + }); + + await this._redisClient.connect(); + } + + return this._redisClient; + } + + static _getKey(updateId: number) { + return `update_${updateId}`; + } + + static async _getCount(updateId: number): Promise { + const key = this._getKey(updateId); + + const client = await this._getClient(); + + await client.set(key, 0, {EX: 5 * 60, NX: true}); + return client.incr(key); + } + + static async isLimited(updateId: number): Promise { + const count = await this._getCount(updateId); + return count <= this.MAX_PROCESSING_COUNT; + } +}