2022-03-19 10:37:45 +00:00
'use strict' ;
const { Buffer } = require ( 'node:buffer' ) ;
2022-03-24 10:55:32 +00:00
const { setTimeout } = require ( 'node:timers' ) ;
2022-03-19 10:37:45 +00:00
const { Collection } = require ( '@discordjs/collection' ) ;
const CachedManager = require ( './CachedManager' ) ;
const { Error , TypeError , RangeError } = require ( '../errors' ) ;
const BaseGuildVoiceChannel = require ( '../structures/BaseGuildVoiceChannel' ) ;
const { GuildMember } = require ( '../structures/GuildMember' ) ;
const { Role } = require ( '../structures/Role' ) ;
2022-03-24 10:55:32 +00:00
const { Events , Opcodes } = require ( '../util/Constants' ) ;
2022-08-04 12:26:16 +00:00
const DataResolver = require ( '../util/DataResolver' ) ;
2022-03-24 10:55:32 +00:00
const SnowflakeUtil = require ( '../util/SnowflakeUtil' ) ;
2022-03-19 10:37:45 +00:00
/ * *
* Manages API methods for GuildMembers and stores their cache .
* @ extends { CachedManager }
* /
class GuildMemberManager extends CachedManager {
constructor ( guild , iterable ) {
super ( guild . client , GuildMember , iterable ) ;
/ * *
* The guild this manager belongs to
* @ type { Guild }
* /
this . guild = guild ;
}
/ * *
* The cache of this Manager
* @ type { Collection < Snowflake , GuildMember > }
* @ name GuildMemberManager # cache
* /
_add ( data , cache = true ) {
return super . _add ( data , cache , { id : data . user . id , extras : [ this . guild ] } ) ;
}
/ * *
* Data that resolves to give a GuildMember object . This can be :
* * A GuildMember object
* * A User resolvable
* @ typedef { GuildMember | UserResolvable } GuildMemberResolvable
* /
/ * *
* Resolves a { @ link GuildMemberResolvable } to a { @ link GuildMember } object .
* @ param { GuildMemberResolvable } member The user that is part of the guild
* @ returns { ? GuildMember }
* /
resolve ( member ) {
const memberResolvable = super . resolve ( member ) ;
if ( memberResolvable ) return memberResolvable ;
const userResolvable = this . client . users . resolveId ( member ) ;
if ( userResolvable ) return super . resolve ( userResolvable ) ;
return null ;
}
/ * *
* Resolves a { @ link GuildMemberResolvable } to a member id .
* @ param { GuildMemberResolvable } member The user that is part of the guild
* @ returns { ? Snowflake }
* /
resolveId ( member ) {
const memberResolvable = super . resolveId ( member ) ;
if ( memberResolvable ) return memberResolvable ;
const userResolvable = this . client . users . resolveId ( member ) ;
return this . cache . has ( userResolvable ) ? userResolvable : null ;
}
/ * *
* Options used to add a user to a guild using OAuth2 .
* @ typedef { Object } AddGuildMemberOptions
* @ property { string } accessToken An OAuth2 access token for the user with the ` guilds.join ` scope granted to the
* bot ' s application
* @ property { string } [ nick ] The nickname to give to the member ( requires ` MANAGE_NICKNAMES ` )
* @ property { Collection < Snowflake , Role > | RoleResolvable [ ] } [ roles ] The roles to add to the member
* ( requires ` MANAGE_ROLES ` )
* @ property { boolean } [ mute ] Whether the member should be muted ( requires ` MUTE_MEMBERS ` )
* @ property { boolean } [ deaf ] Whether the member should be deafened ( requires ` DEAFEN_MEMBERS ` )
* @ property { boolean } [ force ] Whether to skip the cache check and call the API directly
* @ property { boolean } [ fetchWhenExisting = true ] Whether to fetch the user if not cached and already a member
* /
/ * *
* Adds a user to the guild using OAuth2 . Requires the ` CREATE_INSTANT_INVITE ` permission .
* @ param { UserResolvable } user The user to add to the guild
* @ param { AddGuildMemberOptions } options Options for adding the user to the guild
* @ returns { Promise < GuildMember | null > }
* /
async add ( user , options ) {
const userId = this . client . users . resolveId ( user ) ;
if ( ! userId ) throw new TypeError ( 'INVALID_TYPE' , 'user' , 'UserResolvable' ) ;
if ( ! options . force ) {
const cachedUser = this . cache . get ( userId ) ;
if ( cachedUser ) return cachedUser ;
}
const resolvedOptions = {
access _token : options . accessToken ,
nick : options . nick ,
mute : options . mute ,
deaf : options . deaf ,
} ;
if ( options . roles ) {
if ( ! Array . isArray ( options . roles ) && ! ( options . roles instanceof Collection ) ) {
throw new TypeError ( 'INVALID_TYPE' , 'options.roles' , 'Array or Collection of Roles or Snowflakes' , true ) ;
}
const resolvedRoles = [ ] ;
for ( const role of options . roles . values ( ) ) {
const resolvedRole = this . guild . roles . resolveId ( role ) ;
if ( ! resolvedRole ) throw new TypeError ( 'INVALID_ELEMENT' , 'Array or Collection' , 'options.roles' , role ) ;
resolvedRoles . push ( resolvedRole ) ;
}
resolvedOptions . roles = resolvedRoles ;
}
2022-03-24 10:55:32 +00:00
const data = await this . client . api . guilds ( this . guild . id ) . members ( userId ) . put ( { data : resolvedOptions } ) ;
2022-03-19 10:37:45 +00:00
// Data is an empty buffer if the member is already part of the guild.
return data instanceof Buffer ? ( options . fetchWhenExisting === false ? null : this . fetch ( userId ) ) : this . _add ( data ) ;
}
/ * *
* Options used to fetch a single member from a guild .
* @ typedef { BaseFetchOptions } FetchMemberOptions
* @ property { UserResolvable } user The user to fetch
* /
/ * *
* Options used to fetch multiple members from a guild .
* @ typedef { Object } FetchMembersOptions
* @ property { UserResolvable | UserResolvable [ ] } user The user ( s ) to fetch
* @ property { ? string } query Limit fetch to members with similar usernames
* @ 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 )
* @ property { boolean } [ force = false ] Whether to skip the cache check and request the API
* /
/ * *
* Fetches member ( s ) from Discord , even if they ' re offline .
* @ param { UserResolvable | FetchMemberOptions | FetchMembersOptions } [ options ] If a UserResolvable , the user to fetch .
* If undefined , fetches all members .
* If a query , it limits the results to users with similar usernames .
* @ returns { Promise < GuildMember | Collection < Snowflake , GuildMember >> }
* @ example
* // Fetch all members from a guild
* guild . members . fetch ( )
* . then ( console . log )
* . catch ( console . error ) ;
* @ example
* // Fetch a single member
* guild . members . fetch ( '66564597481480192' )
* . then ( console . log )
* . catch ( console . error ) ;
* @ example
* // Fetch a single member without checking cache
* guild . members . fetch ( { user , force : true } )
* . then ( console . log )
* . catch ( console . error )
* @ example
* // Fetch a single member without caching
* guild . members . fetch ( { user , cache : false } )
* . then ( console . log )
* . catch ( console . error ) ;
* @ example
* // Fetch by an array of users including their presences
* guild . members . fetch ( { user : [ '66564597481480192' , '191615925336670208' ] , withPresences : true } )
* . then ( console . log )
* . catch ( console . error ) ;
* @ example
* // Fetch by query
* guild . members . fetch ( { query : 'hydra' , limit : 1 } )
* . then ( console . log )
* . catch ( console . error ) ;
* /
fetch ( options ) {
if ( ! options ) return this . _fetchMany ( ) ;
const user = this . client . users . resolveId ( options ) ;
if ( user ) return this . _fetchSingle ( { user , cache : true } ) ;
if ( options . user ) {
if ( Array . isArray ( options . user ) ) {
options . user = options . user . map ( u => this . client . users . resolveId ( u ) ) ;
return this . _fetchMany ( options ) ;
} else {
options . user = this . client . users . resolveId ( options . user ) ;
}
if ( ! options . limit && ! options . withPresences ) return this . _fetchSingle ( options ) ;
}
return this . _fetchMany ( options ) ;
}
/ * *
* Options used for searching guild members .
* @ typedef { Object } GuildSearchMembersOptions
* @ property { string } query Filter members whose username or nickname start with this query
2022-03-24 10:55:32 +00:00
* @ property { number } [ limit = 1 ] Maximum number of members to search
2022-03-19 10:37:45 +00:00
* @ property { boolean } [ cache = true ] Whether or not to cache the fetched member ( s )
* /
/ * *
* Searches for members in the guild based on a query .
* @ param { GuildSearchMembersOptions } options Options for searching members
* @ returns { Promise < Collection < Snowflake , GuildMember >> }
* /
2022-03-24 10:55:32 +00:00
async search ( { query , limit = 1 , cache = true } = { } ) {
const data = await this . client . api . guilds ( this . guild . id ) . members . search . get ( { query : { query , limit } } ) ;
2022-03-19 10:37:45 +00:00
return data . reduce ( ( col , member ) => col . set ( member . user . id , this . _add ( member , cache ) ) , new Collection ( ) ) ;
}
/ * *
* Options used for listing guild members .
* @ typedef { Object } GuildListMembersOptions
* @ property { Snowflake } [ after ] Limit fetching members to those with an id greater than the supplied id
2022-03-24 10:55:32 +00:00
* @ property { number } [ limit = 1 ] Maximum number of members to list
2022-03-19 10:37:45 +00:00
* @ property { boolean } [ cache = true ] Whether or not to cache the fetched member ( s )
* /
/ * *
* Lists up to 1000 members of the guild .
* @ param { GuildListMembersOptions } [ options ] Options for listing members
* @ returns { Promise < Collection < Snowflake , GuildMember >> }
* /
2022-03-24 10:55:32 +00:00
async list ( { after , limit = 1 , cache = true } = { } ) {
const data = await this . client . api . guilds ( this . guild . id ) . members . get ( { query : { after , limit } } ) ;
2022-03-19 10:37:45 +00:00
return data . reduce ( ( col , member ) => col . set ( member . user . id , this . _add ( member , cache ) ) , new Collection ( ) ) ;
}
/ * *
* The data for editing a guild member .
* @ typedef { Object } GuildMemberEditData
* @ property { ? string } [ nick ] The nickname to set for the member
* @ property { Collection < Snowflake , Role > | RoleResolvable [ ] } [ roles ] The roles or role ids to apply
* @ property { boolean } [ mute ] Whether or not the member should be muted
* @ property { boolean } [ deaf ] Whether or not the member should be deafened
* @ property { GuildVoiceChannelResolvable | null } [ channel ] Channel to move the member to
* ( if they are connected to voice ) , or ` null ` if you want to disconnect them from voice
* @ property { DateResolvable | null } [ communicationDisabledUntil ] The date or timestamp
* for the member ' s communication to be disabled until . Provide ` null ` to enable communication again .
2022-08-04 12:26:16 +00:00
* @ property { ? ( BufferResolvable | Base64Resolvable ) } [ avatar ] The new guild avatar
* @ property { ? ( BufferResolvable | Base64Resolvable ) } [ banner ] The new guild banner
* @ property { ? string } [ bio ] The new guild about me
2022-03-19 10:37:45 +00:00
* /
/ * *
* Edits a member of the guild .
* < info > The user must be a member of the guild < / i n f o >
* @ param { UserResolvable } user The member to edit
* @ param { GuildMemberEditData } data The data to edit the member with
* @ param { string } [ reason ] Reason for editing this user
* @ returns { Promise < GuildMember > }
* /
async edit ( user , data , reason ) {
const id = this . client . users . resolveId ( user ) ;
if ( ! id ) throw new TypeError ( 'INVALID_TYPE' , 'user' , 'UserResolvable' ) ;
// Clone the data object for immutability
const _data = { ... data } ;
if ( _data . channel ) {
_data . channel = this . guild . channels . resolve ( _data . channel ) ;
if ( ! ( _data . channel instanceof BaseGuildVoiceChannel ) ) {
throw new Error ( 'GUILD_VOICE_CHANNEL_RESOLVE' ) ;
}
_data . channel _id = _data . channel . id ;
_data . channel = undefined ;
} else if ( _data . channel === null ) {
_data . channel _id = null ;
_data . channel = undefined ;
}
_data . roles && = _data . roles . map ( role => ( role instanceof Role ? role . id : role ) ) ;
_data . communication _disabled _until =
2022-03-24 10:55:32 +00:00
_data . communicationDisabledUntil && new Date ( _data . communicationDisabledUntil ) . toISOString ( ) ;
2022-03-19 10:37:45 +00:00
2022-08-04 12:26:16 +00:00
// Avatar, banner, bio
if ( typeof _data . avatar !== 'undefined' ) {
_data . avatar = await DataResolver . resolveImage ( _data . avatar ) ;
}
if ( typeof _data . banner !== 'undefined' ) {
_data . banner = await DataResolver . resolveImage ( _data . banner ) ;
}
2022-03-19 10:37:45 +00:00
let endpoint = this . client . api . guilds ( this . guild . id ) ;
if ( id === this . client . user . id ) {
const keys = Object . keys ( data ) ;
2022-08-04 12:26:16 +00:00
if ( keys . length === 1 && [ 'nick' , 'avatar' , 'banner' , 'bio' ] . includes ( keys [ 0 ] ) ) {
endpoint = endpoint . members ( '@me' ) ;
} else {
endpoint = endpoint . members ( id ) ;
}
2022-03-19 10:37:45 +00:00
} else {
endpoint = endpoint . members ( id ) ;
}
const d = await endpoint . patch ( { data : _data , reason } ) ;
const clone = this . cache . get ( id ) ? . _clone ( ) ;
clone ? . _patch ( d ) ;
return clone ? ? this . _add ( d , false ) ;
}
/ * *
* Options used for pruning guild members .
* < info > It ' s recommended to set { @ link GuildPruneMembersOptions # count options . count }
* to ` false ` for large guilds . < / i n f o >
* @ typedef { Object } GuildPruneMembersOptions
2022-03-24 10:55:32 +00:00
* @ property { number } [ days = 7 ] Number of days of inactivity required to kick
2022-03-19 10:37:45 +00:00
* @ property { boolean } [ dry = false ] Get the number of users that will be kicked , without actually kicking them
2022-03-24 10:55:32 +00:00
* @ property { boolean } [ count = true ] Whether or not to return the number of users that have been kicked .
2022-03-19 10:37:45 +00:00
* @ property { RoleResolvable [ ] } [ roles ] Array of roles to bypass the "...and no roles" constraint when pruning
* @ property { string } [ reason ] Reason for this prune
* /
/ * *
* Prunes members from the guild based on how long they have been inactive .
* @ param { GuildPruneMembersOptions } [ options ] Options for pruning
* @ returns { Promise < number | null > } The number of members that were / will be kicked
* @ example
* // See how many members will be pruned
* guild . members . prune ( { dry : true } )
* . then ( pruned => console . log ( ` This will prune ${ pruned } people! ` ) )
* . catch ( console . error ) ;
* @ example
* // Actually prune the members
* guild . members . prune ( { days : 1 , reason : 'too many people!' } )
* . then ( pruned => console . log ( ` I just pruned ${ pruned } people! ` ) )
* . catch ( console . error ) ;
* @ example
* // Include members with a specified role
* guild . members . prune ( { days : 7 , roles : [ '657259391652855808' ] } )
* . then ( pruned => console . log ( ` I just pruned ${ pruned } people! ` ) )
* . catch ( console . error ) ;
* /
2022-03-24 10:55:32 +00:00
async prune ( { days = 7 , dry = false , count : compute _prune _count = true , roles = [ ] , reason } = { } ) {
2022-03-19 10:37:45 +00:00
if ( typeof days !== 'number' ) throw new TypeError ( 'PRUNE_DAYS_TYPE' ) ;
const query = { days } ;
const resolvedRoles = [ ] ;
for ( const role of roles ) {
const resolvedRole = this . guild . roles . resolveId ( role ) ;
if ( ! resolvedRole ) {
throw new TypeError ( 'INVALID_ELEMENT' , 'Array' , 'options.roles' , role ) ;
}
resolvedRoles . push ( resolvedRole ) ;
}
if ( resolvedRoles . length ) {
query . include _roles = dry ? resolvedRoles . join ( ',' ) : resolvedRoles ;
}
const endpoint = this . client . api . guilds ( this . guild . id ) . prune ;
const { pruned } = await ( dry
2022-03-24 10:55:32 +00:00
? endpoint . get ( { query , reason } )
: endpoint . post ( { data : { ... query , compute _prune _count } , reason } ) ) ;
2022-03-19 10:37:45 +00:00
return pruned ;
}
/ * *
* Kicks a user from the guild .
* < info > The user must be a member of the guild < / i n f o >
* @ param { UserResolvable } user The member to kick
* @ param { string } [ reason ] Reason for kicking
* @ returns { Promise < GuildMember | User | Snowflake > } Result object will be resolved as specifically as possible .
* If the GuildMember cannot be resolved , the User will instead be attempted to be resolved . If that also cannot
* be resolved , the user ' s id will be the result .
* @ example
* // Kick a user by id (or with a user/guild member object)
* guild . members . kick ( '84484653687267328' )
2022-05-14 08:06:15 +00:00
* . then ( kickInfo => console . log ( ` Kicked ${ kickInfo . user ? . tag ? ? kickInfo . tag ? ? kickInfo } ` ) )
2022-03-19 10:37:45 +00:00
* . catch ( console . error ) ;
* /
async kick ( user , reason ) {
const id = this . client . users . resolveId ( user ) ;
if ( ! id ) return Promise . reject ( new TypeError ( 'INVALID_TYPE' , 'user' , 'UserResolvable' ) ) ;
2022-03-24 10:55:32 +00:00
await this . client . api . guilds ( this . guild . id ) . members ( id ) . delete ( { reason } ) ;
2022-03-19 10:37:45 +00:00
return this . resolve ( user ) ? ? this . client . users . resolve ( user ) ? ? id ;
}
/ * *
* Bans a user from the guild .
* @ param { UserResolvable } user The user to ban
* @ param { BanOptions } [ options ] Options for the ban
* @ returns { Promise < GuildMember | User | Snowflake > } Result object will be resolved as specifically as possible .
* If the GuildMember cannot be resolved , the User will instead be attempted to be resolved . If that also cannot
* be resolved , the user id will be the result .
* Internally calls the GuildBanManager # create method .
* @ example
* // Ban a user by id (or with a user/guild member object)
* guild . members . ban ( '84484653687267328' )
2022-05-14 08:06:15 +00:00
* . then ( banInfo => console . log ( ` Banned ${ banInfo . user ? . tag ? ? banInfo . tag ? ? banInfo } ` ) )
2022-03-19 10:37:45 +00:00
* . catch ( console . error ) ;
* /
2022-03-24 10:55:32 +00:00
ban ( user , options = { days : 0 } ) {
2022-03-19 10:37:45 +00:00
return this . guild . bans . create ( user , options ) ;
}
/ * *
* Unbans a user from the guild . Internally calls the { @ link GuildBanManager # remove } method .
* @ param { UserResolvable } user The user to unban
* @ param { string } [ reason ] Reason for unbanning user
2022-05-14 08:06:15 +00:00
* @ returns { Promise < ? User > } The user that was unbanned
2022-03-19 10:37:45 +00:00
* @ example
* // Unban a user by id (or with a user/guild member object)
* guild . members . unban ( '84484653687267328' )
* . then ( user => console . log ( ` Unbanned ${ user . username } from ${ guild . name } ` ) )
* . catch ( console . error ) ;
* /
unban ( user , reason ) {
return this . guild . bans . remove ( user , reason ) ;
}
async _fetchSingle ( { user , cache , force = false } ) {
if ( ! force ) {
const existing = this . cache . get ( user ) ;
if ( existing && ! existing . partial ) return existing ;
}
const data = await this . client . api . guilds ( this . guild . id ) . members ( user ) . get ( ) ;
return this . _add ( data , cache ) ;
}
_fetchMany ( {
limit = 0 ,
withPresences : presences = false ,
user : user _ids ,
query ,
time = 120e3 ,
2022-03-24 10:55:32 +00:00
nonce = SnowflakeUtil . generate ( ) ,
2022-04-17 10:21:54 +00:00
sleepTime = 2e3 , // 2 seconds
2022-03-19 10:37:45 +00:00
} = { } ) {
2022-04-17 10:21:54 +00:00
let type ;
2022-03-19 10:37:45 +00:00
return new Promise ( ( resolve , reject ) => {
if ( ! query && ! user _ids ) query = '' ;
if ( nonce . length > 32 ) throw new RangeError ( 'MEMBER_FETCH_NONCE_LENGTH' ) ;
2022-04-16 10:44:43 +00:00
if (
this . guild . me . permissions . has ( 'ADMINISTRATOR' ) ||
this . guild . me . permissions . has ( 'KICK_MEMBERS' ) ||
this . guild . me . permissions . has ( 'BAN_MEMBERS' ) ||
this . guild . me . permissions . has ( 'MANAGE_ROLES' )
) {
2022-06-08 05:35:19 +00:00
type = Opcodes . REQUEST _GUILD _MEMBERS ; // This is opcode
2022-04-11 12:48:20 +00:00
this . guild . shard . send ( {
2022-06-08 05:35:19 +00:00
op : type ,
2022-04-11 12:48:20 +00:00
d : {
guild _id : this . guild . id ,
presences ,
user _ids ,
query ,
nonce ,
limit ,
} ,
} ) ;
} else {
2022-06-08 05:35:19 +00:00
type = Opcodes . LAZY _REQUEST ; // This is opcode
2022-04-11 12:48:20 +00:00
let channel ;
let channels = this . guild . channels . cache . filter ( c => c . isText ( ) ) ;
channels = channels . filter ( c => c . permissionsFor ( this . guild . me ) . has ( 'VIEW_CHANNEL' ) ) ;
2022-04-16 12:01:05 +00:00
if ( ! channels . size ) {
2022-04-16 10:44:43 +00:00
throw new Error ( 'GUILD_MEMBERS_FETCH' , 'ClientUser do not have permission to view members in any channel.' ) ;
2022-04-16 12:01:05 +00:00
}
2022-04-16 10:44:43 +00:00
const channels _allowed _everyone = channels . filter ( c =>
2022-04-11 12:48:20 +00:00
c . permissionsFor ( this . guild . roles . everyone ) . has ( 'VIEW_CHANNEL' ) ,
) ;
2022-04-17 10:21:54 +00:00
channel = channels _allowed _everyone . random ( ) ? ? channels . random ( ) ;
2022-04-16 12:01:05 +00:00
// Create array limit [0, 99]
2022-04-11 12:48:20 +00:00
const list = [ ] ;
2022-04-16 10:44:43 +00:00
const allMember = this . guild . memberCount ;
2022-04-11 12:48:20 +00:00
if ( allMember < 100 ) {
list . push ( [ [ 0 , 99 ] ] ) ;
} else if ( allMember < 200 ) {
2022-04-16 10:44:43 +00:00
list . push ( [
[ 0 , 99 ] ,
[ 100 , 199 ] ,
] ) ;
2022-04-11 12:48:20 +00:00
} else if ( allMember < 300 ) {
2022-04-16 10:44:43 +00:00
list . push ( [
[ 0 , 99 ] ,
[ 100 , 199 ] ,
[ 200 , 299 ] ,
] ) ;
2022-04-11 12:48:20 +00:00
} else {
2022-06-08 05:35:19 +00:00
if ( allMember > 1_000 ) {
console . warn (
` [WARN] Guild ${ this . guild . id } has ${ allMember } > 1000 members. Can't get offline members (Opcode 14) \n > https://discordpy-self.readthedocs.io/en/latest/migrating_from_dpy.html#guild-members ` ,
) ;
if ( allMember > 75_000 ) {
console . warn ( ` [WARN] Can't get enough members because the guild is large (Opcode 14) ` ) ;
}
}
2022-04-11 12:48:20 +00:00
let x = 100 ;
for ( let i = 0 ; i < allMember ; i ++ ) {
if ( x > allMember ) {
i = allMember ;
continue ;
}
list . push ( [
[ 0 , 99 ] ,
[ x , x + 99 ] ,
[ x + 100 , x + 199 ] ,
] ) ;
2022-04-16 12:01:05 +00:00
x += 200 ;
2022-04-11 12:48:20 +00:00
}
}
2022-07-16 09:37:41 +00:00
const sendTime = Date . now ( ) ;
2022-06-25 03:10:17 +00:00
for ( const l of list ) {
this . guild . shard . send ( {
op : type ,
d : {
guild _id : this . guild . id ,
typing : true ,
threads : false ,
activities : true ,
channels : {
[ channel . id ] : l ,
2022-04-11 12:48:20 +00:00
} ,
2022-06-25 03:10:17 +00:00
thread _member _lists : [ ] ,
members : [ ] ,
} ,
} ) ;
}
2022-07-16 09:37:41 +00:00
console . warn ( ` Gateway Rate Limit Warning: Sending ${ list . length } Requests / ${ Date . now ( ) - sendTime || 1 } ms ` ) ;
2022-04-11 12:48:20 +00:00
}
2022-03-19 10:37:45 +00:00
const fetchedMembers = new Collection ( ) ;
let i = 0 ;
const handler = ( members , _ , chunk ) => {
timeout . refresh ( ) ;
2022-04-17 10:21:54 +00:00
if ( chunk . nonce !== nonce && type === 8 ) return ;
2022-03-19 10:37:45 +00:00
i ++ ;
for ( const member of members . values ( ) ) {
fetchedMembers . set ( member . id , member ) ;
}
if ( members . size < 1_000 || ( limit && fetchedMembers . size >= limit ) || i === chunk . count ) {
clearTimeout ( timeout ) ;
2022-03-24 10:55:32 +00:00
this . client . removeListener ( Events . GUILD _MEMBERS _CHUNK , handler ) ;
2022-04-11 12:48:20 +00:00
this . client . removeListener ( Events . GUILD _MEMBER _LIST _UPDATE , handler ) ;
2022-03-19 10:37:45 +00:00
this . client . decrementMaxListeners ( ) ;
2022-04-17 10:21:54 +00:00
let fetched = fetchedMembers . size < this . guild . members . cache . size ? this . guild . members . cache : fetchedMembers ;
2022-03-19 10:37:45 +00:00
if ( user _ids && ! Array . isArray ( user _ids ) && fetched . size ) fetched = fetched . first ( ) ;
2022-06-08 05:35:19 +00:00
if ( type == Opcodes . LAZY _REQUEST ) {
2022-04-17 10:21:54 +00:00
this . guild . client . sleep ( sleepTime ) . then ( ( ) => resolve ( fetched ) ) ;
} else {
resolve ( fetched ) ;
}
2022-03-19 10:37:45 +00:00
}
} ;
const timeout = setTimeout ( ( ) => {
2022-03-24 10:55:32 +00:00
this . client . removeListener ( Events . GUILD _MEMBERS _CHUNK , handler ) ;
2022-04-11 12:48:20 +00:00
this . client . removeListener ( Events . GUILD _MEMBER _LIST _UPDATE , handler ) ;
2022-03-19 10:37:45 +00:00
this . client . decrementMaxListeners ( ) ;
reject ( new Error ( 'GUILD_MEMBERS_TIMEOUT' ) ) ;
} , time ) . unref ( ) ;
this . client . incrementMaxListeners ( ) ;
2022-03-24 10:55:32 +00:00
this . client . on ( Events . GUILD _MEMBERS _CHUNK , handler ) ;
2022-04-11 12:48:20 +00:00
this . client . on ( Events . GUILD _MEMBER _LIST _UPDATE , handler ) ;
2022-03-19 10:37:45 +00:00
} ) ;
}
}
module . exports = GuildMemberManager ;