refactor: switch api and gateway to V8 (#4879)

Co-authored-by: Jan <66554238+Vaporox@users.noreply.github.com>
This commit is contained in:
Sugden
2021-02-11 17:10:35 +00:00
committed by GitHub
parent ae3c3d80ee
commit ee5bc1a5c4
33 changed files with 372 additions and 364 deletions

View File

@@ -2,7 +2,6 @@
const { Presence } = require('./Presence');
const { TypeError } = require('../errors');
const Collection = require('../util/Collection');
const { ActivityTypes, OPCodes } = require('../util/Constants');
class ClientPresence extends Presence {
@@ -14,8 +13,8 @@ class ClientPresence extends Presence {
super(client, Object.assign(data, { status: data.status || 'online', user: { id: null } }));
}
async set(presence) {
const packet = await this._parse(presence);
set(presence) {
const packet = this._parse(presence);
this.patch(packet);
if (typeof presence.shardID === 'undefined') {
this.client.ws.broadcast({ op: OPCodes.STATUS_UPDATE, d: packet });
@@ -29,58 +28,33 @@ class ClientPresence extends Presence {
return this;
}
async _parse({ status, since, afk, activity }) {
const applicationID = activity && (activity.application ? activity.application.id || activity.application : null);
let assets = new Collection();
if (activity) {
if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', 'name', 'string');
if (!activity.type) activity.type = 0;
if (activity.assets && applicationID) {
try {
const a = await this.client.api.oauth2.applications(applicationID).assets.get();
for (const asset of a) assets.set(asset.name, asset.id);
} catch {} // eslint-disable-line no-empty
}
}
const packet = {
afk: afk != null ? afk : false, // eslint-disable-line eqeqeq
since: since != null ? since : null, // eslint-disable-line eqeqeq
_parse({ status, since, afk, activities }) {
const data = {
activities: [],
afk: typeof afk === 'boolean' ? afk : false,
since: typeof since === 'number' && !Number.isNaN(since) ? since : null,
status: status || this.status,
game: activity
? {
type: activity.type,
name: activity.name,
url: activity.url,
details: activity.details || undefined,
state: activity.state || undefined,
assets: activity.assets
? {
large_text: activity.assets.largeText || undefined,
small_text: activity.assets.smallText || undefined,
large_image: assets.get(activity.assets.largeImage) || activity.assets.largeImage,
small_image: assets.get(activity.assets.smallImage) || activity.assets.smallImage,
}
: undefined,
timestamps: activity.timestamps || undefined,
party: activity.party || undefined,
application_id: applicationID || undefined,
secrets: activity.secrets || undefined,
instance: activity.instance || undefined,
}
: null,
};
if (activities === null) {
data.activities = null;
return data;
}
if (activities && activities.length) {
for (const [i, activity] of activities.entries()) {
if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string');
if (!activity.type) activity.type = 0;
if ((status || afk || since) && !activity) {
packet.game = this.activities[0] || null;
data.activities.push({
type: typeof activity.type === 'number' ? activity.type : ActivityTypes.indexOf(activity.type),
name: activity.name,
url: activity.url,
});
}
} else if ((status || afk || since) && this.activities.length) {
data.activities.push(...this.activities);
}
if (packet.game) {
packet.game.type =
typeof packet.game.type === 'number' ? packet.game.type : ActivityTypes.indexOf(packet.game.type);
}
return packet;
return data;
}
}

View File

@@ -46,16 +46,18 @@ class ClientUser extends Structures.get('User') {
return this.client.presence;
}
edit(data) {
return this.client.api
.users('@me')
.patch({ data })
.then(newData => {
this.client.token = newData.token;
const { updated } = this.client.actions.UserUpdate.handle(newData);
if (updated) return updated;
return this;
});
/**
* Edits the logged in client.
* @param {Object} data The new data
* @param {string} [data.username] The new username
* @param {BufferResolvable|Base64Resolvable} [data.avatar] The new avatar
*/
async edit(data) {
const newData = await this.client.api.users('@me').patch({ data });
this.client.token = newData.token;
const { updated } = this.client.actions.UserUpdate.handle(newData);
if (updated) return updated;
return this;
}
/**
@@ -103,7 +105,7 @@ class ClientUser extends Structures.get('User') {
/**
* Sets the full presence of the client user.
* @param {PresenceData} data Data for the presence
* @returns {Promise<Presence>}
* @returns {Presence}
* @example
* // Set the client user's presence
* client.user.setPresence({ activity: { name: 'with discord.js' }, status: 'idle' })
@@ -127,7 +129,7 @@ class ClientUser extends Structures.get('User') {
* Sets the status of the client user.
* @param {PresenceStatusData} status Status to change to
* @param {?number|number[]} [shardID] Shard ID(s) to have the activity set on
* @returns {Promise<Presence>}
* @returns {Presence}
* @example
* // Set the client user's status
* client.user.setStatus('idle')
@@ -144,14 +146,14 @@ class ClientUser extends Structures.get('User') {
* @type {Object}
* @property {string} [url] Twitch / YouTube stream URL
* @property {ActivityType|number} [type] Type of the activity
* @property {?number|number[]} [shardID] Shard Id(s) to have the activity set on
* @property {number|number[]} [shardID] Shard Id(s) to have the activity set on
*/
/**
* Sets the activity the client user is playing.
* @param {string|ActivityOptions} [name] Activity being played, or options for setting the activity
* @param {ActivityOptions} [options] Options for setting the activity
* @returns {Promise<Presence>}
* @returns {Presence}
* @example
* // Set the client user's activity
* client.user.setActivity('discord.js', { type: 'WATCHING' })
@@ -159,19 +161,20 @@ class ClientUser extends Structures.get('User') {
* .catch(console.error);
*/
setActivity(name, options = {}) {
if (!name) return this.setPresence({ activity: null, shardID: options.shardID });
if (!name) return this.setPresence({ activities: null, shardID: options.shardID });
const activity = Object.assign({}, options, typeof name === 'object' ? name : { name });
return this.setPresence({ activity, shardID: activity.shardID });
return this.setPresence({ activities: [activity], shardID: activity.shardID });
}
/**
* Sets/removes the AFK flag for the client user.
* @param {boolean} afk Whether or not the user is AFK
* @returns {Promise<Presence>}
* @param {number|number[]} [shardID] Shard Id(s) to have the AFK flag set on
* @returns {Presence}
*/
setAFK(afk) {
return this.setPresence({ afk });
setAFK(afk, shardID) {
return this.setPresence({ afk, shardID });
}
}

View File

@@ -210,13 +210,6 @@ class Guild extends Base {
*/
this.systemChannelID = data.system_channel_id;
/**
* Whether embedded images are enabled on this guild
* @type {boolean}
* @deprecated
*/
this.embedEnabled = data.embed_enabled;
/**
* The type of premium tier:
* * 0: NONE
@@ -256,15 +249,6 @@ class Guild extends Base {
this.widgetChannelID = data.widget_channel_id;
}
if (typeof data.embed_channel_id !== 'undefined') {
/**
* The embed channel ID, if enabled
* @type {?string}
* @deprecated
*/
this.embedChannelID = data.embed_channel_id;
}
/**
* The verification level of the guild
* @type {VerificationLevel}
@@ -585,16 +569,6 @@ class Guild extends Base {
return this.client.channels.cache.get(this.widgetChannelID) || null;
}
/**
* Embed channel for this guild
* @type {?TextChannel}
* @readonly
* @deprecated
*/
get embedChannel() {
return this.client.channels.cache.get(this.embedChannelID) || null;
}
/**
* Rules channel for this guild
* @type {?TextChannel}
@@ -688,8 +662,6 @@ class Guild extends Base {
/**
* Fetches a collection of integrations to this guild.
* Resolves with a collection mapping integrations by their ids.
* @param {Object} [options] Options for fetching integrations
* @param {boolean} [options.includeApplications] Whether to include bot and Oauth2 webhook integrations
* @returns {Promise<Collection<string, Integration>>}
* @example
* // Fetch integrations
@@ -697,20 +669,12 @@ class Guild extends Base {
* .then(integrations => console.log(`Fetched ${integrations.size} integrations`))
* .catch(console.error);
*/
fetchIntegrations({ includeApplications = false } = {}) {
return this.client.api
.guilds(this.id)
.integrations.get({
query: {
include_applications: includeApplications,
},
})
.then(data =>
data.reduce(
(collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)),
new Collection(),
),
);
async fetchIntegrations() {
const data = await this.client.api.guilds(this.id).integrations.get();
return data.reduce(
(collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)),
new Collection(),
);
}
/**
@@ -895,20 +859,6 @@ class Guild extends Base {
* @property {?GuildChannelResolvable} channel The widget channel
*/
/**
* Fetches the guild embed.
* @returns {Promise<GuildWidget>}
* @deprecated
* @example
* // Fetches the guild embed
* guild.fetchEmbed()
* .then(embed => console.log(`The embed is ${embed.enabled ? 'enabled' : 'disabled'}`))
* .catch(console.error);
*/
fetchEmbed() {
return this.fetchWidget();
}
/**
* Fetches the guild widget.
* @returns {Promise<GuildWidget>}
@@ -920,8 +870,8 @@ class Guild extends Base {
*/
async fetchWidget() {
const data = await this.client.api.guilds(this.id).widget.get();
this.widgetEnabled = this.embedEnabled = data.enabled;
this.widgetChannelID = this.embedChannelID = data.channel_id;
this.widgetEnabled = data.enabled;
this.widgetChannelID = data.channel_id;
return {
enabled: data.enabled,
channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,
@@ -1367,7 +1317,7 @@ class Guild extends Base {
* @returns {Promise<Guild>}
* @example
* guild.setRolePositions([{ role: roleID, position: updatedRoleIndex }])
* .then(guild => console.log(`Role permissions updated for ${guild}`))
* .then(guild => console.log(`Role positions updated for ${guild}`))
* .catch(console.error);
*/
setRolePositions(rolePositions) {
@@ -1392,17 +1342,6 @@ class Guild extends Base {
);
}
/**
* Edits the guild's embed.
* @param {GuildWidgetData} embed The embed for the guild
* @param {string} [reason] Reason for changing the guild's embed
* @returns {Promise<Guild>}
* @deprecated
*/
setEmbed(embed, reason) {
return this.setWidget(embed, reason);
}
/**
* Edits the guild's widget.
* @param {GuildWidgetData} widget The widget for the guild
@@ -1464,7 +1403,7 @@ class Guild extends Base {
* @returns {boolean}
*/
equals(guild) {
let equal =
return (
guild &&
guild instanceof this.constructor &&
this.id === guild.id &&
@@ -1478,20 +1417,10 @@ class Guild extends Base {
this.icon === guild.icon &&
this.ownerID === guild.ownerID &&
this.verificationLevel === guild.verificationLevel &&
this.embedEnabled === guild.embedEnabled &&
(this.features === guild.features ||
(this.features.length === guild.features.length &&
this.features.every((feat, i) => feat === guild.features[i])));
if (equal) {
if (this.embedChannel) {
if (!guild.embedChannel || this.embedChannel.id !== guild.embedChannel.id) equal = false;
} else if (guild.embedChannel) {
equal = false;
}
}
return equal;
this.features.every((feat, i) => feat === guild.features[i])))
);
}
/**
@@ -1522,7 +1451,7 @@ class Guild extends Base {
/**
* Creates a collection of this guild's roles, sorted by their position and IDs.
* @returns {Collection<Role>}
* @returns {Collection<Snowflake, Role>}
* @private
*/
_sortedRoles() {
@@ -1532,7 +1461,7 @@ class Guild extends Base {
/**
* Creates a collection of this guild's or a specific category's channels, sorted by their position and IDs.
* @param {GuildChannel} [channel] Category to get the channels of
* @returns {Collection<GuildChannel>}
* @returns {Collection<Snowflake, GuildChannel>}
* @private
*/
_sortedChannels(channel) {
@@ -1549,10 +1478,6 @@ class Guild extends Base {
}
}
Guild.prototype.setEmbed = deprecate(Guild.prototype.setEmbed, 'Guild#setEmbed: Use setWidget instead');
Guild.prototype.fetchEmbed = deprecate(Guild.prototype.fetchEmbed, 'Guild#fetchEmbed: Use fetchWidget instead');
Guild.prototype.fetchVanityCode = deprecate(
Guild.prototype.fetchVanityCode,
'Guild#fetchVanityCode: Use fetchVanityData() instead',

View File

@@ -3,7 +3,7 @@
const Integration = require('./Integration');
const Webhook = require('./Webhook');
const Collection = require('../util/Collection');
const { PartialTypes } = require('../util/Constants');
const { OverwriteTypes, PartialTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Snowflake = require('../util/Snowflake');
const Util = require('../util/Util');
@@ -384,16 +384,19 @@ class GuildAuditLogsEntry {
case Actions.CHANNEL_OVERWRITE_CREATE:
case Actions.CHANNEL_OVERWRITE_UPDATE:
case Actions.CHANNEL_OVERWRITE_DELETE:
switch (data.options.type) {
case 'member':
this.extra = guild.members.cache.get(data.options.id) || { id: data.options.id, type: 'member' };
break;
case 'role':
switch (Number(data.options.type)) {
case OverwriteTypes.role:
this.extra = guild.roles.cache.get(data.options.id) || {
id: data.options.id,
name: data.options.role_name,
type: 'role',
type: OverwriteTypes[OverwriteTypes.role],
};
break;
case OverwriteTypes.member:
this.extra = guild.members.cache.get(data.options.id) || {
id: data.options.id,
type: OverwriteTypes[OverwriteTypes.member],
};
break;

View File

@@ -7,6 +7,7 @@ const Role = require('./Role');
const { Error, TypeError } = require('../errors');
const Collection = require('../util/Collection');
const { ChannelTypes } = require('../util/Constants');
const { OverwriteTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
@@ -161,12 +162,12 @@ class GuildChannel extends Channel {
const overwrites = this.overwritesFor(member, true, roles);
return permissions
.remove(overwrites.everyone ? overwrites.everyone.deny : 0)
.add(overwrites.everyone ? overwrites.everyone.allow : 0)
.remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.deny) : 0)
.add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allow) : 0)
.remove(overwrites.member ? overwrites.member.deny : 0)
.add(overwrites.member ? overwrites.member.allow : 0)
.remove(overwrites.everyone ? overwrites.everyone.deny : 0n)
.add(overwrites.everyone ? overwrites.everyone.allow : 0n)
.remove(overwrites.roles.length > 0n ? overwrites.roles.map(role => role.deny) : 0n)
.add(overwrites.roles.length > 0n ? overwrites.roles.map(role => role.allow) : 0n)
.remove(overwrites.member ? overwrites.member.deny : 0n)
.add(overwrites.member ? overwrites.member.allow : 0n)
.freeze();
}
@@ -183,10 +184,10 @@ class GuildChannel extends Channel {
const roleOverwrites = this.permissionOverwrites.get(role.id);
return role.permissions
.remove(everyoneOverwrites ? everyoneOverwrites.deny : 0)
.add(everyoneOverwrites ? everyoneOverwrites.allow : 0)
.remove(roleOverwrites ? roleOverwrites.deny : 0)
.add(roleOverwrites ? roleOverwrites.allow : 0)
.remove(everyoneOverwrites ? everyoneOverwrites.deny : 0n)
.add(everyoneOverwrites ? everyoneOverwrites.allow : 0n)
.remove(roleOverwrites ? roleOverwrites.deny : 0n)
.add(roleOverwrites ? roleOverwrites.allow : 0n)
.freeze();
}
@@ -204,13 +205,12 @@ class GuildChannel extends Channel {
* },
* ], 'Needed to change permissions');
*/
overwritePermissions(overwrites, reason) {
async overwritePermissions(overwrites, reason) {
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
return Promise.reject(
new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true),
);
throw new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true);
}
return this.edit({ permissionOverwrites: overwrites, reason }).then(() => this);
await this.edit({ permissionOverwrites: overwrites, reason });
return this;
}
/**
@@ -227,13 +227,17 @@ class GuildChannel extends Channel {
* .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))
* .catch(console.error);
*/
updateOverwrite(userOrRole, options, reason) {
async updateOverwrite(userOrRole, options, reason) {
userOrRole = this.guild.roles.resolve(userOrRole) || this.client.users.resolve(userOrRole);
if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role'));
const existing = this.permissionOverwrites.get(userOrRole.id);
if (existing) return existing.update(options, reason).then(() => this);
return this.createOverwrite(userOrRole, options, reason);
if (existing) {
await existing.update(options, reason);
} else {
await this.createOverwrite(userOrRole, options, reason);
}
return this;
}
/**
@@ -254,13 +258,19 @@ class GuildChannel extends Channel {
userOrRole = this.guild.roles.resolve(userOrRole) || this.client.users.resolve(userOrRole);
if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role'));
const type = userOrRole instanceof Role ? 'role' : 'member';
const type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member;
const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options);
return this.client.api
.channels(this.id)
.permissions[userOrRole.id].put({
data: { id: userOrRole.id, type, allow: allow.bitfield, deny: deny.bitfield },
.permissions(userOrRole.id)
.put({
data: {
id: userOrRole.id,
type,
allow,
deny,
},
reason,
})
.then(() => this);

View File

@@ -2,8 +2,8 @@
const Role = require('./Role');
const { TypeError } = require('../errors');
const { OverwriteTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
/**
* Represents a permission overwrite for a role or member in a guild channel.
@@ -28,30 +28,23 @@ class PermissionOverwrites {
*/
this.id = data.id;
/**
* The type of a permission overwrite. It can be one of:
* * member
* * role
* @typedef {string} OverwriteType
*/
/**
* The type of this overwrite
* @type {OverwriteType}
*/
this.type = data.type;
this.type = OverwriteTypes[data.type];
/**
* The permissions that are denied for the user or role.
* @type {Readonly<Permissions>}
*/
this.deny = new Permissions(data.deny).freeze();
this.deny = new Permissions(BigInt(data.deny)).freeze();
/**
* The permissions that are allowed for the user or role.
* @type {Readonly<Permissions>}
*/
this.allow = new Permissions(data.allow).freeze();
this.allow = new Permissions(BigInt(data.allow)).freeze();
}
/**
@@ -67,16 +60,22 @@ class PermissionOverwrites {
* .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))
* .catch(console.error);
*/
update(options, reason) {
async update(options, reason) {
const { allow, deny } = this.constructor.resolveOverwriteOptions(options, this);
return this.channel.client.api
await this.channel.client.api
.channels(this.channel.id)
.permissions[this.id].put({
data: { id: this.id, type: this.type, allow: allow.bitfield, deny: deny.bitfield },
.permissions(this.id)
.put({
data: {
id: this.id,
type: OverwriteTypes[this.type],
allow,
deny,
},
reason,
})
.then(() => this);
});
return this;
}
/**
@@ -84,12 +83,18 @@ class PermissionOverwrites {
* @param {string} [reason] Reason for deleting this overwrite
* @returns {Promise<PermissionOverwrites>}
*/
delete(reason) {
return this.channel.client.api.channels[this.channel.id].permissions[this.id].delete({ reason }).then(() => this);
async delete(reason) {
await this.channel.client.api.channels(this.channel.id).permissions(this.id).delete({ reason });
return this;
}
toJSON() {
return Util.flatten(this);
return {
id: this.id,
type: OverwriteTypes[this.type],
allow: this.allow,
deny: this.deny,
};
}
/**
@@ -142,9 +147,9 @@ class PermissionOverwrites {
* The raw data for a permission overwrite
* @typedef {Object} RawOverwriteData
* @property {Snowflake} id The id of the overwrite
* @property {number} allow The permissions to allow
* @property {number} deny The permissions to deny
* @property {OverwriteType} type The type of this OverwriteData
* @property {string} allow The permissions to allow
* @property {string} deny The permissions to deny
* @property {number} type The type of this OverwriteData
*/
/**
@@ -164,24 +169,29 @@ class PermissionOverwrites {
/**
* Resolves an overwrite into {@link RawOverwriteData}.
* @param {OverwriteResolvable} overwrite The overwrite-like data to resolve
* @param {Guild} guild The guild to resolve from
* @param {Guild} [guild] The guild to resolve from
* @returns {RawOverwriteData}
*/
static resolve(overwrite, guild) {
if (overwrite instanceof this) return overwrite.toJSON();
if (typeof overwrite.id === 'string' && ['role', 'member'].includes(overwrite.type)) {
return { ...overwrite, allow: Permissions.resolve(overwrite.allow), deny: Permissions.resolve(overwrite.deny) };
if (typeof overwrite.id === 'string' && overwrite.type in OverwriteTypes) {
return {
id: overwrite.id,
type: OverwriteTypes[overwrite.type],
allow: Permissions.resolve(overwrite.allow).toString(),
deny: Permissions.resolve(overwrite.deny).toString(),
};
}
const userOrRole = guild.roles.resolve(overwrite.id) || guild.client.users.resolve(overwrite.id);
if (!userOrRole) throw new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role');
const type = userOrRole instanceof Role ? 'role' : 'member';
const type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member;
return {
id: userOrRole.id,
type,
allow: Permissions.resolve(overwrite.allow),
deny: Permissions.resolve(overwrite.deny),
allow: Permissions.resolve(overwrite.allow).toString(),
deny: Permissions.resolve(overwrite.deny).toString(),
};
}
}

View File

@@ -63,7 +63,7 @@ class Role extends Base {
* The permissions of the role
* @type {Readonly<Permissions>}
*/
this.permissions = new Permissions(data.permissions).freeze();
this.permissions = new Permissions(BigInt(data.permissions)).freeze();
/**
* Whether or not the role is managed by an external service
@@ -301,7 +301,7 @@ class Role extends Base {
* .catch(console.error);
* @example
* // Remove all permissions from a role
* role.setPermissions(0)
* role.setPermissions(0n)
* .then(updated => console.log(`Updated permissions to ${updated.permissions.bitfield}`))
* .catch(console.error);
*/

View File

@@ -245,7 +245,7 @@ class User extends Base {
recipient_id: this.id,
},
});
return this.client.actions.ChannelCreate.handle(data).channel;
return this.client.channels.add(data);
}
/**
@@ -255,8 +255,9 @@ class User extends Base {
async deleteDM() {
const { dmChannel } = this;
if (!dmChannel) throw new Error('USER_NO_DMCHANNEL');
const data = await this.client.api.channels(dmChannel.id).delete();
return this.client.actions.ChannelDelete.handle(data).channel;
await this.client.api.channels(dmChannel.id).delete();
this.client.channels.remove(dmChannel.id);
return dmChannel;
}
/**