LINUX.ORG.RU

Telegram bot, timeout handler и привязка к пользователю начавшему диалог с ботом.

 , ,


0

1

Приветствую всех, делаю бота на питоне , с модулем telebot , возник вопрос : 1. Как сделать таймаут хендлера , например боту отдана первая команда /k , бот ожидает ввода от пользователя , чтобы перейти к следующей функции get_info ... , мне хотелось бы ввести тайм аут ожидания в районе 5 минут, а потом хендлер бы сбрасывался, возможно ли это сделать ? 2. Как сделать привязку к пользователю который ввел команду. Сейчас любой пользователь в группе может перехватить так сказать диалог с ботом... например , я пишу команду /k , и бот должен только от меня дальше пойти выполнять уже следующую функцию, подозреваю что нужно привязываться к параметрку uid = message.from_user.id , но может есть другой способ?

@bot.message_handler(commands=['k'])
def start(message):
     chat_id = message.chat.id
     sent = bot.send_message(message.chat.id, 'Введите команду в формате  /P21T0110  /Л11705054')
     bot.register_next_step_handler(sent, get_info)

#INFO GET
def get_info(message):
    #uid = message.from_user.id
    text = message.text
    bot.send_message(message.chat.id, 'Вы ввели команду {0:}'.format(text))

Удобнее делать на вебхуках, без всякого телебота, бот-апи у телеги простой - post-запросы.

И «диалоги» с отдельными пользователями проще будет разруливать.

vvn_black ★★★★ ()
Ответ на: комментарий от vvn_black

На вебхуках не вариант , нет белого IP , да и уже много написано на этом модуле telebot, так что нужно как то на текущем виде получить. Как фильтровать пользователей разобрался , просто сравниваю UID в первой функции и во второй. Но вот как тайм аут ожидания тут вставить .. не где не нашел инфы об этом.


@bot.message_handler(commands=['k'])
def start(message):
     uid = message.from_user.id
     chat_id = message.chat.id
     sent = bot.send_message(message.chat.id, 'Введите команду в формате  /P21T0110  /Л11705054')
     bot.register_next_step_handler(sent, get_info, uid)

#INFO GET
def get_info(message,uid):
    uid_new = message.from_user.id
    if uid == uid_new:
       text = message.text
       bot.send_message(message.chat.id, 'Вы ввели команду : {0:} первый id {1:} {2:}'.format(text,uid_new,uid))
    else:
        bot.send_message(message.chat.id, 'error')






bot.polling()

atraides ()
Ответ на: комментарий от atraides

На вебхуках не вариант , нет белого IP.

Я могу ошибаться, но по-моему телега принимает self-signed сертификаты, так что можно заморочиться с дин. DNS (если всё-таки есть возможность «белого» IP).

Но вот как тайм аут ожидания тут вставить

Сохранять в start пользовательский uid и время когда пользователь написал первый раз. А в get_info проверять сколько времени прошло. Но это не красиво.

vvn_black ★★★★ ()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от vvn_black

Попробовал привязаться к времени , но получилось не совсем то что нужно, получается функция get_info не сработает до ввода команды боту и соответственно не обработает разницу во времени


@bot.message_handler(commands=['k'])
def start(message):
     date = int(message.date)
     uid = message.from_user.id
     chat_id = message.chat.id
     sent = bot.send_message(message.chat.id, 'Введите команду в формате  /P21T0110  /Л11705054')
     bot.register_next_step_handler(sent, get_info, uid, date)

#INFO GET
def get_info(message,uid,date):
    new_date = int(message.date)
    delta_time = new_date - date
    uid_new = message.from_user.id
    text = message.text
    if delta_time > 10:
       bot.send_message(message.chat.id, 'timeout')
    else:

      if uid == uid_new:
         bot.send_message(message.chat.id, 'last:{0:} prev:{1:} diff:{2:}'.format(message.date,date,delta_time))
        #bot.send_message(message.chat.id, 'Вы ввели команду : {0:} первый id {1:} {2:}'.format(text,uid_new,uid))
      else:
        #bot.send_message(message.chat.id, 'error')
         bot.register_next_step_handler(message, get_info, uid, date)



В таком виде тайм аут сработает только после следующего ввода команды боту , а мне поидее нужно отвязаться от ввода , а просто по пройденому времени таймаут выводить
atraides ()
Ответ на: комментарий от atraides

Ну, всё непонятнее и непонятнее )

В start, как-то так:

conversations = {}
...
conversations[message.from_user.id] = {
    'timestamp': datetime.datetime.now(),
    'chat_id': message.chat.id
}

где-то в основном цикле, периодически проверять:

now = datetime.datetime.now()
expired = filter(lambda x: (now - conversations[x]['timestamp']).seconds > 300,
                 conversations.keys())
for chat in expired:
    bot.send_message(conversations['chat']['chat_id'], 'timeout')
    conversations.pop(chat)

И в get_info:

if message.from_user.id in conversations:
    bot.send_message(...)

Это если в telebot нет нужной функцональности.

vvn_black ★★★★ ()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от vvn_black

Не могли бы вы меня подкорректировать, задумку вроде бы понял вашу

в таком виде сделал


conversations = {}

@bot.message_handler(commands=['k'])
def start(message):

     conversations[message.from_user.id] = {
      'timestamp': datetime.datetime.now(),
      'chat_id': message.chat.id}

     now = datetime.datetime.now()
     expired = filter(lambda x: (now - conversations[x]['timestamp']).seconds > 30, conversations.keys())
     for chat in expired:
         bot.send_message(conversations['chat']['chat_id'], 'timeout')
         conversations.pop(chat)

     bot.register_next_step_handler(conversations, get_info)

#INFO GET
def get_info(conversations, message):

    if message.from_user.id in conversations:
       bot.send_message(message.chat.id, 'Работает')





bot.polling()

Но не работает, вот этот кусок с циклом где нужно вставить? в функцию или вообще за пределы ?

now = datetime.datetime.now()
     expired = filter(lambda x: (now - conversations[x]['timestamp']).seconds > 30, conversations.keys())
     for chat in expired:
         bot.send_message(conversations['chat']['chat_id'], 'timeout')
         conversations.pop(chat)
atraides ()
Ответ на: комментарий от atraides

Вынести из start в основной цикл (если он есть) или в шедулер (если он есть) или каким-то образом организовать выполнение с заданой периодичностью, в старте вы запоминаете диалог. Эта проверка с заданой вами периодичностью выполняется вне start и get_info и удаляет «протухшие» диалоги.

А в get_info отвечаем только на сообщения в диалогах, которые не удалили по таймауту.

vvn_black ★★★★ ()
Последнее исправление: vvn_black (всего исправлений: 1)