Browse Source

Add Guild.chunk and deprecated Client.request_offline_members

pull/5849/head
Rapptz 5 years ago
parent
commit
cb8cb557f5
  1. 3
      discord/client.py
  2. 26
      discord/guild.py
  3. 3
      discord/shard.py
  4. 57
      discord/state.py

3
discord/client.py

@ -382,6 +382,7 @@ class Client:
print('Ignoring exception in {}'.format(event_method), file=sys.stderr) print('Ignoring exception in {}'.format(event_method), file=sys.stderr)
traceback.print_exc() traceback.print_exc()
@utils.deprecated('Guild.chunk')
async def request_offline_members(self, *guilds): async def request_offline_members(self, *guilds):
r"""|coro| r"""|coro|
@ -397,7 +398,7 @@ class Client:
.. warning:: .. warning::
This method is deprecated. This method is deprecated. Use :meth:`Guild.chunk` instead.
Parameters Parameters
----------- -----------

26
discord/guild.py

@ -2037,6 +2037,23 @@ class Guild(Hashable):
return Widget(state=self._state, data=data) return Widget(state=self._state, data=data)
async def chunk(self, *, cache=True):
"""|coro|
Requests all members that belong to this guild. In order to use this,
:meth:`Intents.members` must be enabled.
This is a websocket operation and can be slow.
.. versionadded:: 1.5
Parameters
-----------
cache: :class:`bool`
Whether to cache the members as well.
"""
return await self._state.chunk_guild(self, cache=cache)
async def query_members(self, query=None, *, limit=5, user_ids=None, cache=True): async def query_members(self, query=None, *, limit=5, user_ids=None, cache=True):
"""|coro| """|coro|
@ -2049,16 +2066,15 @@ class Guild(Hashable):
Parameters Parameters
----------- -----------
query: :class:`str` query: Optional[:class:`str`]
The string that the username's start with. An empty string The string that the username's start with.
requests all members.
limit: :class:`int` limit: :class:`int`
The maximum number of members to send back. This must be The maximum number of members to send back. This must be
a number between 1 and 100. a number between 5 and 100.
cache: :class:`bool` cache: :class:`bool`
Whether to cache the members internally. This makes operations Whether to cache the members internally. This makes operations
such as :meth:`get_member` work for those that matched. such as :meth:`get_member` work for those that matched.
user_ids: List[:class:`int`] user_ids: Optional[List[:class:`int`]]
List of user IDs to search for. If the user ID is not in the guild then it won't be returned. List of user IDs to search for. If the user ID is not in the guild then it won't be returned.
.. versionadded:: 1.4 .. versionadded:: 1.4

3
discord/shard.py

@ -334,6 +334,7 @@ class AutoShardedClient(Client):
"""Mapping[int, :class:`ShardInfo`]: Returns a mapping of shard IDs to their respective info object.""" """Mapping[int, :class:`ShardInfo`]: Returns a mapping of shard IDs to their respective info object."""
return { shard_id: ShardInfo(parent, self.shard_count) for shard_id, parent in self.__shards.items() } return { shard_id: ShardInfo(parent, self.shard_count) for shard_id, parent in self.__shards.items() }
@utils.deprecated('Guild.chunk')
async def request_offline_members(self, *guilds): async def request_offline_members(self, *guilds):
r"""|coro| r"""|coro|
@ -349,7 +350,7 @@ class AutoShardedClient(Client):
.. warning:: .. warning::
This method is deprecated. This method is deprecated. Use :meth:`Guild.chunk` instead.
Parameters Parameters
----------- -----------

57
discord/state.py

