diff --git a/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js b/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js index c70c1b2c5..2a04c68b1 100644 --- a/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +++ b/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js @@ -17,6 +17,14 @@ module.exports = (client, { d: data }) => { * @event Client#guildMembersChunk * @param {Collection} members The members in the chunk * @param {Guild} guild The guild related to the member chunk + * @param {Object} chunk Properties of the received chunk + * @param {number} chunk.index Index of the received chunk + * @param {number} chunk.count Number of chunks the client should receive + * @param {?string} chunk.nonce Nonce for this chunk */ - client.emit(Events.GUILD_MEMBERS_CHUNK, members, guild); + client.emit(Events.GUILD_MEMBERS_CHUNK, members, guild, { + count: data.chunk_count, + index: data.chunk_index, + nonce: data.nonce, + }); }; diff --git a/src/errors/Messages.js b/src/errors/Messages.js index 5b4299d49..cbf4016a6 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -99,6 +99,8 @@ const Messages = { DELETE_GROUP_DM_CHANNEL: "Bots don't have access to Group DM Channels and cannot delete them", FETCH_GROUP_DM_CHANNEL: "Bots don't have access to Group DM Channels and cannot fetch them", + + MEMBER_FETCH_NONCE_LENGTH: 'Nonce length must not exceed 32 characters.', }; for (const [name, message] of Object.entries(Messages)) register(name, message); diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index e1387e8ff..85a09e064 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -1,7 +1,7 @@ 'use strict'; const BaseManager = require('./BaseManager'); -const { Error, TypeError } = require('../errors'); +const { Error, TypeError, RangeError } = require('../errors'); const GuildMember = require('../structures/GuildMember'); const Collection = require('../util/Collection'); const { Events, OPCodes } = require('../util/Constants'); @@ -77,6 +77,7 @@ class GuildMemberManager extends BaseManager { * @property {number} [limit=0] Maximum number of members to request * @property {boolean} [withPresences=false] Whether or not to include the presences * @property {number} [time=120e3] Timeout for receipt of members + * @property {?string} nonce Nonce for this request (32 characters max - default to base 16 now timestamp) */ /** @@ -224,13 +225,21 @@ class GuildMemberManager extends BaseManager { .then(data => this.add(data, cache)); } - _fetchMany({ limit = 0, withPresences: presences = false, user: user_ids, query, time = 120e3 } = {}) { + _fetchMany({ + limit = 0, + withPresences: presences = false, + user: user_ids, + query, + time = 120e3, + nonce = Date.now().toString(16), + } = {}) { return new Promise((resolve, reject) => { if (this.guild.memberCount === this.cache.size && !query && !limit && !presences && !user_ids) { resolve(this.cache); return; } if (!query && !user_ids) query = ''; + if (nonce.length > 32) throw new RangeError('MEMBER_FETCH_NONCE_LENGTH'); this.guild.shard.send({ op: OPCodes.REQUEST_GUILD_MEMBERS, d: { @@ -238,21 +247,25 @@ class GuildMemberManager extends BaseManager { presences, user_ids, query, + nonce, limit, }, }); const fetchedMembers = new Collection(); const option = query || limit || presences || user_ids; - const handler = (members, guild) => { - if (guild.id !== this.guild.id) return; + let i = 0; + const handler = (members, _, chunk) => { timeout.refresh(); + if (chunk.nonce !== nonce) return; + i++; for (const member of members.values()) { if (option) fetchedMembers.set(member.id, member); } if ( this.guild.memberCount <= this.cache.size || (option && members.size < 1000) || - (limit && fetchedMembers.size >= limit) + (limit && fetchedMembers.size >= limit) || + i === chunk.count ) { this.guild.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler); let fetched = option ? fetchedMembers : this.cache; diff --git a/typings/index.d.ts b/typings/index.d.ts index fffff77d8..971916028 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -2200,7 +2200,11 @@ declare module 'discord.js' { guildMemberAdd: [GuildMember | PartialGuildMember]; guildMemberAvailable: [GuildMember | PartialGuildMember]; guildMemberRemove: [GuildMember | PartialGuildMember]; - guildMembersChunk: [Collection, Guild]; + guildMembersChunk: [ + Collection, + Guild, + { count: number; index: number; nonce: string | undefined }, + ]; guildMemberSpeaking: [GuildMember | PartialGuildMember, Readonly]; guildMemberUpdate: [GuildMember | PartialGuildMember, GuildMember | PartialGuildMember]; guildUpdate: [Guild, Guild]; @@ -2390,6 +2394,7 @@ declare module 'discord.js' { limit?: number; withPresences?: boolean; time?: number; + nonce?: string; } interface FileOptions {