|
3 | 3 | const { setTimeout, clearTimeout } = require('node:timers'); |
4 | 4 | const { Collection } = require('@discordjs/collection'); |
5 | 5 | const { makeURLSearchParams } = require('@discordjs/rest'); |
| 6 | +const { GatewayRateLimitError } = require('@discordjs/util'); |
| 7 | +const { WebSocketShardEvents } = require('@discordjs/ws'); |
6 | 8 | const { DiscordSnowflake } = require('@sapphire/snowflake'); |
7 | | -const { Routes, GatewayOpcodes } = require('discord-api-types/v10'); |
| 9 | +const { Routes, GatewayOpcodes, GatewayDispatchEvents } = require('discord-api-types/v10'); |
8 | 10 | const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } = require('../errors/index.js'); |
9 | 11 | const { BaseGuildVoiceChannel } = require('../structures/BaseGuildVoiceChannel.js'); |
10 | 12 | const { GuildMember } = require('../structures/GuildMember.js'); |
@@ -246,46 +248,65 @@ class GuildMemberManager extends CachedManager { |
246 | 248 | const query = initialQuery ?? (users ? undefined : ''); |
247 | 249 |
|
248 | 250 | return new Promise((resolve, reject) => { |
249 | | - this.guild.client.ws.send(this.guild.shardId, { |
250 | | - op: GatewayOpcodes.RequestGuildMembers, |
251 | | - // eslint-disable-next-line id-length |
252 | | - d: { |
253 | | - guild_id: this.guild.id, |
254 | | - presences, |
255 | | - user_ids: users, |
256 | | - query, |
257 | | - nonce, |
258 | | - limit, |
259 | | - }, |
260 | | - }); |
261 | 251 | const fetchedMembers = new Collection(); |
262 | 252 | let index = 0; |
| 253 | + |
| 254 | + const cleanup = () => { |
| 255 | + /* eslint-disable no-use-before-define */ |
| 256 | + clearTimeout(timeout); |
| 257 | + |
| 258 | + this.client.ws.removeListener(WebSocketShardEvents.Dispatch, rateLimitHandler); |
| 259 | + this.client.removeListener(Events.GuildMembersChunk, handler); |
| 260 | + this.client.decrementMaxListeners(); |
| 261 | + /* eslint-enable no-use-before-define */ |
| 262 | + }; |
| 263 | + |
| 264 | + const timeout = setTimeout(() => { |
| 265 | + cleanup(); |
| 266 | + reject(new DiscordjsError(ErrorCodes.GuildMembersTimeout)); |
| 267 | + }, time).unref(); |
| 268 | + |
263 | 269 | const handler = (members, _, chunk) => { |
264 | 270 | if (chunk.nonce !== nonce) return; |
265 | 271 |
|
266 | | - // eslint-disable-next-line no-use-before-define |
267 | 272 | timeout.refresh(); |
268 | 273 | index++; |
269 | 274 | for (const member of members.values()) { |
270 | 275 | fetchedMembers.set(member.id, member); |
271 | 276 | } |
272 | 277 |
|
273 | 278 | if (members.size < 1_000 || (limit && fetchedMembers.size >= limit) || index === chunk.count) { |
274 | | - // eslint-disable-next-line no-use-before-define |
275 | | - clearTimeout(timeout); |
276 | | - this.client.removeListener(Events.GuildMembersChunk, handler); |
277 | | - this.client.decrementMaxListeners(); |
| 279 | + cleanup(); |
278 | 280 | resolve(users && !Array.isArray(users) && fetchedMembers.size ? fetchedMembers.first() : fetchedMembers); |
279 | 281 | } |
280 | 282 | }; |
281 | 283 |
|
282 | | - const timeout = setTimeout(() => { |
283 | | - this.client.removeListener(Events.GuildMembersChunk, handler); |
284 | | - this.client.decrementMaxListeners(); |
285 | | - reject(new DiscordjsError(ErrorCodes.GuildMembersTimeout)); |
286 | | - }, time).unref(); |
| 284 | + const requestData = { |
| 285 | + guild_id: this.guild.id, |
| 286 | + presences, |
| 287 | + user_ids: users, |
| 288 | + query, |
| 289 | + nonce, |
| 290 | + limit, |
| 291 | + }; |
| 292 | + |
| 293 | + const rateLimitHandler = payload => { |
| 294 | + if (payload.t === GatewayDispatchEvents.RateLimited && payload.d.meta.nonce === nonce) { |
| 295 | + cleanup(); |
| 296 | + reject(new GatewayRateLimitError(payload.d, requestData)); |
| 297 | + } |
| 298 | + }; |
| 299 | + |
| 300 | + this.client.ws.on(WebSocketShardEvents.Dispatch, rateLimitHandler); |
| 301 | + |
287 | 302 | this.client.incrementMaxListeners(); |
288 | 303 | this.client.on(Events.GuildMembersChunk, handler); |
| 304 | + |
| 305 | + this.guild.client.ws.send(this.guild.shardId, { |
| 306 | + op: GatewayOpcodes.RequestGuildMembers, |
| 307 | + // eslint-disable-next-line id-length |
| 308 | + d: requestData, |
| 309 | + }); |
289 | 310 | }); |
290 | 311 | } |
291 | 312 |
|
|
0 commit comments