Support exclusive conversations by default

This commit is contained in:
Lonami Exo 2018-10-12 22:17:07 +02:00
parent cf6686ff42
commit 0094eb391e
6 changed files with 50 additions and 5 deletions

View File

@ -160,7 +160,7 @@ class DialogMethods(UserMethods):
def conversation( def conversation(
self, entity, self, entity,
*, timeout=None, total_timeout=60, max_messages=100, *, timeout=None, total_timeout=60, max_messages=100,
replies_are_responses=True): exclusive=True, replies_are_responses=True):
""" """
Creates a `Conversation <telethon.tl.custom.conversation.Conversation>` Creates a `Conversation <telethon.tl.custom.conversation.Conversation>`
with the given entity so you can easily send messages and await for with the given entity so you can easily send messages and await for
@ -187,6 +187,16 @@ class DialogMethods(UserMethods):
specified chat, subsequent actions will result in specified chat, subsequent actions will result in
``ValueError``. ``ValueError``.
exclusive (`bool`, optional):
By default, conversations are exclusive within a single
chat. That means that while a conversation is open in a
chat, you can't open another one in the same chat, unless
you disable this flag.
If you try opening an exclusive conversation for
a chat where it's already open, it will raise
``AlreadyInConversationError``.
replies_are_responses (`bool`, optional): replies_are_responses (`bool`, optional):
Whether replies should be treated as responses or not. Whether replies should be treated as responses or not.
@ -229,6 +239,7 @@ class DialogMethods(UserMethods):
timeout=timeout, timeout=timeout,
total_timeout=total_timeout, total_timeout=total_timeout,
max_messages=max_messages, max_messages=max_messages,
exclusive=exclusive,
replies_are_responses=replies_are_responses replies_are_responses=replies_are_responses
) )

View File

@ -272,6 +272,7 @@ class TelegramBaseClient(abc.ABC):
# Some further state for subclasses # Some further state for subclasses
self._event_builders = [] self._event_builders = []
self._conversations = {} self._conversations = {}
self._ids_in_conversations = {} # chat_id: count
# Default parse mode # Default parse mode
self._parse_mode = markdown self._parse_mode = markdown

View File

@ -283,6 +283,10 @@ class UpdateMethods(UserMethods):
try: try:
await callback(event) await callback(event)
except errors.AlreadyInConversationError:
name = getattr(callback, '__name__', repr(callback))
__log__.debug('Event handler "%s" already has an open '
'conversation, ignoring new one', name)
except events.StopPropagation: except events.StopPropagation:
name = getattr(callback, '__name__', repr(callback)) name = getattr(callback, '__name__', repr(callback))
__log__.debug( __log__.debug(

View File

@ -8,7 +8,8 @@ from threading import Thread
from .common import ( from .common import (
ReadCancelledError, TypeNotFoundError, InvalidChecksumError, ReadCancelledError, TypeNotFoundError, InvalidChecksumError,
InvalidBufferError, SecurityError, CdnFileTamperedError, MultiError InvalidBufferError, SecurityError, CdnFileTamperedError,
AlreadyInConversationError, MultiError
) )
# This imports the base errors too, as they're imported there # This imports the base errors too, as they're imported there

View File

@ -79,6 +79,17 @@ class CdnFileTamperedError(SecurityError):
) )
class AlreadyInConversationError(Exception):
"""
Occurs when another exclusive conversation is opened in the same chat.
"""
def __init__(self):
super().__init__(
'Cannot open exclusive conversation in a '
'chat that already has one open conversation'
)
class MultiError(Exception): class MultiError(Exception):
"""Exception container for multiple `TLRequest`'s.""" """Exception container for multiple `TLRequest`'s."""

View File

@ -3,7 +3,7 @@ import itertools
import time import time
from .chatgetter import ChatGetter from .chatgetter import ChatGetter
from ... import utils from ... import utils, errors
class Conversation(ChatGetter): class Conversation(ChatGetter):
@ -23,7 +23,7 @@ class Conversation(ChatGetter):
def __init__(self, client, input_chat, def __init__(self, client, input_chat,
*, timeout, total_timeout, max_messages, *, timeout, total_timeout, max_messages,
replies_are_responses): exclusive, replies_are_responses):
self._id = Conversation._id_counter self._id = Conversation._id_counter
Conversation._id_counter += 1 Conversation._id_counter += 1
@ -50,6 +50,8 @@ class Conversation(ChatGetter):
self._pending_edits = {} self._pending_edits = {}
self._pending_reads = {} self._pending_reads = {}
self._exclusive = exclusive
# The user is able to expect two responses for the same message. # The user is able to expect two responses for the same message.
# {desired message ID: next incoming index} # {desired message ID: next incoming index}
self._response_indices = {} self._response_indices = {}
@ -380,11 +382,20 @@ class Conversation(ChatGetter):
return self._client.loop.run_until_complete(self.__aenter__()) return self._client.loop.run_until_complete(self.__aenter__())
async def __aenter__(self): async def __aenter__(self):
self._client._conversations[self._id] = self
self._input_chat = \ self._input_chat = \
await self._client.get_input_entity(self._input_chat) await self._client.get_input_entity(self._input_chat)
self._chat_peer = utils.get_peer(self._input_chat) self._chat_peer = utils.get_peer(self._input_chat)
# Make sure we're the only conversation in this chat if it's exclusive
chat_id = utils.get_peer_id(self._chat_peer)
count = self._client._ids_in_conversations.get(chat_id, 0)
if self._exclusive and count:
raise errors.AlreadyInConversationError()
self._client._ids_in_conversations[chat_id] = count + 1
self._client._conversations[self._id] = self
self._last_outgoing = 0 self._last_outgoing = 0
self._last_incoming = 0 self._last_incoming = 0
for d in ( for d in (
@ -405,5 +416,11 @@ class Conversation(ChatGetter):
return self._client.loop.run_until_complete(self.__aexit__(*args)) return self._client.loop.run_until_complete(self.__aexit__(*args))
async def __aexit__(self, *args): async def __aexit__(self, *args):
chat_id = utils.get_peer_id(self._chat_peer)
if self._client._ids_in_conversations[chat_id] == 1:
del self._client._ids_in_conversations[chat_id]
else:
self._client._ids_in_conversations[chat_id] -= 1
del self._client._conversations[self._id] del self._client._conversations[self._id]
self._cancel_all() self._cancel_all()