Reputation: 23
I have two handlers in my bot's code:
import asyncio
import logging
import re
from telethon import TelegramClient
from telethon.events import StopPropagation, NewMessage
me = TelegramClient('bot', 'API_ID_BOT', 'API_HASH_BOT').start(bot_token='BOT_TOKEN')
async def my_conversation(event):
async with me.conversation(event.sender_id) as conv:
await conv.send_message('I\'m waiting for message')
response = conv.get_response()
response = await response
await conv.send_message(f'conversation: {response.text}')
raise StopPropagation
async def digits(event):
await me.send_message(event.sender_id, f'catches digits: {event.text}')
raise StopPropagation
async def main():
me.add_event_handler(my_conversation, NewMessage(incoming=True, pattern=r'^\/start$'))
me.add_event_handler(digits, NewMessage(incoming=True, pattern=re.compile(r'[0-9]+')))
await me.run_until_disconnected()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
What I expect:
What I have got:
So Bot also catched message by handler outside the conversation, so unexpected. What I must change in script to make it work properly?
Upvotes: 2
Views: 3918
Reputation: 7086
I plan to remove the conversation
method in future versions of the library because, as you can see, one runs into big limitations very quickly because mixing the callbacks-based approach of events with the imperative style of a conversation is difficult. I recommend you use a FSM-style conversation instead. You should be able to adapt that answer's code to "wait for digits" easily:
from enum import Enum, auto
class State(Enum):
WAIT_DIGITS = auto()
conversation_state = {}
@client.on(events.NewMessage)
async def handler(event):
who = event.sender_id
state = conversation_state.get(who)
if state is None:
await event.respond('Please send digits!')
conversation_state[who] = State.WAIT_DIGITS
elif state == State.WAIT_DIGITS:
if event.text.isdigit():
digits = event.text
await event.respond(f'Thanks for your digits! {digits}')
del conversation_state[who]
else:
await event.respond('Please only send digits, not letters')
You can easily add more abstractions to this (build your own decorators for other functions depending on the state, or just separate the code of each state to another function, using their return values as the next state, etc.).
Upvotes: 2