From 7d4e36f0bd8906f9101107f78c76fd1d9df1cf9e Mon Sep 17 00:00:00 2001 From: Rapptz Date: Thu, 23 Jul 2020 00:17:22 -0400 Subject: [PATCH] Update message references in AutoShardedConnectionState Fixes #5133 --- discord/message.py | 8 ++++++++ discord/state.py | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/discord/message.py b/discord/message.py index 5b4d79cb1512..a09c2d73ab24 100644 --- a/discord/message.py +++ b/discord/message.py @@ -524,6 +524,14 @@ def _handle_call(self, call): call['participants'] = participants self.call = CallMessage(message=self, **call) + def _rebind_channel_reference(self, new_channel): + self.channel = new_channel + + try: + del self._cs_guild + except AttributeError: + pass + @utils.cached_slot_property('_cs_guild') def guild(self): """Optional[:class:`Guild`]: The guild that the message belongs to, if applicable.""" diff --git a/discord/state.py b/discord/state.py index 34823845927c..f0e93d352756 100644 --- a/discord/state.py +++ b/discord/state.py @@ -1062,6 +1062,17 @@ def __init__(self, *args, **kwargs): self.shard_ids = () self.shards_launched = asyncio.Event() + def _update_message_references(self): + for msg in self._messages: + if not msg.guild: + continue + + new_guild = self._get_guild(msg.guild.id) + if new_guild is not None and new_guild is not msg.guild: + channel_id = msg.channel.id + channel = new_guild.get_channel(channel_id) or Object(id=channel_id) + msg._rebind_channel_reference(channel) + async def chunker(self, guild_id, query='', limit=0, *, shard_id=None, nonce=None): ws = self._get_websocket(guild_id, shard_id=shard_id) await ws.request_chunks(guild_id, query=query, limit=limit, nonce=nonce) @@ -1141,12 +1152,24 @@ def parse_ready(self, data): if guild.large: guilds.append((guild, guild.unavailable)) + if self._messages: + self._update_message_references() + for pm in data.get('private_channels', []): factory, _ = _channel_factory(pm['type']) self._add_private_channel(factory(me=user, data=pm, state=self)) self.dispatch('connect') self.dispatch('shard_connect', data['__shard_id__']) + + # Much like clear(), if we have a massive deallocation + # then it's better to explicitly call the GC + # Note that in the original ready parsing code this was done + # implicitly via clear() but in the auto sharded client clearing + # the cache would have the consequence of clearing data on other + # shards as well. + gc.collect() + if self._ready_task is None: self._ready_task = asyncio.ensure_future(self._delay_ready(), loop=self.loop)