From 8ed7091d9daa573ab326cae03cf7751be76c1cdf Mon Sep 17 00:00:00 2001 From: dolfies Date: Tue, 16 Nov 2021 19:38:10 -0500 Subject: [PATCH] Improve thread event parsing and add DM closing --- discord/channel.py | 22 ++++++++++++++++++---- discord/gateway.py | 21 ++++++++++----------- discord/state.py | 40 ++++++++++++++++++++++++++-------------- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/discord/channel.py b/discord/channel.py index 1063fd2e5..3ecf9665d 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -448,7 +448,6 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): List[:class:`.Message`] The list of messages that were deleted. """ - if check is MISSING: check = lambda m: True @@ -461,7 +460,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): async for message in iterator: if count == 50: to_delete = ret[-50:] - await _delete_messages(state, channel_id, to_delete) + await state._delete_messages(channel_id, to_delete) count = 0 if not check(message): @@ -472,7 +471,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): # Some messages remaining to poll to_delete = ret[-count:] - await _delete_messages(state, channel_id, to_delete) + await state._delete_messages(channel_id, to_delete) return ret @@ -1805,6 +1804,21 @@ class DMChannel(discord.abc.Messageable, discord.abc.Connectable, Hashable): return PartialMessage(channel=self, id=message_id) + async def close(self): + """|coro| + + "Deletes" the channel. + + In reality, if you recreate a DM with the same user, + all your message history will be there. + + Raises + ------- + HTTPException + Closing the channel failed. + """ + await self._state.http.delete_channel(self.id) + async def connect(self, *, ring=True, **kwargs): await self._get_channel() call = self.call @@ -2075,7 +2089,7 @@ class GroupChannel(discord.abc.Messageable, discord.abc.Connectable, Hashable): Leaving the group failed. """ - await self._state.http.leave_group(self.id) + await self._state.http.delete_channel(self.id) class PartialMessageable(discord.abc.Messageable, Hashable): diff --git a/discord/gateway.py b/discord/gateway.py index 7d484646a..01fc4b855 100644 --- a/discord/gateway.py +++ b/discord/gateway.py @@ -116,7 +116,7 @@ class KeepAliveHandler: # Inspired by enhanced-discord.py/Gnome self.not_responding_msg = 'Gateway has stopped responding. Closing and restarting.' self.no_stop_msg = 'An error occurred while stopping the gateway. Ignoring.' - self._stop_ev = asyncio.Event() + self._stop = asyncio.Event() self._last_send = time.perf_counter() self._last_recv = time.perf_counter() self._last_ack = time.perf_counter() @@ -125,7 +125,7 @@ class KeepAliveHandler: # Inspired by enhanced-discord.py/Gnome async def run(self): while True: try: - await asyncio.wait_for(self._stop_ev.wait(), timeout=self.interval) + await asyncio.wait_for(self._stop.wait(), timeout=self.interval) except asyncio.TimeoutError: pass else: @@ -145,7 +145,6 @@ class KeepAliveHandler: # Inspired by enhanced-discord.py/Gnome data = self.get_payload() _log.debug(self.msg) try: - # Block until sending is complete total = 0 while True: try: @@ -173,7 +172,7 @@ class KeepAliveHandler: # Inspired by enhanced-discord.py/Gnome self.ws.loop.create_task(self.run()) def stop(self): - self._stop_ev.set() + self._stop.set() def tick(self): self._last_recv = time.perf_counter() @@ -235,7 +234,7 @@ class DiscordWebSocket: RECONNECT Receive only. Tells the client to reconnect to a new gateway. REQUEST_MEMBERS - Send only. Asks for the full member list of a guild. + Send only. Asks for the guild members. INVALIDATE_SESSION Receive only. Tells the client to optionally invalidate the session and IDENTIFY again. @@ -268,7 +267,7 @@ class DiscordWebSocket: INVALIDATE_SESSION = 9 HELLO = 10 HEARTBEAT_ACK = 11 - GUILD_SYNC = 12 + GUILD_SYNC = 12 # :( ACCESS_DM = 13 GUILD_SUBSCRIBE = 14 @@ -276,15 +275,15 @@ class DiscordWebSocket: self.socket = socket self.loop = loop - # an empty dispatcher to prevent crashes + # An empty dispatcher to prevent crashes self._dispatch = lambda *args: None - # generic event listeners + # Generic event listeners self._dispatch_listeners = [] # the keep alive self._keep_alive = None self.thread_id = threading.get_ident() - # ws related stuff + # WS related stuff self.session_id = None self.sequence = None self._zlib = zlib.decompressobj() @@ -315,7 +314,7 @@ class DiscordWebSocket: socket = await client.http.ws_connect(gateway) ws = cls(socket, loop=client.loop) - # dynamically add attributes needed + # Dynamically add attributes needed ws.token = client.http.token ws._connection = client._connection ws._discord_parsers = client._connection.parsers @@ -627,7 +626,7 @@ class DiscordWebSocket: } sent = utils._to_json(payload) - _log.debug('Sending "%s" to change status', sent) + _log.debug('Sending "%s" to change presence.', sent) await self.send(sent) async def request_lazy_guild(self, guild_id, *, typing=None, threads=None, activities=None, members=None, channels=None, thread_member_lists=None): diff --git a/discord/state.py b/discord/state.py index 274d9e724..590c7dcc0 100644 --- a/discord/state.py +++ b/discord/state.py @@ -870,6 +870,11 @@ class ConnectionState: if channel is not None: guild._remove_channel(channel) self.dispatch('guild_channel_delete', channel) + else: + channel = self._get_private_channel(channel_id) + if channel is not None: + self._remove_private_channel(channel) + self.dispatch('private_channel_delete', channel) def parse_channel_update(self, data) -> None: channel_type = try_enum(ChannelType, data.get('type')) @@ -956,11 +961,17 @@ class ConnectionState: _log.debug('THREAD_CREATE referencing an unknown guild ID: %s. Discarding.', guild_id) return - thread = Thread(guild=guild, state=self, data=data) - has_thread = guild.get_thread(thread.id) - guild._add_thread(thread) - if not has_thread: - self.dispatch('thread_join', thread) + existing = guild.get_thread(int(data['id'])) + if existing is not None: # Shouldn't happen + old = existing._update(data) + if old is not None: + self.dispatch('thread_update', old, existing) + else: + thread = Thread(guild=guild, state=self, data=data) + guild._add_thread(thread) + self.dispatch('thread_create', thread) + if self.self_id in thread.member_ids: # Thread was created by us/we were added to a private thread + self.dispatch('thread_join', thread) def parse_thread_update(self, data) -> None: guild_id = int(data['guild_id']) @@ -969,16 +980,17 @@ class ConnectionState: _log.debug('THREAD_UPDATE referencing an unknown guild ID: %s. Discarding', guild_id) return - thread_id = int(data['id']) - thread = guild.get_thread(thread_id) - if thread is not None: - old = copy.copy(thread) - thread._update(data) - self.dispatch('thread_update', old, thread) - else: - thread = Thread(guild=guild, state=guild._state, data=data) + existing = guild.get_thread(int(data['id'])) + if existing is not None: + old = existing._update(data) + if old is not None: + self.dispatch('thread_update', old, existing) + else: # Shouldn't happen + thread = Thread(guild=guild, state=self, data=data) guild._add_thread(thread) - self.dispatch('thread_join', thread) + self.dispatch('thread_create', thread) + if self.self_id in thread.member_ids: # Thread was created by us/we were added to a private thread + self.dispatch('thread_join', thread) def parse_thread_delete(self, data) -> None: guild_id = int(data['guild_id'])