Add limiter

This commit is contained in:
2022-08-06 20:43:52 +03:00
parent a6f0816325
commit 462032a4e9
4 changed files with 57 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
import { Context } from "telegraf"; import { Context } from "telegraf";
import { AuthorAnnnotation, BookAnnotation } from "./services/book_library"; import { AuthorAnnotation, BookAnnotation } from "./services/book_library";
import { isNormalText } from "./utils"; import { isNormalText } from "./utils";
import { getTextPaginationData } from './keyboard'; import { getTextPaginationData } from './keyboard';
@@ -7,7 +7,7 @@ import Sentry from '@/sentry';
import { downloadImage } from "./services/downloader"; import { downloadImage } from "./services/downloader";
export function getAnnotationHandler<T extends BookAnnotation | AuthorAnnnotation>( export function getAnnotationHandler<T extends BookAnnotation | AuthorAnnotation>(
annotationGetter: (id: number) => Promise<T>, annotationGetter: (id: number) => Promise<T>,
callbackData: string callbackData: string
): (ctx: Context) => Promise<void> { ): (ctx: Context) => Promise<void> {
@@ -32,7 +32,6 @@ export function getAnnotationHandler<T extends BookAnnotation | AuthorAnnnotatio
try { try {
await ctx.telegram.sendPhoto(ctx.message.chat.id, { source: imageData }); await ctx.telegram.sendPhoto(ctx.message.chat.id, { source: imageData });
} catch (e) { } catch (e) {
console.log(e);
Sentry.captureException(e); Sentry.captureException(e);
} }
} }

View File

@@ -12,6 +12,7 @@ import * as CallbackData from "./callback_data";
import * as BookLibrary from "./services/book_library"; import * as BookLibrary from "./services/book_library";
import * as Rating from "./services/book_ratings"; import * as Rating from "./services/book_ratings";
import UsersCounter from '@/analytics/users_counter'; import UsersCounter from '@/analytics/users_counter';
import Limiter from '@/bots/limiter';
import { createOrUpdateUserSettings, getUserOrDefaultLangCodes } from './services/user_settings'; import { createOrUpdateUserSettings, getUserOrDefaultLangCodes } from './services/user_settings';
import { formatBook, formatBookShort, formatAuthor, formatSequence, formatTranslator, formatDetailBook, formatDetailBookWithRating } from './format'; import { formatBook, formatBookShort, formatAuthor, formatSequence, formatTranslator, formatDetailBook, formatDetailBookWithRating } from './format';
import { getCallbackArgs, getPaginatedMessage, getPrefixWithQueryCreator, getSearchArgs, registerLanguageSettingsCallback, registerPaginationCommand, registerRandomItemCallback } from './utils'; import { getCallbackArgs, getPaginatedMessage, getPrefixWithQueryCreator, getSearchArgs, registerLanguageSettingsCallback, registerPaginationCommand, registerRandomItemCallback } from './utils';
@@ -54,6 +55,12 @@ export async function createApprovedBot(token: string, state: BotState): Promise
await next(); await next();
}); });
bot.use(async (ctx: Context, next) => {
if (await Limiter.isLimited(ctx.update.update_id)) return;
await next();
});
bot.command(["start", `start@${me.username}`], async (ctx: Context) => { bot.command(["start", `start@${me.username}`], async (ctx: Context) => {
if (!ctx.message) { if (!ctx.message) {
return; return;
@@ -449,7 +456,7 @@ export async function createApprovedBot(token: string, state: BotState): Promise
}); });
bot.catch((err, ctx: Context) => { bot.catch((err, ctx: Context) => {
console.log(err, ctx); console.log({err, ctx});
Sentry.captureException(err); Sentry.captureException(err);
}); });

View File

@@ -88,7 +88,7 @@ export interface Sequence {
} }
export interface AuthorAnnnotation { export interface AuthorAnnotation {
id: number; id: number;
title: string; title: string;
text: string; text: string;

46
src/bots/limiter/index.ts Normal file
View File

@@ -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<number> {
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<boolean> {
const count = await this._getCount(updateId);
return count <= this.MAX_PROCESSING_COUNT;
}
}