diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..cc29821 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,28 @@ +# This file contains a list of commits with +# mass changes for exclusion by `git blame`. +# +# Passing `--ignore-revs-file .git-blame-ignore-revs` as a flag will +# tell git to "ignore changes made by the revision when assigning +# blame, as if the change never happened". +# +# For example: +# git blame --ignore-revs-file .git-blame-ignore-revs ... +# +# For extra hot sauce, ignore white space changes too: +# git blame -w --ignore-revs-file .git-blame-ignore-revs ... +# +# You can make this a default for your repo using: +# git config blame.ignoreRevsFile .git-blame-ignore-revs +# +# Also, if you use the GitLens extension for Visual Studio Code, you +# can add "-w" as a value to "gitlens.advanced.blame.customArguments". +# +# Note that `git blame` does not use any file by default, and +# the filename `.git-blame-ignore-revs` is just a convention. + +299c8db5dd9b59cfe450cb7dc425205406acf015 +# Author: xtaodada +# Date: Tue Aug 13 18:38:13 2024 +0800 +# +# :lipstick: Format with black 24.x.x +# diff --git a/pyromod/listen/listen.py b/pyromod/listen/listen.py index 5bdc1cd..a6e841a 100644 --- a/pyromod/listen/listen.py +++ b/pyromod/listen/listen.py @@ -38,6 +38,8 @@ from ..utils.conversation import Conversation from ..utils.errors import TimeoutConversationError, ListenerCanceled pyrogram.errors.ListenerCanceled = ListenerCanceled # noqa +LOCK = asyncio.Lock() +DONE = [] @patch(pyrogram.client.Client) @@ -108,34 +110,50 @@ class Client: @patch(pyrogram.handlers.message_handler.MessageHandler) -class MessageHandler: +class MessageHandler(pyrogram.handlers.message_handler.MessageHandler): @patchable def __init__(self, callback: callable, filters=None): self.user_callback = callback self.old__init__(self.resolve_listener, filters) - @patchable - async def resolve_listener(self, client, message, *args): - listener = client.listening.get(message.chat.id) - if listener and not listener["future"].done(): - listener["future"].set_result(message) - else: + @staticmethod + async def resolve_listener_(self, client, message, *args): + global LOCK, DONE + async with LOCK: + listener = client.listening.get(message.chat.id) + if listener: + with contextlib.suppress(ValueError): + DONE.remove(listener) + if listener and not listener["future"].done(): + listener["future"].set_result(message) + return if listener and listener["future"].done(): client.clear_listener(message.chat.id, listener["future"]) - await self.user_callback(client, message, *args) + await self.user_callback(client, message, *args) + + @patchable + async def resolve_listener(self, client, message, *args): + await MessageHandler.resolve_listener_(self, client, message, *args) + + @staticmethod + async def check_(self, client, update): + global LOCK, DONE + async with LOCK: + listener = client.listening.get(update.chat.id) + if listener and (listener not in DONE) and (not listener["future"].done()): + if callable(listener["filters"]): + result = await listener["filters"](client, update) + if result: + DONE.append(listener) + return result + else: + DONE.append(listener) + return True + return await self.filters(client, update) if callable(self.filters) else True @patchable async def check(self, client, update): - listener = client.listening.get(update.chat.id) - - if listener and not listener["future"].done(): - return ( - await listener["filters"](client, update) - if callable(listener["filters"]) - else True - ) - - return await self.filters(client, update) if callable(self.filters) else True + return await MessageHandler.check_(self, client, update) @patch(pyrogram.handlers.edited_message_handler.EditedMessageHandler) @@ -147,26 +165,11 @@ class EditedMessageHandler: @patchable async def resolve_listener(self, client, message, *args): - listener = client.listening.get(message.chat.id) - if listener and not listener["future"].done(): - listener["future"].set_result(message) - else: - if listener and listener["future"].done(): - client.clear_listener(message.chat.id, listener["future"]) - await self.user_callback(client, message, *args) + await MessageHandler.resolve_listener_(self, client, message, *args) @patchable async def check(self, client, update): - listener = client.listening.get(update.chat.id) - - if listener and not listener["future"].done(): - return ( - await listener["filters"](client, update) - if callable(listener["filters"]) - else True - ) - - return await self.filters(client, update) if callable(self.filters) else True + return await MessageHandler.check_(self, client, update) @patch(pyrogram.types.user_and_chats.chat.Chat)