Skip to content

Commit cd18c16

Browse files
committed
add handling for timed out Promises
1 parent edc91ff commit cd18c16

File tree

1 file changed

+55
-5
lines changed

1 file changed

+55
-5
lines changed

telegram/ext/conversationhandler.py

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
class ConversationHandler(Handler):
2929
"""
30-
A handler to hold a conversation with a user by managing three collections of other handlers.
30+
A handler to hold a conversation with a user by managing four collections of other handlers.
3131
3232
The first collection, a ``list`` named ``entry_points``, is used to initiate the conversation,
3333
for example with a ``CommandHandler`` or ``RegexHandler``.
@@ -43,34 +43,64 @@ class ConversationHandler(Handler):
4343
a regular text message is expected. You could use this for a ``/cancel`` command or to let the
4444
user know their message was not recognized.
4545
46+
The fourth, optional collection of handlers, a ``list`` named ``timed_out_behavior`` is used if
47+
the wait for ``run_async`` takes longer than defined in ``run_async_timeout``. For example,
48+
you can let the user know that they should wait for a bit before they can continue.
49+
4650
To change the state of conversation, the callback function of a handler must return the new
4751
state after responding to the user. If it does not return anything (returning ``None`` by
4852
default), the state will not change. To end the conversation, the callback function must
49-
return ``CallbackHandler.END`` or -1.
53+
return ``CallbackHandler.END`` or ``-1``.
5054
5155
Args:
5256
entry_points (list): A list of ``Handler`` objects that can trigger the start of the
53-
conversation.
57+
conversation. The first handler which ``check_update`` method returns ``True`` will be
58+
used. If all return ``False``, the update is not handled.
5459
states (dict): A ``dict[object: list[Handler]]`` that defines the different states of
5560
conversation a user can be in and one or more associated ``Handler`` objects that
5661
should be used in that state. The first handler which ``check_update`` method returns
5762
``True`` will be used.
5863
fallbacks (list): A list of handlers that might be used if the user is in a conversation,
5964
but every handler for their current state returned ``False`` on ``check_update``.
65+
The first handler which ``check_update`` method returns ``True`` will be used. If all
66+
return ``False``, the update is not handled.
6067
allow_reentry (Optional[bool]): If set to ``True``, a user that is currently in a
6168
conversation can restart the conversation by triggering one of the entry points.
69+
run_async_timeout (Optional[float]): If the previous handler for this user was running
70+
asynchronously using the ``run_async`` decorator, it might not be finished when the
71+
next message arrives. This timeout defines how long the conversation handler should
72+
wait for the next state to be computed. The default is ``None`` which means it will
73+
wait indefinitely.
74+
timed_out_behavior (Optional[list]): A list of handlers that might be used if
75+
the wait for ``run_async`` timed out. The first handler which ``check_update`` method
76+
returns ``True`` will be used. If all return ``False``, the update is not handled.
77+
6278
"""
6379

6480
END = -1
6581

66-
def __init__(self, entry_points, states, fallbacks, allow_reentry=False):
82+
def __init__(self,
83+
entry_points,
84+
states,
85+
fallbacks,
86+
allow_reentry=False,
87+
run_async_timeout=None,
88+
timed_out_behavior=None):
89+
6790
self.entry_points = entry_points
6891
""":type: list[telegram.ext.Handler]"""
92+
6993
self.states = states
7094
""":type: dict[str: telegram.ext.Handler]"""
95+
7196
self.fallbacks = fallbacks
7297
""":type: list[telegram.ext.Handler]"""
98+
7399
self.allow_reentry = allow_reentry
100+
self.run_async_timeout = run_async_timeout
101+
102+
self.timed_out_behavior = timed_out_behavior
103+
""":type: list[telegram.ext.Handler]"""
74104

75105
self.conversations = dict()
76106
""":type: dict[(int, int): str]"""
@@ -112,9 +142,26 @@ def check_update(self, update):
112142
key = (chat.id, user.id) if chat else (None, user.id)
113143
state = self.conversations.get(key)
114144

145+
# Resolve promises
115146
if isinstance(state, Promise):
116147
self.logger.debug('waiting for promise...')
117-
state = state.result()
148+
state.result(timeout=self.run_async_timeout)
149+
150+
if state.done.is_set():
151+
self.update_state(state.result())
152+
state = self.conversations.get(key)
153+
154+
else:
155+
for candidate in (self.timed_out_behavior or []):
156+
if candidate.check_update(update):
157+
# Save the current user and the selected handler for handle_update
158+
self.current_conversation = key
159+
self.current_handler = candidate
160+
161+
return True
162+
163+
else:
164+
return False
118165

119166
self.logger.debug('selecting conversation %s with state %s' % (str(key), str(state)))
120167

@@ -160,6 +207,9 @@ def handle_update(self, update, dispatcher):
160207

161208
new_state = self.current_handler.handle_update(update, dispatcher)
162209

210+
self.update_state(new_state)
211+
212+
def update_state(self, new_state):
163213
if new_state == self.END:
164214
del self.conversations[self.current_conversation]
165215
elif new_state is not None:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy