diff --git a/discord/client.py b/discord/client.py index 6304fb4e9..2c5ed69cd 100644 --- a/discord/client.py +++ b/discord/client.py @@ -179,7 +179,13 @@ class Client: @property def private_channels(self): - """List[:class:`abc.PrivateChannel`]: The private channels that the connected client is participating on.""" + """List[:class:`abc.PrivateChannel`]: The private channels that the connected client is participating on. + + .. note:: + + This returns only up to 128 most recent private channels due to an internal working + on how Discord deals with private channels. + """ return self._connection.private_channels @property diff --git a/discord/state.py b/discord/state.py index fa74a3841..f2ed82447 100644 --- a/discord/state.py +++ b/discord/state.py @@ -37,7 +37,7 @@ from .calls import GroupCall from . import utils, compat from .embeds import Embed -from collections import deque, namedtuple +from collections import deque, namedtuple, OrderedDict import copy, enum, math import datetime import asyncio @@ -89,7 +89,9 @@ class ConnectionState: self._calls = {} self._guilds = {} self._voice_clients = {} - self._private_channels = {} + + # LRU of max size 128 + self._private_channels = OrderedDict() # extra dict to look up private channels by user id self._private_channels_by_user = {} self._messages = deque(maxlen=self.max_messages) @@ -189,13 +191,27 @@ class ConnectionState: return list(self._private_channels.values()) def _get_private_channel(self, channel_id): - return self._private_channels.get(channel_id) + try: + value = self._private_channels[channel_id] + except KeyError: + return None + else: + self._private_channels.move_to_end(channel_id) + return value def _get_private_channel_by_user(self, user_id): return self._private_channels_by_user.get(user_id) def _add_private_channel(self, channel): - self._private_channels[channel.id] = channel + channel_id = channel.id + self._private_channels[channel_id] = channel + + if len(self._private_channels) > 128: + _, to_remove = self._private_channels.popitem(last=False) + print(to_remove) + if isinstance(to_remove, DMChannel): + self._private_channels_by_user.pop(to_remove.recipient.id, None) + if isinstance(channel, DMChannel): self._private_channels_by_user[channel.recipient.id] = channel