feat: fetchMember (super fast)

!!! experiment !!!
This commit is contained in:
Elysia 2023-07-17 21:05:58 +07:00
parent b7ef9cb71d
commit 0c456d64cb
4 changed files with 86 additions and 37 deletions

View File

@ -202,11 +202,15 @@ class GuildMemberManager extends CachedManager {
) { ) {
return this._fetchMany(); return this._fetchMany();
} else { } else {
return this.fetchBruteforce({ return this.fetchByMemberSafety();
/*
NOTE: This is a very slow method, and can take up to 999+ minutes to complete.
this.fetchBruteforce({
delay: 50, delay: 50,
skipWarn: true, skipWarn: true,
depth: 1, depth: 1,
}); });
*/
} }
} }
const user = this.client.users.resolveId(options); const user = this.client.users.resolveId(options);
@ -535,6 +539,47 @@ class GuildMemberManager extends CachedManager {
}); });
} }
/**
* Experimental method to fetch all members from the guild.
* @param {number} [timeout=120000] Timeout for receipt of members in ms
* @returns {Promise<Collection<Snowflake, GuildMember>>}
*/
fetchByMemberSafety(timeout = 120_000) {
return new Promise(resolve => {
let timeout_ = setTimeout(() => {
this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
resolve(this.guild.members.cache);
}, timeout).unref();
const handler = (members, guild, raw) => {
if (guild.id == this.guild.id && !raw.nonce && raw.index == 0 && raw.count == 1) {
if (members.size > 0) {
this.client.ws.broadcast({
op: 35,
d: {
guild_id: this.guild.id,
query: '',
continuation_token: members.first()?.id,
},
});
} else {
clearTimeout(timeout_);
this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler);
resolve(this.guild.members.cache);
}
}
};
this.client.on('guildMembersChunk', handler);
this.client.ws.broadcast({
op: 35,
d: {
guild_id: this.guild.id,
query: '',
continuation_token: null,
},
});
});
}
/** /**
* Fetches multiple members from the guild in the channel. * Fetches multiple members from the guild in the channel.
* @param {GuildTextChannelResolvable} channel The channel to get members from (Members has VIEW_CHANNEL permission) * @param {GuildTextChannelResolvable} channel The channel to get members from (Members has VIEW_CHANNEL permission)

View File

@ -287,55 +287,58 @@ exports.Status = {
* * STREAM_WATCH: 20 * * STREAM_WATCH: 20
* * STREAM_PING: 21 # Send * * STREAM_PING: 21 # Send
* * STREAM_SET_PAUSED: 22 * * STREAM_SET_PAUSED: 22
* * REQUEST_GUILD_APPLICATION_COMMANDS: 24 * * LFG_SUBSCRIPTIONS: 23 [Unused]
* * EMBEDDED_ACTIVITY_LAUNCH: 25 * * REQUEST_GUILD_APPLICATION_COMMANDS: 24 [Unused]
* * EMBEDDED_ACTIVITY_CLOSE: 26 * * EMBEDDED_ACTIVITY_LAUNCH: 25 => Launch an embedded activity in a voice channel or call.
* * EMBEDDED_ACTIVITY_UPDATE: 27 * * EMBEDDED_ACTIVITY_CLOSE: 26 => Stop an embedded activity.
* * REQUEST_FORUM_UNREADS: 28 * * EMBEDDED_ACTIVITY_UPDATE: 27 => Update an embedded activity.
* * REMOTE_COMMAND: 29 * * REQUEST_FORUM_UNREADS: 28 => Request forum channel unread counts.
* * GET_DELETED_ENTITY_IDS_NOT_MATCHING_HASH: 30 * * REMOTE_COMMAND: 29 => Send a remote command to an embedded (Xbox, PlayStation) voice session.
* * GET_DELETED_ENTITY_IDS_NOT_MATCHING_HASH: 30 => Request deleted entity IDs not matching a given hash for a guild.
* * REQUEST_SOUNDBOARD_SOUNDS: 31 * * REQUEST_SOUNDBOARD_SOUNDS: 31
* * SPEED_TEST_CREATE: 32 * * SPEED_TEST_CREATE: 32 => Create a voice speed test.
* * SPEED_TEST_DELETE: 33 * * SPEED_TEST_DELETE: 33 => Delete a voice speed test.
* * REQUEST_LAST_MESSAGES: 34 * * REQUEST_LAST_MESSAGES: 34 => Request last messages for a guild's channels.
* * SEARCH_RECENT_MEMBERS: 35 => ~ Opcode 8 (Member Safety)
* @typedef {Object<string, number>} Opcodes * @typedef {Object<string, number>} Opcodes
*/ */
exports.Opcodes = { exports.Opcodes = {
DISPATCH: 0, // # Receive => dispatches an event DISPATCH: 0,
HEARTBEAT: 1, // # Send/Receive => used for ping checking HEARTBEAT: 1,
IDENTIFY: 2, // # Send => used for client handshake IDENTIFY: 2,
STATUS_UPDATE: 3, // # Send => used to update the client status STATUS_UPDATE: 3,
VOICE_STATE_UPDATE: 4, // # Send => used to join/move/leave voice channels VOICE_STATE_UPDATE: 4,
VOICE_GUILD_PING: 5, // # Send => used for voice ping checking VOICE_GUILD_PING: 5,
RESUME: 6, // # Send => used to resume a closed connection RESUME: 6,
RECONNECT: 7, // # Receive => used to tell when to reconnect (sometimes...) RECONNECT: 7,
REQUEST_GUILD_MEMBERS: 8, // # Send => used to request guild members (when searching for members in the search bar of a guild) REQUEST_GUILD_MEMBERS: 8,
INVALID_SESSION: 9, // # Receive => used to notify client they have an invalid session id INVALID_SESSION: 9,
HELLO: 10, // # Receive => sent immediately after connecting, contains heartbeat and server debug information HELLO: 10,
HEARTBEAT_ACK: 11, // # Sent => immediately following a client heartbeat that was received HEARTBEAT_ACK: 11,
GUILD_SYNC: 12, // # Receive => guild_sync but not used anymore GUILD_SYNC: 12,
DM_UPDATE: 13, // # Send => used to get dm features DM_UPDATE: 13,
GUILD_SUBSCRIPTIONS: 14, // # Send => discord responds back with GUILD_MEMBER_LIST_UPDATE type SYNC... GUILD_SUBSCRIPTIONS: 14,
LOBBY_CONNECT: 15, LOBBY_CONNECT: 15,
LOBBY_DISCONNECT: 16, LOBBY_DISCONNECT: 16,
LOBBY_VOICE_STATE_UPDATE: 17, // # Receive LOBBY_VOICE_STATE_UPDATE: 17,
STREAM_CREATE: 18, STREAM_CREATE: 18,
STREAM_DELETE: 19, STREAM_DELETE: 19,
STREAM_WATCH: 20, STREAM_WATCH: 20,
STREAM_PING: 21, // # Send STREAM_PING: 21,
STREAM_SET_PAUSED: 22, STREAM_SET_PAUSED: 22,
REQUEST_GUILD_APPLICATION_COMMANDS: 24, // # Send => request application/bot cmds (user, message, and slash cmds) REQUEST_GUILD_APPLICATION_COMMANDS: 24,
EMBEDDED_ACTIVITY_LAUNCH: 25, EMBEDDED_ACTIVITY_LAUNCH: 25,
EMBEDDED_ACTIVITY_CLOSE: 26, EMBEDDED_ACTIVITY_CLOSE: 26,
EMBEDDED_ACTIVITY_UPDATE: 27, EMBEDDED_ACTIVITY_UPDATE: 27,
REQUEST_FORUM_UNREADS: 28, REQUEST_FORUM_UNREADS: 28, // Payload: { guild_id: Snowflake, channel_id: Snowflake, threads: { thread_id: Snowflake, ack_message_id: Snowflake }[] }
REMOTE_COMMAND: 29, REMOTE_COMMAND: 29, // Payload: { target_session_id: string, payload: any }
GET_DELETED_ENTITY_IDS_NOT_MATCHING_HASH: 30, GET_DELETED_ENTITY_IDS_NOT_MATCHING_HASH: 30, // Payload: { guild_id: Snowflake, channel_ids_hash: string[], role_ids_hash: string[], emoji_ids_hash: string[], sticker_ids_hash: string[] }
REQUEST_SOUNDBOARD_SOUNDS: 31, // Payload: { guild_ids: string[] } REQUEST_SOUNDBOARD_SOUNDS: 31, // Payload: { guild_ids: string[] }
SPEED_TEST_CREATE: 32, SPEED_TEST_CREATE: 32, // Payload: { preferred_region: string }
SPEED_TEST_DELETE: 33, SPEED_TEST_DELETE: 33, // Payload: null
REQUEST_LAST_MESSAGES: 34, // Payload: { guild_id: string, channel_ids: string[] } REQUEST_LAST_MESSAGES: 34, // Payload: { guild_id: string, channel_ids: string[] }
// Update: 30/5/2023 SEARCH_RECENT_MEMBERS: 35, // Payload: { guild_id: string, query: string, continuation_token?: Snowflake }
// Update: 17/7/2023
}; };
/** /**

View File

@ -206,8 +206,8 @@ class Options extends null {
system_locale: 'en-US', system_locale: 'en-US',
browser_user_agent: defaultUA, browser_user_agent: defaultUA,
browser_version: '22.3.12', browser_version: '22.3.12',
client_build_number: 211811, client_build_number: 213510,
native_build_number: 34515, native_build_number: 34898,
client_event_source: null, client_event_source: null,
}, },
compress: false, compress: false,

1
typings/index.d.ts vendored
View File

@ -4135,6 +4135,7 @@ export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, Gu
time?: number, time?: number,
): Promise<Collection<Snowflake, GuildMember>>; ): Promise<Collection<Snowflake, GuildMember>>;
public fetchBruteforce(options?: BruteforceOptions): Promise<Collection<Snowflake, GuildMember>>; public fetchBruteforce(options?: BruteforceOptions): Promise<Collection<Snowflake, GuildMember>>;
public fetchByMemberSafety(timeout?: number): Promise<Collection<Snowflake, GuildMember>>;
public fetchMe(options?: BaseFetchOptions): Promise<GuildMember>; public fetchMe(options?: BaseFetchOptions): Promise<GuildMember>;
public kick(user: UserResolvable, reason?: string): Promise<GuildMember | User | Snowflake>; public kick(user: UserResolvable, reason?: string): Promise<GuildMember | User | Snowflake>;
public list(options?: GuildListMembersOptions): Promise<Collection<Snowflake, GuildMember>>; public list(options?: GuildListMembersOptions): Promise<Collection<Snowflake, GuildMember>>;