From 59c11e71a22a5c88c86175fe78b3bdf1114c6f9d Mon Sep 17 00:00:00 2001 From: Nadir Chowdhury Date: Thu, 31 Dec 2020 18:50:22 +0000 Subject: [PATCH] Implement presences for `Guild.query_members` --- discord/gateway.py | 3 ++- discord/guild.py | 17 ++++++++++++++--- discord/state.py | 23 +++++++++++++++++------ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/discord/gateway.py b/discord/gateway.py index ed583495a..4fe64a655 100644 --- a/discord/gateway.py +++ b/discord/gateway.py @@ -636,11 +636,12 @@ class DiscordWebSocket: } await self.send_as_json(payload) - async def request_chunks(self, guild_id, query=None, *, limit, user_ids=None, nonce=None): + async def request_chunks(self, guild_id, query=None, *, limit, user_ids=None, presences, nonce=None): payload = { 'op': self.REQUEST_MEMBERS, 'd': { 'guild_id': guild_id, + 'presences': presences, 'limit': limit } } diff --git a/discord/guild.py b/discord/guild.py index a86dd5cc3..2dd6a0128 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -2108,7 +2108,7 @@ class Guild(Hashable): 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, presences=False, cache=True): """|coro| Request members that belong to this guild whose username starts with @@ -2125,6 +2125,12 @@ class Guild(Hashable): limit: :class:`int` The maximum number of members to send back. This must be a number between 5 and 100. + presences: :class:`bool` + Whether to request for presences to be provided. This defaults + to ``False``. + + .. versionadded:: 1.6 + cache: :class:`bool` Whether to cache the members internally. This makes operations such as :meth:`get_member` work for those that matched. @@ -2140,6 +2146,8 @@ class Guild(Hashable): The query timed out waiting for the members. ValueError Invalid parameters were passed to the function + ClientException + The presences intent is not enabled. Returns -------- @@ -2147,6 +2155,9 @@ class Guild(Hashable): The list of members that have matched the query. """ + if presences and not self._state._intents.presences: + raise ClientException('Intents.presences must be enabled to use this.') + if query is None: if query == '': raise ValueError('Cannot pass empty query string.') @@ -2156,9 +2167,9 @@ class Guild(Hashable): if user_ids is not None and query is not None: raise ValueError('Cannot pass both query and user_ids') - + limit = min(100, limit or 5) - return await self._state.query_members(self, query=query, limit=limit, user_ids=user_ids, cache=cache) + return await self._state.query_members(self, query=query, limit=limit, user_ids=user_ids, presences=presences, cache=cache) async def change_voice_state(self, *, channel, self_mute=False, self_deaf=False): """|coro| diff --git a/discord/state.py b/discord/state.py index e05851c5f..214313aec 100644 --- a/discord/state.py +++ b/discord/state.py @@ -382,11 +382,11 @@ class ConnectionState: return channel or Object(id=channel_id), guild - async def chunker(self, guild_id, query='', limit=0, *, nonce=None): + async def chunker(self, guild_id, query='', limit=0, presences=False, *, nonce=None): ws = self._get_websocket(guild_id) # This is ignored upstream - await ws.request_chunks(guild_id, query=query, limit=limit, nonce=nonce) + await ws.request_chunks(guild_id, query=query, limit=limit, presences=presences, nonce=nonce) - async def query_members(self, guild, query, limit, user_ids, cache): + async def query_members(self, guild, query, limit, user_ids, cache, presences): guild_id = guild.id ws = self._get_websocket(guild_id) if ws is None: @@ -397,7 +397,7 @@ class ConnectionState: try: # 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, presences=presences, nonce=request.nonce) return await asyncio.wait_for(request.wait(), timeout=30.0) except asyncio.TimeoutError: log.warning('Timed out waiting for chunks with query %r and limit %d for guild_id %d', query, limit, guild_id) @@ -967,8 +967,19 @@ class ConnectionState: def parse_guild_members_chunk(self, data): guild_id = int(data['guild_id']) guild = self._get_guild(guild_id) + presences = data.get('presences', []) + 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) + + if presences: + member_dict = {str(member.id): member for member in members} + for presence in presences: + user = presence['user'] + member_id = user['id'] + member = member_dict.get(member_id) + member._presence_update(presence, user) + complete = data.get('chunk_index', 0) + 1 == data.get('chunk_count') self.process_chunk_requests(guild_id, data.get('nonce'), members, complete) @@ -1121,9 +1132,9 @@ class AutoShardedConnectionState(ConnectionState): 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): + async def chunker(self, guild_id, query='', limit=0, presences=False, *, 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) + await ws.request_chunks(guild_id, query=query, limit=limit, presences=presences, nonce=nonce) async def _delay_ready(self): await self.shards_launched.wait()