Функция-таймер для Telegram-бота

Рейтинг: 0Ответов: 3Опубликовано: 23.08.2023

Друзья, добрый день!

Наверняка этот вопрос уже кем-то задавался, но соответствующего топика не нашёл.

Есть Telegram-бот, принимающий сообщения пользователей и пересылающий их администратору. Необходимо реализовать антиспам-защиту, чтобы один и тот же пользователь не мог отправлять сообщения чаще одного раза в пять минут.

Создал в папке с хэндлерами файл "global_data.py", имеющий следующее содержание:

import time

# Глобальная переменная-флаг с таймером отправки сообщений.
timer_flag = False


def start_timer() -> None:
    """
    Функция - таймер для отправки сообщений.
    """
    global timer_flag
    timer_flag = True
    while True:
        duration = 5 * 60  # Время в секундах.
        start_time = time.time()
        remaining_time = duration - (time.time() - start_time)
        time.sleep(1)
        if remaining_time <= 0:
            timer_flag = False
            break

В файле с хендлерами сделал импорт

from . import global_data as data

и добавил

data.start_timer()

в конце функции отправки сообщения администратору.

Проблема в том, что функция "start_timer" запускается, но цикл, по-видимому, почему-то никогда не прерывается, и, соответственно, глобальной переменной "timer_flag" не передаётся значение False.

Проверка в самом хендлере выглядит так:

elif data.timer_flag:
    bot.send_message(message.chat.id, f'<b>Анти-спам</b>: Вы сможете отправить '
                                      f'новое сообщение через 5 минут',
                     parse_mode='html')

Помогите, пожалуйста, с решением этой проблемы или предложите какую-нибудь более изящную реализацию.

Заранее спасибо :)

Ответы

▲ 0Принят

Сделать БД с id пользователями и записывать туда дату/время последнего сообщения, потом создать декоратор проверяющий текущее время и время в БД, если всё ок - отправить сообщение по адресу, если не ок - ответить пользователю об ошибке или забанить на время.

▲ 0

Переменная start_time каждую итерацию определяется заново, потому обратный отсчёт не меняется. start_time надо вынести за пределы while True:

# Предыдущий код
global timer_flag
timer_flag = True
start_time = time.time()
while timer_flag:
    ... # Дальнейший код без изменений

Но вообще функцию лучше оформить проще:

def start_timer() -> None:
    """
    Функция - таймер для отправки сообщений.
    """
    global timer_flag
    timer_flag = True
    remaining_time = 5 * 60  # Время в секундах.
    while timer_flag:
        remaining_time -= 1
        time.sleep(1)
        if remaining_time == 0:
            timer_flag = False
▲ 0

Друзья, спасибо за ответы!

Пока ждал вашего фидбека, придумал вот что. Сделал импорт

from threading import Timer

и прописал следующие функции:

def start_timer() -> None:
    global timer_flag
    timer_flag = True

    send_timer = Timer(300, flag_change)
    send_timer.start()


def flag_change() -> None:
    global timer_flag
    timer_flag = False

В хендлере проверка флага осталась той же.

Всё работает, но, насколько я понимаю, если одновременно будет писать несколько юзеров, возможны ошибки, поскольку глобальная переменная "timer_flag" является общей для всех пользователей.

Видимо, действительно придётся прибегнуть к решению с БД, предложенному Alex.