8

I have a telegram bot that for any received message runs a program in the server and sends its result back. But there is a problem! If a user sends too many messages to my bot(spamming), it will make server so busy!
Is there any way to block the people whom send more than 5 messages in a second and don't receive their messages anymore? (using telegram api!!)

MaGaroo
  • 164
  • 1
  • 1
  • 13
  • No, you can't. API does not provide this feature. Just make a local block list of users whom the bot will ignore. – mymedia Mar 19 '17 at 11:23
  • I want those users' messages don't even exist in the json file which I download from telegram server! Anyway, it's ok if there is no other way. – MaGaroo Mar 19 '17 at 11:31

3 Answers3

9

Firstly I have to say that Telegram Bot API does not have such a capability itself, Therefore you will need to implement it on your own and all you need to do is:

  1. Count the number of the messages that a user sends within a second which won't be so easy without having a database. But if you have a database with a table called Black_List and save all the messages with their sent-time in another table, you'll be able to count the number of messages sent via one specific ChatID in a pre-defined time period(In your case; 1 second) and check if the count is bigger than 5 or not, if the answer was YES you can insert that ChatID to the Black_List table.
  2. Every time the bot receives a message it must run a database query to see that the sender's chatID exists in the Black_List table or not. If it exists it should continue its own job and ignore the message(Or even it can send an alert to the user saying: "You're blocked." which I think can be time consuming).

Note that as I know the current telegram bot API doesn't have the feature to stop receiving messages but as I mentioned above you can ignore the messages from spammers.

In order to save time, You should avoid making a database connection every time the bot receives an update(message), instead you can load the ChatIDs that exist in the Black_List to a DataSet and update the DataSet right after the insertion of a new spammer ChatID to the Black_List table. This way the number of the queries will reduce noticeably.

anatol
  • 1,680
  • 2
  • 24
  • 47
Naser.Sadeghi
  • 1,341
  • 1
  • 12
  • 35
0

I have achieved it by this mean:

# Using the ttlcache to set a time-limited dict. you can adjust the ttl.
ttl_cache = cachetools.TTLCache(maxsize=128, ttl=60)


def check_user_msg_frequency(message):
    print(ttl_cache)
    msg_cnt = ttl_cache[message.from_user.id]
    if msg_cnt > 3:
        now = datetime.now()
        until = now + timedelta(seconds=60*10)
        bot.restrict_chat_member(message.chat.id, message.from_user.id, until_date=until)
        

def set_user_msg_frequency(message):
    if not ttl_cache.get(message.from_user.id):
        ttl_cache[message.from_user.id] = 1
    else:
        ttl_cache[message.from_user.id] += 1

With these to functions above, you can record how many messages sent by any user in the period. If a user's messages sent more than expected, he would be restricted.

Then, every handler you called should call these two functions:

@bot.message_handler(commands=['start', 'help'])
def handle_start_help(message):
    set_user_msg_frequency(message)
    check_user_msg_frequency(message)

I'm using pyTelegramBotAPI this module to handle.

DennisLi
  • 3,915
  • 6
  • 30
  • 66
0

I know I'm late to the party, but here is another simple solution that doesn't use a Db:

  • Create a ConversationState class to attach to each telegram Id when they start to chat with the bot

  • Then add a LastMessage DateTime variable to the ConversationState class

  • Now every time you receive a message check if enought time has passed from the LasteMessage DateTime, if not enought time has passed answer with a warning message.

You can also implement a timer that deletes the conversation state class if you are worried about performance.

  • Parties are good even if you arrive a bit late. XD However, I was wondering although this solution works for a small bot, it's against the factors of [12-factor app](https://12factor.net/) and therefore not so scalable. – MaGaroo Jan 24 '23 at 22:43
  • @MaGaroo against which factor would it be? Wouldn't checking a simple hash map for each message be more efficent than doing a query ( as suggested in the highest answer)? – milo brontesi Jan 26 '23 at 08:46
  • Of course that's more efficient, but it's against "Execute the app as one or more stateless processes" rule as mentioned [here](https://12factor.net/processes). That's because defining `ConversationState` makes the process stateful, and we won't be able to scale the number of processes. It's impossible to share this dictionary among multiple processes without a backing service, and if we don't share it, there may be odd situations in which a process has blocked a user and another one hasn't. – MaGaroo Jan 30 '23 at 05:06