Skip to content

Commit 740f0c8

Browse files
DamegoToricane
andauthored
feat: Add support for REQUEST_MEMBERS packet sending (#1089)
* feat: Add `REQUEST_MEMBERS` support * fix: attributeerror * refactor: convert to `Member` & add http * refactor: change typehints * Update interactions/api/gateway/client.py Co-authored-by: Toricane <[email protected]> * Update interactions/api/gateway/client.py Co-authored-by: Toricane <[email protected]> * ref: optimize condition * refactor: use elif Co-authored-by: Toricane <[email protected]>
1 parent 9c11f37 commit 740f0c8

File tree

3 files changed

+100
-10
lines changed

3 files changed

+100
-10
lines changed

interactions/api/gateway/client.py

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
if TYPE_CHECKING:
4646
from ...client.context import _Context
4747
from ..cache import Storage
48+
from ..models.gw import GuildMembers
4849

4950
log = get_logger("gateway")
5051

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

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

539+
elif "guild_members_chunk" in name:
540+
self.__modify_guild_cache(name, data, model, obj, ids=ids)
541+
542+
_member_cache: "Storage" = self._http.cache[Member]
543+
obj: GuildMembers
544+
for member in obj.members:
545+
member._guild_id = obj.guild_id
546+
_member_cache.add(member, (obj.guild_id, member.id))
547+
548+
self._dispatch.dispatch(f"on_{name}", obj)
549+
538550
else:
539551
self._dispatch.dispatch(f"on_{name}", obj)
540552

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

544556
def __get_object_id(
545-
self, data: dict, obj: Any, model: Any
557+
self, data: dict, obj: Any, model: type
546558
) -> Optional[Union[Snowflake, Tuple[Snowflake, Snowflake]]]:
547559
"""
548560
Gets an ID from object.
@@ -552,7 +564,7 @@ def __get_object_id(
552564
:param obj: The object of the event.
553565
:type obj: Any
554566
:param model: The model of the event.
555-
:type model: Any
567+
:type model: type
556568
:return: Object ID
557569
:rtype: Optional[Union[Snowflake, Tuple[Snowflake, Snowflake]]]
558570
"""
@@ -581,14 +593,14 @@ def __get_object_id(
581593

582594
return id
583595

584-
def __get_object_ids(self, obj: Any, model: Any) -> Optional[List[Snowflake]]:
596+
def __get_object_ids(self, obj: Any, model: type) -> Optional[List[Snowflake]]:
585597
"""
586598
Gets a list of ids of object.
587599
588600
:param obj: The object of the event.
589601
:type obj: Any
590602
:param model: The model of the event.
591-
:type model: Any
603+
:type model: type
592604
:return: Object IDs
593605
:rtype: Optional[Union[Snowflake, Tuple[Snowflake, Snowflake]]]
594606
"""
@@ -648,7 +660,7 @@ def __modify_guild_cache(
648660
if iterable is not None and isinstance(iterable, list):
649661
if "_create" in name or "_add" in name:
650662
iterable.append(obj)
651-
if id:
663+
elif id:
652664
_id = id[1] if isinstance(id, tuple) else id
653665
for index, __obj in enumerate(iterable):
654666
if __obj.id == _id:
@@ -658,11 +670,19 @@ def __modify_guild_cache(
658670
elif "_update" in name and hasattr(obj, "id"):
659671
iterable[index] = obj
660672
break
661-
elif ids is not None and "_update" in name:
662-
objs = getattr(obj, attr, None)
663-
if objs is not None:
673+
elif ids is not None and (objs := getattr(obj, attr, None)) is not None:
674+
if "_update" in name:
664675
iterable.clear()
665676
iterable.extend(objs)
677+
elif "_chunk" in name:
678+
for _obj in objs:
679+
for index, __obj in enumerate(iterable):
680+
if __obj.id == _obj.id:
681+
iterable[index] = _obj
682+
break
683+
else:
684+
iterable.append(_obj)
685+
666686
setattr(guild, attr, iterable)
667687

668688
self._http.cache[Guild].add(guild)
@@ -1060,6 +1080,42 @@ async def _update_presence(self, presence: ClientPresence) -> None:
10601080
log.debug(f"UPDATE_PRESENCE: {presence._json}")
10611081
self.__presence = presence
10621082

1083+
async def request_guild_members(
1084+
self,
1085+
guild_id: int,
1086+
limit: int,
1087+
query: Optional[str] = None,
1088+
presences: Optional[bool] = None,
1089+
user_ids: Optional[Union[int, List[int]]] = None,
1090+
nonce: Optional[str] = None,
1091+
) -> None:
1092+
"""Sends an ``REQUEST_MEMBERS`` packet to the gateway.
1093+
1094+
:param guild_id: ID of the guild to get members for.
1095+
:type guild_id: int
1096+
:param limit: Maximum number of members to send matching the 'query' parameter. Required when specifying 'query'.
1097+
:type limit: int
1098+
:param query: String that username starts with.
1099+
:type query: Optional[str]
1100+
:param presences: Used to specify if we want the presences of the matched members.
1101+
:type presences: Optional[bool]
1102+
:param user_ids: Used to specify which users you wish to fetch.
1103+
:type user_ids: Optional[Union[int, List[int]]]
1104+
:param nonce: Nonce to identify the Guild Members Chunk response.
1105+
:type nonce: Optional[str]
1106+
"""
1107+
_data: dict = {"guild_id": guild_id, "query": query or "", "limit": limit}
1108+
if presences is not None:
1109+
_data["presences"] = presences
1110+
if user_ids is not None:
1111+
_data["user_ids"] = user_ids
1112+
if nonce is not None:
1113+
_data["nonce"] = nonce
1114+
payload: dict = {"op": OpCodeType.REQUEST_MEMBERS.value, "d": _data}
1115+
1116+
await self._send_packet(payload)
1117+
log.debug(f"REQUEST_MEMBERS: {payload}")
1118+
10631119
async def close(self) -> None:
10641120
"""
10651121
Closes the current connection.

interactions/api/models/gw.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class GuildMembers(DictSerializerMixin):
262262
A class object representing the gateway event ``GUILD_MEMBERS_CHUNK``.
263263
264264
:ivar Snowflake guild_id: The guild ID of the event.
265-
:ivar List[GuildMember] members: The members of the event.
265+
:ivar List[Member] members: The members of the event.
266266
:ivar int chunk_index: The current chunk index of the event.
267267
:ivar int chunk_count: The total chunk count of the event.
268268
:ivar list not_found: A list of not found members in the event if an invalid request was made.
@@ -271,7 +271,7 @@ class GuildMembers(DictSerializerMixin):
271271
"""
272272

273273
guild_id: Snowflake = field(converter=Snowflake)
274-
members: List[GuildMember] = field(converter=convert_list(GuildMember))
274+
members: List[Member] = field(converter=convert_list(Member), add_client=True)
275275
chunk_index: int = field()
276276
chunk_count: int = field()
277277
not_found: Optional[list] = field(default=None)

interactions/client/bot.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,40 @@ async def modify(
14811481

14821482
return User(**data)
14831483

1484+
async def request_guild_members(
1485+
self,
1486+
guild_id: Union[Guild, Snowflake, int, str],
1487+
limit: Optional[int] = MISSING,
1488+
query: Optional[str] = MISSING,
1489+
presences: Optional[bool] = MISSING,
1490+
user_ids: Optional[Union[Snowflake, List[Snowflake]]] = MISSING,
1491+
nonce: Optional[str] = MISSING,
1492+
) -> None:
1493+
"""
1494+
Requests guild members via websocket.
1495+
1496+
:param guild_id: ID of the guild to get members for.
1497+
:type guild_id: Union[Guild, Snowflake, int, str]
1498+
:param limit: Maximum number of members to send matching the 'query' parameter. Required when specifying 'query'.
1499+
:type limit: Optional[int]
1500+
:param query: String that username starts with.
1501+
:type query: Optional[str]
1502+
:param presences: Used to specify if we want the presences of the matched members.
1503+
:type presences: Optional[bool]
1504+
:param user_ids: Used to specify which users you wish to fetch.
1505+
:type user_ids: Optional[Union[Snowflake, List[Snowflake]]]
1506+
:param nonce: Nonce to identify the Guild Members Chunk response.
1507+
:type nonce: Optional[str]
1508+
"""
1509+
await self._websocket.request_guild_members(
1510+
guild_id=int(guild_id.id) if isinstance(guild_id, Guild) else int(guild_id),
1511+
limit=limit if limit is not MISSING else 0,
1512+
query=query if query is not MISSING else None,
1513+
presences=presences if presences is not MISSING else None,
1514+
user_ids=user_ids if user_ids is not MISSING else None,
1515+
nonce=nonce if nonce is not MISSING else None,
1516+
)
1517+
14841518
async def _logout(self) -> None:
14851519
await self._websocket.close()
14861520
await self._http._req.close()

0 commit comments

Comments
 (0)