Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 67 additions & 8 deletions interactions/api/gateway/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
if TYPE_CHECKING:
from ...client.context import _Context
from ..cache import Storage
from ..models.gw import GuildMembers

log = get_logger("gateway")

Expand Down Expand Up @@ -535,14 +536,25 @@ def _dispatch_event(self, event: str, data: dict) -> None:

self._dispatch.dispatch(f"on_{name}", old_obj or obj)

elif "guild_members_chunk" in name:
self.__modify_guild_cache(name, data, model, obj, ids=ids)

_member_cache: "Storage" = self._http.cache[Member]
obj: GuildMembers
for member in obj.members:
member._guild_id = obj.guild_id
_member_cache.add(member, (obj.guild_id, member.id))

self._dispatch.dispatch(f"on_{name}", obj)

else:
self._dispatch.dispatch(f"on_{name}", obj)

except AttributeError as error:
log.warning(f"An error occurred dispatching {name}: {error}")

def __get_object_id(
self, data: dict, obj: Any, model: Any
self, data: dict, obj: Any, model: type
) -> Optional[Union[Snowflake, Tuple[Snowflake, Snowflake]]]:
"""
Gets an ID from object.
Expand All @@ -552,7 +564,7 @@ def __get_object_id(
:param obj: The object of the event.
:type obj: Any
:param model: The model of the event.
:type model: Any
:type model: type
:return: Object ID
:rtype: Optional[Union[Snowflake, Tuple[Snowflake, Snowflake]]]
"""
Expand Down Expand Up @@ -581,14 +593,14 @@ def __get_object_id(

return id

def __get_object_ids(self, obj: Any, model: Any) -> Optional[List[Snowflake]]:
def __get_object_ids(self, obj: Any, model: type) -> Optional[List[Snowflake]]:
"""
Gets a list of ids of object.

:param obj: The object of the event.
:type obj: Any
:param model: The model of the event.
:type model: Any
:type model: type
:return: Object IDs
:rtype: Optional[Union[Snowflake, Tuple[Snowflake, Snowflake]]]
"""
Expand Down Expand Up @@ -658,11 +670,22 @@ def __modify_guild_cache(
elif "_update" in name and hasattr(obj, "id"):
iterable[index] = obj
break
elif ids is not None and "_update" in name:
elif ids is not None:
objs = getattr(obj, attr, None)
if objs is not None:
iterable.clear()
iterable.extend(objs)
if "_update" in name:
if objs is not None:
iterable.clear()
iterable.extend(objs)
elif "_chunk" in name:
if objs is not None:
for _obj in objs:
for index, __obj in enumerate(iterable):
if __obj.id == _obj.id:
iterable[index] = _obj
break
else:
iterable.append(_obj)

setattr(guild, attr, iterable)

self._http.cache[Guild].add(guild)
Expand Down Expand Up @@ -1051,6 +1074,42 @@ async def _update_presence(self, presence: ClientPresence) -> None:
log.debug(f"UPDATE_PRESENCE: {presence._json}")
self.__presence = presence

async def request_guild_members(
self,
guild_id: int,
limit: int,
query: Optional[str] = None,
presences: Optional[bool] = None,
user_ids: Optional[Union[int, List[int]]] = None,
nonce: Optional[str] = None,
) -> None:
"""Sends an ``REQUEST_MEMBERS`` packet to the gateway.

:param guild_id: ID of the guild to get members for.
:type guild_id: int
:param limit: Maximum number of members to send matching the 'query' parameter. Required when specifying 'query'.
:type limit: int
:param query: String that username starts with.
:type query: Optional[str]
:param presences: Used to specify if we want the presences of the matched members.
:type presences: Optional[bool]
:param user_ids: Used to specify which users you wish to fetch.
:type user_ids: Optional[Union[int, List[int]]]
:param nonce: Nonce to identify the Guild Members Chunk response.
:type nonce: Optional[str]
"""
_data: dict = {"guild_id": guild_id, "query": query or "", "limit": limit}
if presences is not None:
_data["presences"] = presences
if user_ids is not None:
_data["user_ids"] = user_ids
if nonce is not None:
_data["nonce"] = nonce
payload: dict = {"op": OpCodeType.REQUEST_MEMBERS.value, "d": _data}

await self._send_packet(payload)
log.debug(f"REQUEST_MEMBERS: {payload}")

async def close(self) -> None:
"""
Closes the current connection.
Expand Down
4 changes: 2 additions & 2 deletions interactions/api/models/gw.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class GuildMembers(DictSerializerMixin):
A class object representing the gateway event ``GUILD_MEMBERS_CHUNK``.

:ivar Snowflake guild_id: The guild ID of the event.
:ivar List[GuildMember] members: The members of the event.
:ivar List[Member] members: The members of the event.
:ivar int chunk_index: The current chunk index of the event.
:ivar int chunk_count: The total chunk count of the event.
:ivar list not_found: A list of not found members in the event if an invalid request was made.
Expand All @@ -271,7 +271,7 @@ class GuildMembers(DictSerializerMixin):
"""

guild_id: Snowflake = field(converter=Snowflake)
members: List[GuildMember] = field(converter=convert_list(GuildMember))
members: List[Member] = field(converter=convert_list(Member), add_client=True)
chunk_index: int = field()
chunk_count: int = field()
not_found: Optional[list] = field(default=None)
Expand Down
34 changes: 34 additions & 0 deletions interactions/client/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,40 @@ async def modify(

return User(**data)

async def request_guild_members(
self,
guild_id: Union[Guild, Snowflake, int, str],
limit: Optional[int] = MISSING,
query: Optional[str] = MISSING,
presences: Optional[bool] = MISSING,
user_ids: Optional[Union[Snowflake, List[Snowflake]]] = MISSING,
nonce: Optional[str] = MISSING,
) -> None:
"""
Requests guild members via websocket.

:param guild_id: ID of the guild to get members for.
:type guild_id: Union[Guild, Snowflake, int, str]
:param limit: Maximum number of members to send matching the 'query' parameter. Required when specifying 'query'.
:type limit: Optional[int]
:param query: String that username starts with.
:type query: Optional[str]
:param presences: Used to specify if we want the presences of the matched members.
:type presences: Optional[bool]
:param user_ids: Used to specify which users you wish to fetch.
:type user_ids: Optional[Union[Snowflake, List[Snowflake]]]
:param nonce: Nonce to identify the Guild Members Chunk response.
:type nonce: Optional[str]
"""
await self._websocket.request_guild_members(
guild_id=int(guild_id.id) if isinstance(guild_id, Guild) else int(guild_id),
limit=limit if limit is not MISSING else 0,
query=query if query is not MISSING else None,
presences=presences if presences is not MISSING else None,
user_ids=user_ids if user_ids is not MISSING else None,
nonce=nonce if nonce is not MISSING else None,
)

async def _logout(self) -> None:
await self._websocket.close()
await self._http._req.close()
Expand Down