From a315c30336814c2cb9b3bcc2a2e8342f48410391 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Wed, 17 Oct 2018 20:37:53 +0200 Subject: [PATCH 1/6] Optimize dispatcher.py code --- pyrogram/client/dispatcher/dispatcher.py | 159 +++++++++-------------- 1 file changed, 61 insertions(+), 98 deletions(-) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index a0c5e365..4366b56d 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -25,7 +25,7 @@ from threading import Thread import pyrogram from pyrogram.api import types from ..ext import utils -from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler +from ..handlers import CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler, RawUpdateHandler log = logging.getLogger(__name__) @@ -88,56 +88,6 @@ class Dispatcher: "Handler was not removed.".format(group)) self.groups[group].remove(handler) - def dispatch(self, update, users: dict = None, chats: dict = None, is_raw: bool = False): - for group in self.groups.values(): - try: - for handler in group: - if is_raw: - if not isinstance(handler, RawUpdateHandler): - continue - - args = (self.client, update, users, chats) - else: - message = (update.message - or update.channel_post - or update.edited_message - or update.edited_channel_post) - - deleted_messages = (update.deleted_channel_posts - or update.deleted_messages) - - callback_query = update.callback_query - - user_status = update.user_status - - if message and isinstance(handler, MessageHandler): - if not handler.check(message): - continue - - args = (self.client, message) - elif deleted_messages and isinstance(handler, DeletedMessagesHandler): - if not handler.check(deleted_messages): - continue - - args = (self.client, deleted_messages) - elif callback_query and isinstance(handler, CallbackQueryHandler): - if not handler.check(callback_query): - continue - - args = (self.client, callback_query) - elif user_status and isinstance(handler, UserStatusHandler): - if not handler.check(user_status): - continue - - args = (self.client, user_status) - else: - continue - - handler.callback(*args) - break - except Exception as e: - log.error(e, exc_info=True) - def update_worker(self): name = threading.current_thread().name log.debug("{} started".format(name)) @@ -153,80 +103,93 @@ class Dispatcher: chats = {i.id: i for i in update[2]} update = update[0] - self.dispatch(update, users=users, chats=chats, is_raw=True) + self.dispatch_raw(update, users=users, chats=chats, handler_class=RawUpdateHandler) if isinstance(update, Dispatcher.MESSAGE_UPDATES): if isinstance(update.message, types.MessageEmpty): continue - message = utils.parse_messages( - self.client, - update.message, - users, - chats - ) + message = utils.parse_messages(self.client, update.message, users, chats) + is_edited = isinstance(update, Dispatcher.EDIT_MESSAGE_UPDATES) + is_channel = message.chat.type == "channel" - is_edited_message = isinstance(update, Dispatcher.EDIT_MESSAGE_UPDATES) - - self.dispatch( - pyrogram.Update( - message=((message if message.chat.type != "channel" - else None) if not is_edited_message - else None), - edited_message=((message if message.chat.type != "channel" - else None) if is_edited_message - else None), - channel_post=((message if message.chat.type == "channel" - else None) if not is_edited_message - else None), - edited_channel_post=((message if message.chat.type == "channel" - else None) if is_edited_message - else None) - ) + update = pyrogram.Update( + message=message if not is_channel and not is_edited else None, + edited_message=message if not is_channel and is_edited else None, + channel_post=message if is_channel and not is_edited else None, + edited_channel_post=message if is_channel and is_edited else None ) elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES): - is_channel = hasattr(update, 'channel_id') - + is_channel = hasattr(update, "channel_id") messages = utils.parse_deleted_messages( update.messages, - (update.channel_id if is_channel else None) + update.channel_id if is_channel else None ) - self.dispatch( - pyrogram.Update( - deleted_messages=(messages if not is_channel else None), - deleted_channel_posts=(messages if is_channel else None) - ) + update = pyrogram.Update( + deleted_messages=messages if not is_channel else None, + deleted_channel_posts=messages if is_channel else None ) elif isinstance(update, types.UpdateBotCallbackQuery): - self.dispatch( - pyrogram.Update( - callback_query=utils.parse_callback_query( - self.client, update, users - ) + update = pyrogram.Update( + callback_query=utils.parse_callback_query( + self.client, update, users ) ) elif isinstance(update, types.UpdateInlineBotCallbackQuery): - self.dispatch( - pyrogram.Update( - callback_query=utils.parse_inline_callback_query( - self.client, update, users - ) + update = pyrogram.Update( + callback_query=utils.parse_inline_callback_query( + self.client, update, users ) ) elif isinstance(update, types.UpdateUserStatus): - self.dispatch( - pyrogram.Update( - user_status=utils.parse_user_status( - update.status, update.user_id - ) + update = pyrogram.Update( + user_status=utils.parse_user_status( + update.status, update.user_id ) ) else: continue + + self.dispatch(update) except Exception as e: log.error(e, exc_info=True) log.debug("{} stopped".format(name)) + + def dispatch_raw(self, update, users: dict, chats: dict, handler_class): + for group in self.groups.values(): + for handler in group: + if isinstance(handler, handler_class): + try: + handler.callback(self.client, update, users, chats) + except Exception as e: + log.error(e, exc_info=True) + + # noinspection PyShadowingBuiltins + def dispatch(self, update): + message = update.message or update.channel_post or update.edited_message or update.edited_channel_post + deleted_messages = update.deleted_channel_posts or update.deleted_messages + callback_query = update.callback_query + user_status = update.user_status + + update = message or deleted_messages or callback_query or user_status + + type = ( + MessageHandler if message + else DeletedMessagesHandler if deleted_messages + else CallbackQueryHandler if callback_query + else UserStatusHandler if user_status + else None + ) + + for group in self.groups.values(): + for handler in group: + if isinstance(handler, type): + if handler.check(update): + try: + handler.callback(self.client, update) + except Exception as e: + log.error(e, exc_info=True) From 426cdbbcb86f983e2ed74f60fea73cf91821b325 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Wed, 17 Oct 2018 20:59:33 +0200 Subject: [PATCH 2/6] Don't make use of Update objects when dispatching updates The Update type is used nowhere, adds costly abstraction and makes the code uglier. If I ever need it again (unlikely) I can just revert this. --- pyrogram/client/dispatcher/dispatcher.py | 60 ++++-------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index 4366b56d..53448252 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -22,7 +22,6 @@ from collections import OrderedDict from queue import Queue from threading import Thread -import pyrogram from pyrogram.api import types from ..ext import utils from ..handlers import CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler, RawUpdateHandler @@ -110,50 +109,26 @@ class Dispatcher: continue message = utils.parse_messages(self.client, update.message, users, chats) - is_edited = isinstance(update, Dispatcher.EDIT_MESSAGE_UPDATES) - is_channel = message.chat.type == "channel" - - update = pyrogram.Update( - message=message if not is_channel and not is_edited else None, - edited_message=message if not is_channel and is_edited else None, - channel_post=message if is_channel and not is_edited else None, - edited_channel_post=message if is_channel and is_edited else None - ) + update = message, MessageHandler elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES): - is_channel = hasattr(update, "channel_id") - messages = utils.parse_deleted_messages( + deleted_messages = utils.parse_deleted_messages( update.messages, - update.channel_id if is_channel else None + update.channel_id if hasattr(update, "channel_id") else None ) - update = pyrogram.Update( - deleted_messages=messages if not is_channel else None, - deleted_channel_posts=messages if is_channel else None - ) + update = deleted_messages, DeletedMessagesHandler elif isinstance(update, types.UpdateBotCallbackQuery): - update = pyrogram.Update( - callback_query=utils.parse_callback_query( - self.client, update, users - ) - ) + update = utils.parse_callback_query(self.client, update, users), CallbackQueryHandler elif isinstance(update, types.UpdateInlineBotCallbackQuery): - update = pyrogram.Update( - callback_query=utils.parse_inline_callback_query( - self.client, update, users - ) - ) + update = utils.parse_inline_callback_query(self.client, update, users), CallbackQueryHandler elif isinstance(update, types.UpdateUserStatus): - update = pyrogram.Update( - user_status=utils.parse_user_status( - update.status, update.user_id - ) - ) + update = utils.parse_user_status(update.status, update.user_id), UserStatusHandler else: continue - self.dispatch(update) + self.dispatch(*update) except Exception as e: log.error(e, exc_info=True) @@ -169,25 +144,10 @@ class Dispatcher: log.error(e, exc_info=True) # noinspection PyShadowingBuiltins - def dispatch(self, update): - message = update.message or update.channel_post or update.edited_message or update.edited_channel_post - deleted_messages = update.deleted_channel_posts or update.deleted_messages - callback_query = update.callback_query - user_status = update.user_status - - update = message or deleted_messages or callback_query or user_status - - type = ( - MessageHandler if message - else DeletedMessagesHandler if deleted_messages - else CallbackQueryHandler if callback_query - else UserStatusHandler if user_status - else None - ) - + def dispatch(self, update, handler_class): for group in self.groups.values(): for handler in group: - if isinstance(handler, type): + if isinstance(handler, handler_class): if handler.check(update): try: handler.callback(self.client, update) From 38ff950d0160e93f710e9c0886f0feb706eb9a00 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Wed, 17 Oct 2018 21:00:14 +0200 Subject: [PATCH 3/6] Remove useless #noinspection --- pyrogram/client/dispatcher/dispatcher.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index 53448252..2989d9fa 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -143,7 +143,6 @@ class Dispatcher: except Exception as e: log.error(e, exc_info=True) - # noinspection PyShadowingBuiltins def dispatch(self, update, handler_class): for group in self.groups.values(): for handler in group: From 09e0345868d3d28a46df6a0e79463199c260e8f9 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 18 Oct 2018 21:18:22 +0200 Subject: [PATCH 4/6] Small dispatcher clean ups --- pyrogram/client/dispatcher/dispatcher.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index 2989d9fa..cbfb59e4 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -50,6 +50,7 @@ class Dispatcher: def __init__(self, client, workers): self.client = client self.workers = workers + self.workers_list = [] self.updates = Queue() self.groups = OrderedDict() @@ -69,8 +70,8 @@ class Dispatcher: for _ in range(self.workers): self.updates.put(None) - for i in self.workers_list: - i.join() + for worker in self.workers_list: + worker.join() self.workers_list.clear() @@ -83,8 +84,8 @@ class Dispatcher: def remove_handler(self, handler, group: int): if group not in self.groups: - raise ValueError("Group {} does not exist. " - "Handler was not removed.".format(group)) + raise ValueError("Group {} does not exist. Handler was not removed.".format(group)) + self.groups[group].remove(handler) def update_worker(self): @@ -108,8 +109,7 @@ class Dispatcher: if isinstance(update.message, types.MessageEmpty): continue - message = utils.parse_messages(self.client, update.message, users, chats) - update = message, MessageHandler + update = utils.parse_messages(self.client, update.message, users, chats), MessageHandler elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES): deleted_messages = utils.parse_deleted_messages( From 3f0a355f7eff8eaf623759b9bcb5d25f074ae744 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Fri, 19 Oct 2018 11:54:27 +0200 Subject: [PATCH 5/6] Further optimize and simplify the Dispatcher --- pyrogram/client/dispatcher/dispatcher.py | 88 ++++++++++++------------ pyrogram/client/ext/utils.py | 64 +++++++++-------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index cbfb59e4..f1c14fbe 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -45,9 +45,16 @@ class Dispatcher: types.UpdateDeleteChannelMessages ) + CALLBACK_QUERY_UPDATES = ( + types.UpdateBotCallbackQuery, + types.UpdateInlineBotCallbackQuery + ) + MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES - def __init__(self, client, workers): + UPDATES = None + + def __init__(self, client, workers: int): self.client = client self.workers = workers @@ -55,6 +62,22 @@ class Dispatcher: self.updates = Queue() self.groups = OrderedDict() + Dispatcher.UPDATES = { + Dispatcher.MESSAGE_UPDATES: + lambda upd, usr, cht: (utils.parse_messages(self.client, upd.message, usr, cht), MessageHandler), + + Dispatcher.DELETE_MESSAGE_UPDATES: + lambda upd, usr, cht: (utils.parse_deleted_messages(upd), DeletedMessagesHandler), + + Dispatcher.CALLBACK_QUERY_UPDATES: + lambda upd, usr, cht: (utils.parse_callback_query(self.client, upd, usr), CallbackQueryHandler), + + (types.UpdateUserStatus,): + lambda upd, usr, cht: (utils.parse_user_status(upd.status, upd.user_id), UserStatusHandler) + } + + Dispatcher.UPDATES = {key: value for key_tuple, value in Dispatcher.UPDATES.items() for key in key_tuple} + def start(self): for i in range(self.workers): self.workers_list.append( @@ -103,52 +126,31 @@ class Dispatcher: chats = {i.id: i for i in update[2]} update = update[0] - self.dispatch_raw(update, users=users, chats=chats, handler_class=RawUpdateHandler) + parser = Dispatcher.UPDATES.get(type(update), None) - if isinstance(update, Dispatcher.MESSAGE_UPDATES): - if isinstance(update.message, types.MessageEmpty): - continue - - update = utils.parse_messages(self.client, update.message, users, chats), MessageHandler - - elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES): - deleted_messages = utils.parse_deleted_messages( - update.messages, - update.channel_id if hasattr(update, "channel_id") else None - ) - - update = deleted_messages, DeletedMessagesHandler - - elif isinstance(update, types.UpdateBotCallbackQuery): - update = utils.parse_callback_query(self.client, update, users), CallbackQueryHandler - elif isinstance(update, types.UpdateInlineBotCallbackQuery): - update = utils.parse_inline_callback_query(self.client, update, users), CallbackQueryHandler - elif isinstance(update, types.UpdateUserStatus): - update = utils.parse_user_status(update.status, update.user_id), UserStatusHandler - else: + if parser is None: continue - self.dispatch(*update) + update, handler_type = parser(update, users, chats) + + for group in self.groups.values(): + for handler in group: + args = None + + if isinstance(handler, RawUpdateHandler): + args = (update, users, chats) + elif isinstance(handler, handler_type): + if handler.check(update): + args = (update,) + + if args is not None: + try: + handler.callback(self.client, *args) + except Exception as e: + log.error(e, exc_info=True) + finally: + break except Exception as e: log.error(e, exc_info=True) log.debug("{} stopped".format(name)) - - def dispatch_raw(self, update, users: dict, chats: dict, handler_class): - for group in self.groups.values(): - for handler in group: - if isinstance(handler, handler_class): - try: - handler.callback(self.client, update, users, chats) - except Exception as e: - log.error(e, exc_info=True) - - def dispatch(self, update, handler_class): - for group in self.groups.values(): - for handler in group: - if isinstance(handler, handler_class): - if handler.check(update): - try: - handler.callback(self.client, update) - except Exception as e: - log.error(e, exc_info=True) diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index c7a10db9..fdf7693c 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -764,10 +764,10 @@ def parse_messages( return parsed_messages if is_list else parsed_messages[0] -def parse_deleted_messages( - messages: list, - channel_id: int -) -> pyrogram_types.Messages: +def parse_deleted_messages(update) -> pyrogram_types.Messages: + messages = update.messages + channel_id = getattr(update, "channel_id", None) + parsed_messages = [] for message in messages: @@ -874,42 +874,40 @@ def parse_profile_photos(photos): ) -def parse_callback_query(client, callback_query, users): - peer = callback_query.peer +def parse_callback_query(client, update, users): + message = None + inline_message_id = None - if isinstance(peer, types.PeerUser): - peer_id = peer.user_id - elif isinstance(peer, types.PeerChat): - peer_id = -peer.chat_id - else: - peer_id = int("-100" + str(peer.channel_id)) + if isinstance(update, types.UpdateBotCallbackQuery): + peer = update.peer - return pyrogram_types.CallbackQuery( - id=str(callback_query.query_id), - from_user=parse_user(users[callback_query.user_id]), - message=client.get_messages(peer_id, callback_query.msg_id), - chat_instance=str(callback_query.chat_instance), - data=callback_query.data.decode(), - game_short_name=callback_query.game_short_name, - client=client - ) + if isinstance(peer, types.PeerUser): + peer_id = peer.user_id + elif isinstance(peer, types.PeerChat): + peer_id = -peer.chat_id + else: + peer_id = int("-100" + str(peer.channel_id)) - -def parse_inline_callback_query(client, callback_query, users): - return pyrogram_types.CallbackQuery( - id=str(callback_query.query_id), - from_user=parse_user(users[callback_query.user_id]), - chat_instance=str(callback_query.chat_instance), - inline_message_id=b64encode( + message = client.get_messages(peer_id, update.msg_id) + elif isinstance(update, types.UpdateInlineBotCallbackQuery): + inline_message_id = b64encode( pack( " Date: Fri, 9 Nov 2018 09:21:01 +0100 Subject: [PATCH 6/6] Update dispatcher.py --- pyrogram/client/dispatcher/dispatcher.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index f1c14fbe..fa65f987 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -143,13 +143,15 @@ class Dispatcher: if handler.check(update): args = (update,) - if args is not None: - try: - handler.callback(self.client, *args) - except Exception as e: - log.error(e, exc_info=True) - finally: - break + if args is None: + continue + + try: + handler.callback(self.client, *args) + except Exception as e: + log.error(e, exc_info=True) + finally: + break except Exception as e: log.error(e, exc_info=True)