@ -57,12 +57,28 @@ from .object import Object
from .invite import Invite from .invite import Invite
class ChunkRequest: class ChunkRequest:
__slots__ = ('guild_id', 'nonce', 'future') def __init__(self, guild_id, future, resolver, *, cache=True):
def __init__(self, guild_id, future):
self.guild_id = guild_id self.guild_id = guild_id
self.resolver = resolver
self.cache = cache
self.nonce = os.urandom(16).hex() self.nonce = os.urandom(16).hex()
self.future = future self.future = future
self.buffer = [] # List[Member]
def add_members(self, members):
self.buffer.extend(members)
if self.cache:
guild = self.resolver(self.guild_id)
if guild is None:
return
for member in members:
existing = guild.get_member(member.id)
if existing is None or existing.joined_at is None:
guild._add_member(member)
def done(self):
self.future.set_result(self.buffer)
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -156,7 +172,7 @@ class ConnectionState:
# to reconnect loops which cause mass allocations and deallocations. # to reconnect loops which cause mass allocations and deallocations.
gc.collect() gc.collect()
def process_chunk_requests(self, guild_id, nonce, members): def process_chunk_requests(self, guild_id, nonce, members, complete):
removed = [] removed = []
for i, request in enumerate(self._chunk_requests): for i, request in enumerate(self._chunk_requests):
future = request.future future = request.future
@ -165,8 +181,10 @@ class ConnectionState:
continue continue
if request.guild_id == guild_id and request.nonce == nonce: if request.guild_id == guild_id and request.nonce == nonce:
future.set_result(members) request.add_members(members)
removed.append(i) if complete:
request.done()
removed.append(i)
for index in reversed(removed): for index in reversed(removed):
del self._chunk_requests[index] del self._chunk_requests[index]
@ -330,19 +348,13 @@ class ConnectionState:
raise RuntimeError('Somehow do not have a websocket for this guild_id') raise RuntimeError('Somehow do not have a websocket for this guild_id')
future = self.loop.create_future() future = self.loop.create_future()
request = ChunkRequest(guild.id, future) request = ChunkRequest(guild.id, future, self._get_guild, cache=cache)
self._chunk_requests.append(request) self._chunk_requests.append(request)
try: try:
# start the query operation # start the query operation
await ws.request_chunks(guild_id, query=query, limit=limit, user_ids=user_ids, nonce=request.nonce) await ws.request_chunks(guild_id, query=query, limit=limit, user_ids=user_ids, nonce=request.nonce)
members = await asyncio.wait_for(future, timeout=30.0) return await asyncio.wait_for(future, timeout=30.0)
if cache:
for member in members:
guild._add_member(member)
return members
except asyncio.TimeoutError: except asyncio.TimeoutError:
log.warning('Timed out waiting for chunks with query %r and limit %d for guild_id %d', query, limit, guild_id) log.warning('Timed out waiting for chunks with query %r and limit %d for guild_id %d', query, limit, guild_id)
raise raise
@ -747,9 +759,10 @@ class ConnectionState:
return self._add_guild_from_data(data) return self._add_guild_from_data(data)
async def chunk_guild(self, guild, *, wait=True): async def chunk_guild(self, guild, *, wait=True, cache=None):
cache = cache or self._cache_members
future = self.loop.create_future() future = self.loop.create_future()
request = ChunkRequest(guild.id, future) request = ChunkRequest(guild.id, future, self._get_guild, cache=cache)
self._chunk_requests.append(request) self._chunk_requests.append(request)
await self.chunker(guild.id, nonce=request.nonce) await self.chunker(guild.id, nonce=request.nonce)
if wait: if wait:
@ -893,14 +906,8 @@ class ConnectionState:
guild = self._get_guild(guild_id) guild = self._get_guild(guild_id)
members = [Member(guild=guild, data=member, state=self) for member in data.get('members', [])] members = [Member(guild=guild, data=member, state=self) for member in data.get('members', [])]
log.debug('Processed a chunk for %s members in guild ID %s.', len(members), guild_id) log.debug('Processed a chunk for %s members in guild ID %s.', len(members), guild_id)
if self._cache_members: complete = data.get('chunk_index', 0) + 1 == data.get('chunk_count')
for member in members: self.process_chunk_requests(guild_id, data.get('nonce'), members, complete)
existing = guild.get_member(member.id)
if existing is None or existing.joined_at is None:
guild._add_member(member)
if data.get('chunk_index', 0) + 1 == data.get('chunk_count'):
self.process_chunk_requests(guild_id, data.get('nonce'), members)
def parse_guild_integrations_update(self, data): def parse_guild_integrations_update(self, data):
guild = self._get_guild(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
@ -1075,7 +1082,7 @@ class AutoShardedConnectionState(ConnectionState):
current_bucket.append(future) current_bucket.append(future)
else: else:
future = self.loop.create_future() future = self.loop.create_future()
future.set_result(True) future.set_result([])
processed.append((guild, future)) processed.append((guild, future))

Loading…
Cancel
Save