mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-11 00:53:31 +01:00
Cleanup Part 2: Electric Boogaloo (Reloaded) (#594)
* Cleanup Part 2: Electric Boogaloo (Reloaded) * Moar cleanup * Tweak NOT_A_PERMISSION error
This commit is contained in:
committed by
Amish Shah
parent
5a9c42061f
commit
0b908f5bce
@@ -15,10 +15,8 @@ const Collection = require('../util/Collection');
|
||||
* @extends {EventEmitter}
|
||||
*/
|
||||
class Client extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Creates an instance of Client.
|
||||
* @param {ClientOptions} [options] options to pass to the client
|
||||
* @param {ClientOptions} [options] Options for the client
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
@@ -129,17 +127,13 @@ class Client extends EventEmitter {
|
||||
* client.login(email, password);
|
||||
*/
|
||||
login(emailOrToken, password) {
|
||||
if (password) {
|
||||
// login with email and password
|
||||
return this.rest.methods.loginEmailPassword(emailOrToken, password);
|
||||
}
|
||||
// login with token
|
||||
if (password) return this.rest.methods.loginEmailPassword(emailOrToken, password);
|
||||
return this.rest.methods.loginToken(emailOrToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the client and logs out. Resolves with null if successful.
|
||||
* @returns {Promise<null, Error>}
|
||||
* Destroys the client and logs out.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
destroy() {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -152,8 +146,7 @@ class Client extends EventEmitter {
|
||||
this._timeouts = [];
|
||||
this._intervals = [];
|
||||
resolve();
|
||||
})
|
||||
.catch(reject);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,7 +169,7 @@ class Client extends EventEmitter {
|
||||
/**
|
||||
* This shouldn't really be necessary to most developers as it is automatically invoked every 30 seconds, however
|
||||
* if you wish to force a sync of Guild data, you can use this. Only applicable to user accounts.
|
||||
* @param {array<Guild>} [guilds=this.guilds.array()] An array of guilds to sync.
|
||||
* @param {Guild[]} [guilds=this.guilds.array()] An array of guilds to sync
|
||||
*/
|
||||
syncGuilds(guilds = this.guilds.array()) {
|
||||
if (!this.user.bot) {
|
||||
@@ -215,7 +208,6 @@ class Client extends EventEmitter {
|
||||
get uptime() {
|
||||
return this.readyTime ? Date.now() - this.readyTime : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Client;
|
||||
|
||||
@@ -23,11 +23,10 @@ class ClientDataManager {
|
||||
this.client.guilds.set(guild.id, guild);
|
||||
if (this.pastReady && !already) {
|
||||
/**
|
||||
* Emitted whenever the client joins a Guild.
|
||||
*
|
||||
* @event Client#guildCreate
|
||||
* @param {Guild} guild the created guild.
|
||||
*/
|
||||
* Emitted whenever the client joins a Guild.
|
||||
* @event Client#guildCreate
|
||||
* @param {Guild} guild The created guild
|
||||
*/
|
||||
this.client.emit(Constants.Events.GUILD_CREATE, guild);
|
||||
}
|
||||
|
||||
@@ -35,16 +34,13 @@ class ClientDataManager {
|
||||
}
|
||||
|
||||
newUser(data) {
|
||||
if (this.client.users.has(data.id)) {
|
||||
return this.client.users.get(data.id);
|
||||
}
|
||||
if (this.client.users.has(data.id)) return this.client.users.get(data.id);
|
||||
const user = new User(this.client, data);
|
||||
this.client.users.set(user.id, user);
|
||||
return user;
|
||||
}
|
||||
|
||||
newChannel(data, $guild) {
|
||||
let guild = $guild;
|
||||
newChannel(data, guild) {
|
||||
const already = this.client.channels.has(data.id);
|
||||
let channel;
|
||||
if (data.type === Constants.ChannelTypes.DM) {
|
||||
@@ -65,22 +61,18 @@ class ClientDataManager {
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
if (this.pastReady && !already) {
|
||||
this.client.emit(Constants.Events.CHANNEL_CREATE, channel);
|
||||
}
|
||||
|
||||
if (this.pastReady && !already) this.client.emit(Constants.Events.CHANNEL_CREATE, channel);
|
||||
this.client.channels.set(channel.id, channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
killGuild(guild) {
|
||||
const already = this.client.guilds.has(guild.id);
|
||||
this.client.guilds.delete(guild.id);
|
||||
if (already && this.pastReady) {
|
||||
this.client.emit(Constants.Events.GUILD_DELETE, guild);
|
||||
}
|
||||
if (already && this.pastReady) this.client.emit(Constants.Events.GUILD_DELETE, guild);
|
||||
}
|
||||
|
||||
killUser(user) {
|
||||
@@ -89,17 +81,13 @@ class ClientDataManager {
|
||||
|
||||
killChannel(channel) {
|
||||
this.client.channels.delete(channel.id);
|
||||
if (channel instanceof GuildChannel) {
|
||||
channel.guild.channels.delete(channel.id);
|
||||
}
|
||||
if (channel instanceof GuildChannel) channel.guild.channels.delete(channel.id);
|
||||
}
|
||||
|
||||
updateGuild(currentGuild, newData) {
|
||||
const oldGuild = cloneObject(currentGuild);
|
||||
currentGuild.setup(newData);
|
||||
if (this.pastReady) {
|
||||
this.client.emit(Constants.Events.GUILD_UPDATE, oldGuild, currentGuild);
|
||||
}
|
||||
if (this.pastReady) this.client.emit(Constants.Events.GUILD_UPDATE, oldGuild, currentGuild);
|
||||
}
|
||||
|
||||
updateChannel(currentChannel, newData) {
|
||||
|
||||
@@ -2,13 +2,12 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const request = require('superagent');
|
||||
|
||||
const getStructure = name => require(`../structures/${name}`);
|
||||
|
||||
const User = getStructure('User');
|
||||
const Message = getStructure('Message');
|
||||
const Guild = getStructure('Guild');
|
||||
const Channel = getStructure('Channel');
|
||||
const GuildMember = getStructure('GuildMember');
|
||||
const Constants = require('../util/constants');
|
||||
const User = require(`../structures/User`);
|
||||
const Message = require(`../structures/Message`);
|
||||
const Guild = require(`../structures/Guild`);
|
||||
const Channel = require(`../structures/Channel`);
|
||||
const GuildMember = require(`../structures/GuildMember`);
|
||||
|
||||
/**
|
||||
* The DataResolver identifies different objects and tries to resolve a specific piece of information from them, e.g.
|
||||
@@ -16,7 +15,9 @@ const GuildMember = getStructure('GuildMember');
|
||||
* @private
|
||||
*/
|
||||
class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* @param {Client} client The client the resolver is for
|
||||
*/
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
}
|
||||
@@ -33,7 +34,7 @@ class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* Resolves a UserResolvable to a User object
|
||||
* @param {UserResolvable} user the UserResolvable to identify
|
||||
* @param {UserResolvable} user The UserResolvable to identify
|
||||
* @returns {?User}
|
||||
*/
|
||||
resolveUser(user) {
|
||||
@@ -60,18 +61,12 @@ class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* Resolves a GuildResolvable to a Guild object
|
||||
* @param {GuildResolvable} guild the GuildResolvable to identify
|
||||
* @param {GuildResolvable} guild The GuildResolvable to identify
|
||||
* @returns {?Guild}
|
||||
*/
|
||||
resolveGuild(guild) {
|
||||
if (guild instanceof Guild) {
|
||||
return guild;
|
||||
}
|
||||
|
||||
if (typeof guild === 'string') {
|
||||
return this.client.guilds.get(guild);
|
||||
}
|
||||
|
||||
if (guild instanceof Guild) return guild;
|
||||
if (typeof guild === 'string') return this.client.guilds.get(guild);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -84,21 +79,16 @@ class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* Resolves a GuildMemberResolvable to a GuildMember object
|
||||
* @param {GuildResolvable} guild the guild that the member is part of
|
||||
* @param {UserResolvable} user the user that is part of the guild
|
||||
* @param {GuildResolvable} guild The guild that the member is part of
|
||||
* @param {UserResolvable} user The user that is part of the guild
|
||||
* @returns {?GuildMember}
|
||||
*/
|
||||
resolveGuildMember(guild, user) {
|
||||
if (user instanceof GuildMember) {
|
||||
return user;
|
||||
}
|
||||
if (user instanceof GuildMember) return user;
|
||||
|
||||
guild = this.resolveGuild(guild);
|
||||
user = this.resolveUser(user);
|
||||
|
||||
if (!guild || !user) {
|
||||
return null;
|
||||
}
|
||||
if (!guild || !user) return null;
|
||||
|
||||
return guild.members.get(user.id);
|
||||
}
|
||||
@@ -112,14 +102,11 @@ class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* Resolves a Base64Resolvable to a Base 64 image
|
||||
* @param {Base64Resolvable} data the base 64 resolvable you want to resolve
|
||||
* @param {Base64Resolvable} data The base 64 resolvable you want to resolve
|
||||
* @returns {?string}
|
||||
*/
|
||||
resolveBase64(data) {
|
||||
if (data instanceof Buffer) {
|
||||
return `data:image/jpg;base64,${data.toString('base64')}`;
|
||||
}
|
||||
|
||||
if (data instanceof Buffer) return `data:image/jpg;base64,${data.toString('base64')}`;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -132,43 +119,49 @@ class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* Resolves a ChannelResolvable to a Channel object
|
||||
* @param {ChannelResolvable} channel the channel resolvable to resolve
|
||||
* @param {ChannelResolvable} channel The channel resolvable to resolve
|
||||
* @returns {?Channel}
|
||||
*/
|
||||
resolveChannel(channel) {
|
||||
if (channel instanceof Channel) {
|
||||
return channel;
|
||||
}
|
||||
|
||||
if (typeof channel === 'string') {
|
||||
return this.client.channels.get(channel.id);
|
||||
}
|
||||
|
||||
if (channel instanceof Channel) return channel;
|
||||
if (typeof channel === 'string') return this.client.channels.get(channel.id);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to give a permission number. This can be:
|
||||
* * A string
|
||||
* * A permission number
|
||||
* @typedef {string|number} PermissionResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a PermissionResolvable to a permission number
|
||||
* @param {PermissionResolvable} permission The permission resolvable to resolve
|
||||
* @returns {number}
|
||||
*/
|
||||
resolvePermission(permission) {
|
||||
if (typeof permission === 'string') permission = Constants.PermissionFlags[permission];
|
||||
if (!permission) throw Constants.Errors.NOT_A_PERMISSION;
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to give a string. This can be:
|
||||
* * A string
|
||||
* * An Array (joined with a new line delimiter to give a string)
|
||||
* * Any object
|
||||
* @typedef {string|Array|Object} StringResolvable
|
||||
* * Any value
|
||||
* @typedef {string|Array|*} StringResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a StringResolvable to a string
|
||||
* @param {StringResolvable} data the string resolvable to resolve
|
||||
* @param {StringResolvable} data The string resolvable to resolve
|
||||
* @returns {string}
|
||||
*/
|
||||
resolveString(data) {
|
||||
if (typeof data === 'string') {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (data instanceof Array) {
|
||||
return data.join('\n');
|
||||
}
|
||||
|
||||
if (typeof data === 'string') return data;
|
||||
if (data instanceof Array) return data.join('\n');
|
||||
return String(data);
|
||||
}
|
||||
|
||||
@@ -182,8 +175,8 @@ class ClientDataResolver {
|
||||
|
||||
/**
|
||||
* Resolves a FileResolvable to a Buffer
|
||||
* @param {FileResolvable} resource the file resolvable to resolve
|
||||
* @returns {string|Buffer}
|
||||
* @param {FileResolvable} resource The file resolvable to resolve
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
resolveFile(resource) {
|
||||
if (typeof resource === 'string') {
|
||||
@@ -194,19 +187,19 @@ class ClientDataResolver {
|
||||
.end((err, res) => err ? reject(err) : resolve(res.body));
|
||||
} else {
|
||||
const file = path.resolve(resource);
|
||||
const stat = fs.statSync(file);
|
||||
if (!stat.isFile()) {
|
||||
throw new Error(`The file could not be found: ${file}`);
|
||||
}
|
||||
|
||||
fs.readFile(file, (err, data) => {
|
||||
if (err) reject(err); else resolve(data);
|
||||
fs.stat(file, (err, stats) => {
|
||||
if (err) reject(err);
|
||||
if (!stats.isFile()) throw new Error(`The file could not be found: ${file}`);
|
||||
fs.readFile(file, (err2, data) => {
|
||||
if (err2) reject(err2); else resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(resource);
|
||||
if (resource instanceof Buffer) return Promise.resolve(resource);
|
||||
return Promise.reject(new TypeError('resource is not a string or Buffer'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ const Constants = require('../util/Constants');
|
||||
* @private
|
||||
*/
|
||||
class ClientManager {
|
||||
|
||||
constructor(client) {
|
||||
/**
|
||||
* The Client that instantiated this Manager
|
||||
@@ -21,25 +20,22 @@ class ClientManager {
|
||||
|
||||
/**
|
||||
* Connects the Client to the WebSocket
|
||||
* @param {string} token the authorization token
|
||||
* @param {function} resolve function to run when connection is successful
|
||||
* @param {function} reject function to run when connection fails
|
||||
* @param {string} token The authorization token
|
||||
* @param {function} resolve Function to run when connection is successful
|
||||
* @param {function} reject Function to run when connection fails
|
||||
*/
|
||||
connectToWebSocket(token, resolve, reject) {
|
||||
this.client.token = token;
|
||||
this.client.rest.methods.getGateway()
|
||||
.then(gateway => {
|
||||
this.client.ws.connect(gateway);
|
||||
this.client.once(Constants.Events.READY, () => resolve(token));
|
||||
})
|
||||
.catch(reject);
|
||||
|
||||
this.client.rest.methods.getGateway().then(gateway => {
|
||||
this.client.ws.connect(gateway);
|
||||
this.client.once(Constants.Events.READY, () => resolve(token));
|
||||
}).catch(reject);
|
||||
this.client.setTimeout(() => reject(Constants.Errors.TOOK_TOO_LONG), 1000 * 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a keep-alive interval to keep the Client's connection valid
|
||||
* @param {number} time the interval in milliseconds at which heartbeat packets should be sent
|
||||
* @param {number} time The interval in milliseconds at which heartbeat packets should be sent
|
||||
*/
|
||||
setupKeepAlive(time) {
|
||||
this.heartbeatInterval = this.client.setInterval(() => {
|
||||
|
||||
@@ -11,7 +11,6 @@ that WebSocket events don't clash with REST methods.
|
||||
*/
|
||||
|
||||
class GenericAction {
|
||||
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
}
|
||||
@@ -19,7 +18,6 @@ class GenericAction {
|
||||
handle(data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GenericAction;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class ActionsManager {
|
||||
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const Action = require('./Action');
|
||||
|
||||
class ChannelCreateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
const channel = client.dataManager.newChannel(data);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const Action = require('./Action');
|
||||
|
||||
class ChannelDeleteAction extends Action {
|
||||
|
||||
constructor(client) {
|
||||
super(client);
|
||||
this.deleted = new Map();
|
||||
|
||||
@@ -3,7 +3,6 @@ const Constants = require('../../util/Constants');
|
||||
const cloneObject = require('../../util/CloneObject');
|
||||
|
||||
class ChannelUpdateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
@@ -26,11 +25,10 @@ class ChannelUpdateAction extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a channel is updated - e.g. name change, topic change.
|
||||
*
|
||||
* @event Client#channelUpdate
|
||||
* @param {Channel} oldChannel the channel before the update
|
||||
* @param {Channel} newChannel the channel after the update
|
||||
*/
|
||||
* Emitted whenever a channel is updated - e.g. name change, topic change.
|
||||
* @event Client#channelUpdate
|
||||
* @param {Channel} oldChannel The channel before the update
|
||||
* @param {Channel} newChannel The channel after the update
|
||||
*/
|
||||
|
||||
module.exports = ChannelUpdateAction;
|
||||
|
||||
@@ -2,7 +2,6 @@ const Action = require('./Action');
|
||||
const Constants = require('../../util/Constants');
|
||||
|
||||
class GuildBanRemove extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
|
||||
@@ -2,7 +2,6 @@ const Action = require('./Action');
|
||||
const Constants = require('../../util/Constants');
|
||||
|
||||
class GuildDeleteAction extends Action {
|
||||
|
||||
constructor(client) {
|
||||
super(client);
|
||||
this.deleted = new Map();
|
||||
@@ -45,9 +44,8 @@ class GuildDeleteAction extends Action {
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild becomes unavailable, likely due to a server outage.
|
||||
*
|
||||
* @event Client#guildUnavailable
|
||||
* @param {Guild} guild the guild that has become unavailable.
|
||||
*/
|
||||
* @param {Guild} guild The guild that has become unavailable.
|
||||
*/
|
||||
|
||||
module.exports = GuildDeleteAction;
|
||||
|
||||
@@ -2,7 +2,6 @@ const Action = require('./Action');
|
||||
const Constants = require('../../util/Constants');
|
||||
|
||||
class GuildMemberRemoveAction extends Action {
|
||||
|
||||
constructor(client) {
|
||||
super(client);
|
||||
this.deleted = new Map();
|
||||
@@ -43,10 +42,9 @@ class GuildMemberRemoveAction extends Action {
|
||||
|
||||
/**
|
||||
* Emitted whenever a member leaves a guild, or is kicked.
|
||||
*
|
||||
* @event Client#guildMemberRemove
|
||||
* @param {Guild} guild the guild that the member has left.
|
||||
* @param {GuildMember} member the member that has left the guild.
|
||||
* @param {Guild} guild The guild that the member has left.
|
||||
* @param {GuildMember} member The member that has left the guild.
|
||||
*/
|
||||
|
||||
module.exports = GuildMemberRemoveAction;
|
||||
|
||||
@@ -3,7 +3,6 @@ const Constants = require('../../util/Constants');
|
||||
const Role = require('../../structures/Role');
|
||||
|
||||
class GuildRoleCreate extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
@@ -25,11 +24,10 @@ class GuildRoleCreate extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild role is created.
|
||||
*
|
||||
* @event Client#guildRoleCreate
|
||||
* @param {Guild} guild the guild that the role was created in.
|
||||
* @param {Role} role the role that was created.
|
||||
*/
|
||||
* Emitted whenever a guild role is created.
|
||||
* @event Client#guildRoleCreate
|
||||
* @param {Guild} guild The guild that the role was created in.
|
||||
* @param {Role} role The role that was created.
|
||||
*/
|
||||
|
||||
module.exports = GuildRoleCreate;
|
||||
|
||||
@@ -2,7 +2,6 @@ const Action = require('./Action');
|
||||
const Constants = require('../../util/Constants');
|
||||
|
||||
class GuildRoleDeleteAction extends Action {
|
||||
|
||||
constructor(client) {
|
||||
super(client);
|
||||
this.deleted = new Map();
|
||||
@@ -39,11 +38,10 @@ class GuildRoleDeleteAction extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild role is deleted.
|
||||
*
|
||||
* @event Client#guildRoleDelete
|
||||
* @param {Guild} guild the guild that the role was deleted in.
|
||||
* @param {Role} role the role that was deleted.
|
||||
*/
|
||||
* Emitted whenever a guild role is deleted.
|
||||
* @event Client#guildRoleDelete
|
||||
* @param {Guild} guild The guild that the role was deleted in.
|
||||
* @param {Role} role The role that was deleted.
|
||||
*/
|
||||
|
||||
module.exports = GuildRoleDeleteAction;
|
||||
|
||||
@@ -3,7 +3,6 @@ const Constants = require('../../util/Constants');
|
||||
const cloneObject = require('../../util/CloneObject');
|
||||
|
||||
class GuildRoleUpdateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
@@ -33,12 +32,11 @@ class GuildRoleUpdateAction extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild role is updated.
|
||||
*
|
||||
* @event Client#guildRoleUpdated
|
||||
* @param {Guild} guild the guild that the role was updated in.
|
||||
* @param {Role} oldRole the role before the update.
|
||||
* @param {Role} newRole the role after the update.
|
||||
*/
|
||||
* Emitted whenever a guild role is updated.
|
||||
* @event Client#guildRoleUpdated
|
||||
* @param {Guild} guild The guild that the role was updated in.
|
||||
* @param {Role} oldRole The role before the update.
|
||||
* @param {Role} newRole The role after the update.
|
||||
*/
|
||||
|
||||
module.exports = GuildRoleUpdateAction;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const Action = require('./Action');
|
||||
|
||||
class GuildSync extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ const Constants = require('../../util/Constants');
|
||||
const cloneObject = require('../../util/CloneObject');
|
||||
|
||||
class GuildUpdateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
@@ -26,11 +25,10 @@ class GuildUpdateAction extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a guild is updated - e.g. name change.
|
||||
*
|
||||
* @event Client#guildUpdate
|
||||
* @param {Guild} oldGuild the guild before the update.
|
||||
* @param {Guild} newGuild the guild after the update.
|
||||
*/
|
||||
* Emitted whenever a guild is updated - e.g. name change.
|
||||
* @event Client#guildUpdate
|
||||
* @param {Guild} oldGuild The guild before the update.
|
||||
* @param {Guild} newGuild The guild after the update.
|
||||
*/
|
||||
|
||||
module.exports = GuildUpdateAction;
|
||||
|
||||
@@ -2,7 +2,6 @@ const Action = require('./Action');
|
||||
const Message = require('../../structures/Message');
|
||||
|
||||
class MessageCreateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const Action = require('./Action');
|
||||
|
||||
class MessageDeleteAction extends Action {
|
||||
|
||||
constructor(client) {
|
||||
super(client);
|
||||
this.deleted = new Map();
|
||||
|
||||
@@ -3,7 +3,6 @@ const Collection = require('../../util/Collection');
|
||||
const Constants = require('../../util/Constants');
|
||||
|
||||
class MessageDeleteBulkAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
const channel = client.channels.get(data.channel_id);
|
||||
@@ -12,9 +11,7 @@ class MessageDeleteBulkAction extends Action {
|
||||
const messages = new Collection();
|
||||
for (const id of ids) {
|
||||
const message = channel.messages.get(id);
|
||||
if (message) {
|
||||
messages.set(message.id, message);
|
||||
}
|
||||
if (message) messages.set(message.id, message);
|
||||
}
|
||||
|
||||
if (messages.size > 0) client.emit(Constants.Events.MESSAGE_BULK_DELETE, messages);
|
||||
|
||||
@@ -3,7 +3,6 @@ const Constants = require('../../util/Constants');
|
||||
const cloneObject = require('../../util/CloneObject');
|
||||
|
||||
class MessageUpdateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
@@ -34,11 +33,10 @@ class MessageUpdateAction extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a message is updated - e.g. embed or content change.
|
||||
*
|
||||
* @event Client#messageUpdate
|
||||
* @param {Message} oldMessage the message before the update.
|
||||
* @param {Message} newMessage the message after the update.
|
||||
*/
|
||||
* Emitted whenever a message is updated - e.g. embed or content change.
|
||||
* @event Client#messageUpdate
|
||||
* @param {Message} oldMessage The message before the update.
|
||||
* @param {Message} newMessage The message after the update.
|
||||
*/
|
||||
|
||||
module.exports = MessageUpdateAction;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const Action = require('./Action');
|
||||
|
||||
class UserGetAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
const user = client.dataManager.newUser(data);
|
||||
|
||||
@@ -3,7 +3,6 @@ const Constants = require('../../util/Constants');
|
||||
const cloneObject = require('../../util/CloneObject');
|
||||
|
||||
class UserUpdateAction extends Action {
|
||||
|
||||
handle(data) {
|
||||
const client = this.client;
|
||||
|
||||
@@ -32,11 +31,10 @@ class UserUpdateAction extends Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a detail of the logged in User changes - e.g. username.
|
||||
*
|
||||
* @event Client#userUpdate
|
||||
* @param {ClientUser} oldClientUser the client user before the update.
|
||||
* @param {ClientUser} newClientUser the client user after the update.
|
||||
*/
|
||||
* Emitted whenever a detail of the logged in User changes - e.g. username.
|
||||
* @event Client#userUpdate
|
||||
* @param {ClientUser} oldClientUser The client user before the update.
|
||||
* @param {ClientUser} newClientUser The client user after the update.
|
||||
*/
|
||||
|
||||
module.exports = UserUpdateAction;
|
||||
|
||||
@@ -26,17 +26,12 @@ class APIRequest {
|
||||
|
||||
gen() {
|
||||
const apiRequest = request[this.method](this.url);
|
||||
if (this.auth) {
|
||||
apiRequest.set('authorization', this.getAuth());
|
||||
}
|
||||
if (this.auth) apiRequest.set('authorization', this.getAuth());
|
||||
if (this.file && this.file.file) {
|
||||
apiRequest.set('Content-Type', 'multipart/form-data');
|
||||
apiRequest.attach('file', this.file.file, this.file.name);
|
||||
}
|
||||
if (this.data) {
|
||||
apiRequest.send(this.data);
|
||||
}
|
||||
|
||||
if (this.data) apiRequest.send(this.data);
|
||||
apiRequest.set('User-Agent', this.rest.userAgentManager.userAgent);
|
||||
return apiRequest;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ const APIRequest = require('./APIRequest');
|
||||
const Constants = require('../../util/Constants');
|
||||
|
||||
class RESTManager {
|
||||
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.handlers = {};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const Constants = require('../../util/Constants');
|
||||
const Collection = require('../../util/Collection');
|
||||
|
||||
const getStructure = name => require(`../../structures/${name}`);
|
||||
const User = getStructure('User');
|
||||
const GuildMember = getStructure('GuildMember');
|
||||
const Role = getStructure('Role');
|
||||
const Invite = getStructure('Invite');
|
||||
const requireStructure = name => require(`../../structures/${name}`);
|
||||
const User = requireStructure('User');
|
||||
const GuildMember = requireStructure('GuildMember');
|
||||
const Role = requireStructure('Role');
|
||||
const Invite = requireStructure('Invite');
|
||||
|
||||
class RESTMethods {
|
||||
constructor(restManager) {
|
||||
@@ -45,10 +45,9 @@ class RESTMethods {
|
||||
});
|
||||
}
|
||||
|
||||
sendMessage($channel, content, tts, nonce, file) {
|
||||
sendMessage(channel, content, tts, nonce, file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const $this = this;
|
||||
let channel = $channel;
|
||||
|
||||
function req() {
|
||||
$this.rest.makeRequest('post', Constants.Endpoints.channelMessages(channel.id), true, {
|
||||
@@ -101,11 +100,9 @@ class RESTMethods {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('patch', Constants.Endpoints.channelMessage(message.channel.id, message.id), true, {
|
||||
content,
|
||||
})
|
||||
.then(data => {
|
||||
}).then(data => {
|
||||
resolve(this.rest.client.actions.MessageUpdate.handle(data).updated);
|
||||
})
|
||||
.catch(reject);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -114,11 +111,9 @@ class RESTMethods {
|
||||
this.rest.makeRequest('post', Constants.Endpoints.guildChannels(guild.id), true, {
|
||||
name: channelName,
|
||||
type: channelType,
|
||||
})
|
||||
.then(data => {
|
||||
resolve(this.rest.client.actions.ChannelCreate.handle(data).channel);
|
||||
})
|
||||
.catch(reject);
|
||||
}).then(data => {
|
||||
resolve(this.rest.client.actions.ChannelCreate.handle(data).channel);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,98 +121,73 @@ class RESTMethods {
|
||||
const dmChannel = Array.from(this.rest.client.channels.values())
|
||||
.filter(channel => channel.recipient)
|
||||
.filter(channel => channel.recipient.id === recipient.id);
|
||||
|
||||
return dmChannel[0];
|
||||
}
|
||||
|
||||
createDM(recipient) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const dmChannel = this.getExistingDM(recipient);
|
||||
|
||||
if (dmChannel) {
|
||||
return resolve(dmChannel);
|
||||
}
|
||||
|
||||
if (dmChannel) return resolve(dmChannel);
|
||||
return this.rest.makeRequest('post', Constants.Endpoints.userChannels(this.rest.client.user.id), true, {
|
||||
recipient_id: recipient.id,
|
||||
})
|
||||
.then(data => resolve(this.rest.client.actions.ChannelCreate.handle(data).channel))
|
||||
.catch(reject);
|
||||
}).then(data => resolve(this.rest.client.actions.ChannelCreate.handle(data).channel)).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
deleteChannel($channel) {
|
||||
let channel = $channel;
|
||||
deleteChannel(channel) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (channel instanceof User || channel instanceof GuildMember) {
|
||||
channel = this.getExistingDM(channel);
|
||||
}
|
||||
|
||||
this.rest.makeRequest('del', Constants.Endpoints.channel(channel.id), true)
|
||||
.then($data => {
|
||||
const data = $data;
|
||||
data.id = channel.id;
|
||||
resolve(this.rest.client.actions.ChannelDelete.handle(data).channel);
|
||||
})
|
||||
.catch(reject);
|
||||
if (channel instanceof User || channel instanceof GuildMember) channel = this.getExistingDM(channel);
|
||||
this.rest.makeRequest('del', Constants.Endpoints.channel(channel.id), true).then(data => {
|
||||
data.id = channel.id;
|
||||
resolve(this.rest.client.actions.ChannelDelete.handle(data).channel);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
updateChannel(channel, $data) {
|
||||
const data = $data;
|
||||
updateChannel(channel, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
data.name = (data.name || channel.name).trim();
|
||||
data.topic = data.topic || channel.topic;
|
||||
data.position = data.position || channel.position;
|
||||
data.bitrate = data.bitrate || channel.bitrate;
|
||||
|
||||
this.rest.makeRequest('patch', Constants.Endpoints.channel(channel.id), true, data)
|
||||
.then(newData => {
|
||||
resolve(this.rest.client.actions.ChannelUpdate.handle(newData).updated);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('patch', Constants.Endpoints.channel(channel.id), true, data).then(newData => {
|
||||
resolve(this.rest.client.actions.ChannelUpdate.handle(newData).updated);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
leaveGuild(guild) {
|
||||
if (guild.ownerID === this.rest.client.user.id) {
|
||||
return this.deleteGuild(guild);
|
||||
}
|
||||
if (guild.ownerID === this.rest.client.user.id) return this.deleteGuild(guild);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('del', Constants.Endpoints.meGuild(guild.id), true)
|
||||
.then(() => {
|
||||
resolve(this.rest.client.actions.GuildDelete.handle({ id: guild.id }).guild);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('del', Constants.Endpoints.meGuild(guild.id), true).then(() => {
|
||||
resolve(this.rest.client.actions.GuildDelete.handle({ id: guild.id }).guild);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
// untested but probably will work
|
||||
deleteGuild(guild) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('del', Constants.Endpoints.guild(guild.id), true)
|
||||
.then(() => {
|
||||
resolve(this.rest.client.actions.GuildDelete.handle({ id: guild.id }).guild);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('del', Constants.Endpoints.guild(guild.id), true).then(() => {
|
||||
resolve(this.rest.client.actions.GuildDelete.handle({ id: guild.id }).guild);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
getUser(userID) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('get', Constants.Endpoints.user(userID), true)
|
||||
.then((data) => {
|
||||
resolve(this.rest.client.actions.UserGet.handle(data).user);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('get', Constants.Endpoints.user(userID), true).then((data) => {
|
||||
resolve(this.rest.client.actions.UserGet.handle(data).user);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
updateCurrentUser(_data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const user = this.rest.client.user;
|
||||
const data = {};
|
||||
|
||||
const data = {};
|
||||
data.username = _data.username || user.username;
|
||||
data.avatar = this.rest.client.resolver.resolveBase64(_data.avatar) || user.avatar;
|
||||
if (!user.bot) {
|
||||
@@ -234,44 +204,15 @@ class RESTMethods {
|
||||
|
||||
updateGuild(guild, _data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
/*
|
||||
can contain:
|
||||
name, region, verificationLevel, afkChannel, afkTimeout, icon, owner, splash
|
||||
*/
|
||||
|
||||
const data = {};
|
||||
|
||||
if (_data.name) {
|
||||
data.name = _data.name;
|
||||
}
|
||||
|
||||
if (_data.region) {
|
||||
data.region = _data.region;
|
||||
}
|
||||
|
||||
if (_data.verificationLevel) {
|
||||
data.verification_level = Number(_data.verificationLevel);
|
||||
}
|
||||
|
||||
if (_data.afkChannel) {
|
||||
data.afk_channel_id = this.rest.client.resolver.resolveChannel(_data.afkChannel).id;
|
||||
}
|
||||
|
||||
if (_data.afkTimeout) {
|
||||
data.afk_timeout = Number(_data.afkTimeout);
|
||||
}
|
||||
|
||||
if (_data.icon) {
|
||||
data.icon = this.rest.client.resolver.resolveBase64(_data.icon);
|
||||
}
|
||||
|
||||
if (_data.owner) {
|
||||
data.owner_id = this.rest.client.resolver.resolveUser(_data.owner).id;
|
||||
}
|
||||
|
||||
if (_data.splash) {
|
||||
data.splash = this.rest.client.resolver.resolveBase64(_data.splash);
|
||||
}
|
||||
if (_data.name) data.name = _data.name;
|
||||
if (_data.region) data.region = _data.region;
|
||||
if (_data.verificationLevel) data.verification_level = Number(_data.verificationLevel);
|
||||
if (_data.afkChannel) data.afk_channel_id = this.rest.client.resolver.resolveChannel(_data.afkChannel).id;
|
||||
if (_data.afkTimeout) data.afk_timeout = Number(_data.afkTimeout);
|
||||
if (_data.icon) data.icon = this.rest.client.resolver.resolveBase64(_data.icon);
|
||||
if (_data.owner) data.owner_id = this.rest.client.resolver.resolveUser(_data.owner).id;
|
||||
if (_data.splash) data.splash = this.rest.client.resolver.resolveBase64(_data.splash);
|
||||
|
||||
this.rest.makeRequest('patch', Constants.Endpoints.guild(guild.id), true, data)
|
||||
.then(newData => resolve(this.rest.client.actions.GuildUpdate.handle(newData).updated))
|
||||
@@ -281,40 +222,34 @@ class RESTMethods {
|
||||
|
||||
kickGuildMember(guild, member) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('del', Constants.Endpoints.guildMember(guild.id, member.id), true)
|
||||
.then(() => {
|
||||
resolve(this.rest.client.actions.GuildMemberRemove.handle({
|
||||
guild_id: guild.id,
|
||||
user: member.user,
|
||||
}).member);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('del', Constants.Endpoints.guildMember(guild.id, member.id), true).then(() => {
|
||||
resolve(this.rest.client.actions.GuildMemberRemove.handle({
|
||||
guild_id: guild.id,
|
||||
user: member.user,
|
||||
}).member);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
createGuildRole(guild) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('post', Constants.Endpoints.guildRoles(guild.id), true)
|
||||
.then(role => {
|
||||
resolve(this.rest.client.actions.GuildRoleCreate.handle({
|
||||
guild_id: guild.id,
|
||||
role,
|
||||
}).role);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('post', Constants.Endpoints.guildRoles(guild.id), true).then(role => {
|
||||
resolve(this.rest.client.actions.GuildRoleCreate.handle({
|
||||
guild_id: guild.id,
|
||||
role,
|
||||
}).role);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
deleteGuildRole(role) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('del', Constants.Endpoints.guildRole(role.guild.id, role.id), true)
|
||||
.then(() => {
|
||||
resolve(this.rest.client.actions.GuildRoleDelete.handle({
|
||||
guild_id: role.guild.id,
|
||||
role_id: role.id,
|
||||
}).role);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('del', Constants.Endpoints.guildRole(role.guild.id, role.id), true).then(() => {
|
||||
resolve(this.rest.client.actions.GuildRoleDelete.handle({
|
||||
guild_id: role.guild.id,
|
||||
role_id: role.id,
|
||||
}).role);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -338,23 +273,14 @@ class RESTMethods {
|
||||
getChannelMessages(channel, payload = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = [];
|
||||
if (payload.limit) {
|
||||
params.push(`limit=${payload.limit}`);
|
||||
}
|
||||
if (payload.around) {
|
||||
params.push(`around=${payload.around}`);
|
||||
} else if (payload.before) {
|
||||
params.push(`before=${payload.before}`);
|
||||
} else if (payload.after) {
|
||||
params.push(`after=${payload.after}`);
|
||||
}
|
||||
if (payload.limit) params.push(`limit=${payload.limit}`);
|
||||
if (payload.around) params.push(`around=${payload.around}`);
|
||||
else if (payload.before) params.push(`before=${payload.before}`);
|
||||
else if (payload.after) params.push(`after=${payload.after}`);
|
||||
|
||||
let request = Constants.Endpoints.channelMessages(channel.id);
|
||||
if (params.length > 0) {
|
||||
request += `?${params.join('&')}`;
|
||||
}
|
||||
|
||||
this.rest.makeRequest('get', request, true)
|
||||
let endpoint = Constants.Endpoints.channelMessages(channel.id);
|
||||
if (params.length > 0) endpoint += `?${params.join('&')}`;
|
||||
this.rest.makeRequest('get', endpoint, true)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
});
|
||||
@@ -362,13 +288,9 @@ class RESTMethods {
|
||||
|
||||
updateGuildMember(member, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (data.channel) {
|
||||
data.channel_id = this.rest.client.resolver.resolveChannel(data.channel).id;
|
||||
}
|
||||
if (data.channel) data.channel_id = this.rest.client.resolver.resolveChannel(data.channel).id;
|
||||
if (data.roles) {
|
||||
if (data.roles instanceof Map) {
|
||||
data.roles = data.roles.array();
|
||||
}
|
||||
if (data.roles instanceof Collection) data.roles = data.roles.array();
|
||||
data.roles = data.roles.map(role => role instanceof Role ? role.id : role);
|
||||
}
|
||||
|
||||
@@ -379,6 +301,7 @@ class RESTMethods {
|
||||
endpoint = Constants.Endpoints.stupidInconsistentGuildEndpoint(member.guild.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.rest.makeRequest('patch', endpoint, true, data)
|
||||
.then(resData => resolve(member.guild._updateMember(member, resData).mem))
|
||||
.catch(reject);
|
||||
@@ -407,9 +330,7 @@ class RESTMethods {
|
||||
unbanGuildMember(guild, member) {
|
||||
return new Promise((resolve, reject) => {
|
||||
member = this.rest.client.resolver.resolveUser(member);
|
||||
if (!member) {
|
||||
throw new Error('cannot unban a user that is not a user resolvable');
|
||||
}
|
||||
if (!member) throw new Error('cannot unban a user that is not a user resolvable');
|
||||
const listener = (eGuild, eUser) => {
|
||||
if (guild.id === guild.id && member.id === eUser.id) {
|
||||
this.rest.client.removeListener(Constants.Events.GUILD_BAN_REMOVE, listener);
|
||||
@@ -423,48 +344,30 @@ class RESTMethods {
|
||||
|
||||
getGuildBans(guild) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('get', Constants.Endpoints.guildBans(guild.id), true)
|
||||
.then(banItems => {
|
||||
const bannedUsers = new Collection();
|
||||
for (const banItem of banItems) {
|
||||
const user = this.rest.client.dataManager.newUser(banItem.user);
|
||||
bannedUsers.set(user.id, user);
|
||||
}
|
||||
resolve(bannedUsers);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('get', Constants.Endpoints.guildBans(guild.id), true).then(banItems => {
|
||||
const bannedUsers = new Collection();
|
||||
for (const banItem of banItems) {
|
||||
const user = this.rest.client.dataManager.newUser(banItem.user);
|
||||
bannedUsers.set(user.id, user);
|
||||
}
|
||||
resolve(bannedUsers);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
updateGuildRole(role, _data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
/*
|
||||
can contain:
|
||||
name, position, permissions, color, hoist
|
||||
*/
|
||||
|
||||
const data = {};
|
||||
|
||||
data.name = _data.name || role.name;
|
||||
data.position = _data.position || role.position;
|
||||
data.color = _data.color || role.color;
|
||||
|
||||
if (data.color.startsWith('#')) {
|
||||
data.color = parseInt(data.color.replace('#', ''), 16);
|
||||
}
|
||||
|
||||
if (typeof _data.hoist !== 'undefined') {
|
||||
data.hoist = _data.hoist;
|
||||
} else {
|
||||
data.hoist = role.hoist;
|
||||
}
|
||||
if (data.color.startsWith('#')) data.color = parseInt(data.color.replace('#', ''), 16);
|
||||
data.hoist = typeof _data.hoist !== 'undefined' ? _data.hoist : role.hoist;
|
||||
|
||||
if (_data.permissions) {
|
||||
let perms = 0;
|
||||
for (let perm of _data.permissions) {
|
||||
if (typeof perm === 'string') {
|
||||
perm = Constants.PermissionFlags[perm];
|
||||
}
|
||||
if (typeof perm === 'string') perm = Constants.PermissionFlags[perm];
|
||||
perms |= perm;
|
||||
}
|
||||
data.permissions = perms;
|
||||
@@ -472,14 +375,12 @@ class RESTMethods {
|
||||
data.permissions = role.permissions;
|
||||
}
|
||||
|
||||
this.rest.makeRequest('patch', Constants.Endpoints.guildRole(role.guild.id, role.id), true, data)
|
||||
.then(_role => {
|
||||
resolve(this.rest.client.actions.GuildRoleUpdate.handle({
|
||||
role: _role,
|
||||
guild_id: role.guild.id,
|
||||
}).updated);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('patch', Constants.Endpoints.guildRole(role.guild.id, role.id), true, data).then(_role => {
|
||||
resolve(this.rest.client.actions.GuildRoleUpdate.handle({
|
||||
role: _role,
|
||||
guild_id: role.guild.id,
|
||||
}).updated);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -526,16 +427,14 @@ class RESTMethods {
|
||||
|
||||
getGuildInvites(guild) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.rest.makeRequest('get', Constants.Endpoints.guildInvites(guild.id), true)
|
||||
.then(inviteItems => {
|
||||
const invites = new Collection();
|
||||
for (const inviteItem of inviteItems) {
|
||||
const invite = new Invite(this.rest.client, inviteItem);
|
||||
invites.set(invite.code, invite);
|
||||
}
|
||||
resolve(invites);
|
||||
})
|
||||
.catch(reject);
|
||||
this.rest.makeRequest('get', Constants.Endpoints.guildInvites(guild.id), true).then(inviteItems => {
|
||||
const invites = new Collection();
|
||||
for (const inviteItem of inviteItems) {
|
||||
const invite = new Invite(this.rest.client, inviteItem);
|
||||
invites.set(invite.code, invite);
|
||||
}
|
||||
resolve(invites);
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
* @private
|
||||
*/
|
||||
class RequestHandler {
|
||||
/**
|
||||
* @param {RESTManager} restManager The REST manager to use
|
||||
*/
|
||||
constructor(restManager) {
|
||||
/**
|
||||
* The RESTManager that instantiated this RequestHandler
|
||||
@@ -12,7 +15,7 @@ class RequestHandler {
|
||||
|
||||
/**
|
||||
* A list of requests that have yet to be processed.
|
||||
* @type {Array<APIRequest>}
|
||||
* @type {APIRequest[]}
|
||||
*/
|
||||
this.queue = [];
|
||||
}
|
||||
@@ -31,7 +34,7 @@ class RequestHandler {
|
||||
|
||||
/**
|
||||
* Push a new API request into this bucket
|
||||
* @param {APIRequest} request the new request to push into the queue
|
||||
* @param {APIRequest} request The new request to push into the queue
|
||||
*/
|
||||
push(request) {
|
||||
this.queue.push(request);
|
||||
|
||||
@@ -8,7 +8,10 @@ const RequestHandler = require('./RequestHandler');
|
||||
* @private
|
||||
*/
|
||||
class SequentialRequestHandler extends RequestHandler {
|
||||
|
||||
/**
|
||||
* @param {RESTManager} restManager The REST manager to use
|
||||
* @param {string} endpoint The endpoint to handle
|
||||
*/
|
||||
constructor(restManager, endpoint) {
|
||||
super(restManager, endpoint);
|
||||
|
||||
@@ -39,8 +42,8 @@ class SequentialRequestHandler extends RequestHandler {
|
||||
|
||||
/**
|
||||
* Performs a request then resolves a promise to indicate its readiness for a new request
|
||||
* @param {APIRequest} item the item to execute
|
||||
* @returns {Promise<Object, Error>}
|
||||
* @param {APIRequest} item The item to execute
|
||||
* @returns {Promise<?Object|Error>}
|
||||
*/
|
||||
execute(item) {
|
||||
return new Promise(resolve => {
|
||||
@@ -88,9 +91,8 @@ class SequentialRequestHandler extends RequestHandler {
|
||||
|
||||
handle() {
|
||||
super.handle();
|
||||
if (this.waiting || this.queue.length === 0 || this.globalLimit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.waiting || this.queue.length === 0 || this.globalLimit) return;
|
||||
this.waiting = true;
|
||||
|
||||
const item = this.queue[0];
|
||||
|
||||
@@ -33,9 +33,7 @@ class ClientVoiceManager {
|
||||
*/
|
||||
_checkPendingReady(guildID) {
|
||||
const pendingRequest = this.pending.get(guildID);
|
||||
if (!pendingRequest) {
|
||||
throw new Error('Guild not pending');
|
||||
}
|
||||
if (!pendingRequest) throw new Error('Guild not pending');
|
||||
if (pendingRequest.token && pendingRequest.sessionID && pendingRequest.endpoint) {
|
||||
const { channel, token, sessionID, endpoint, resolve, reject } = pendingRequest;
|
||||
const voiceConnection = new VoiceConnection(this, channel, token, sessionID, endpoint, resolve, reject);
|
||||
@@ -49,15 +47,13 @@ class ClientVoiceManager {
|
||||
|
||||
/**
|
||||
* Called when the Client receives information about this voice server update.
|
||||
* @param {string} guildID the ID of the Guild
|
||||
* @param {string} token the token to authorise with
|
||||
* @param {string} endpoint the endpoint to connect to
|
||||
* @param {string} guildID The ID of the Guild
|
||||
* @param {string} token The token to authorise with
|
||||
* @param {string} endpoint The endpoint to connect to
|
||||
*/
|
||||
_receivedVoiceServer(guildID, token, endpoint) {
|
||||
const pendingRequest = this.pending.get(guildID);
|
||||
if (!pendingRequest) {
|
||||
throw new Error('Guild not pending');
|
||||
}
|
||||
if (!pendingRequest) throw new Error('Guild not pending');
|
||||
pendingRequest.token = token;
|
||||
// remove the port otherwise it errors ¯\_(ツ)_/¯
|
||||
pendingRequest.endpoint = endpoint.match(/([^:]*)/)[0];
|
||||
@@ -66,22 +62,20 @@ class ClientVoiceManager {
|
||||
|
||||
/**
|
||||
* Called when the Client receives information about the voice state update.
|
||||
* @param {string} guildID the ID of the Guild
|
||||
* @param {string} sessionID the session id to authorise with
|
||||
* @param {string} guildID The ID of the Guild
|
||||
* @param {string} sessionID The session id to authorise with
|
||||
*/
|
||||
_receivedVoiceStateUpdate(guildID, sessionID) {
|
||||
const pendingRequest = this.pending.get(guildID);
|
||||
if (!pendingRequest) {
|
||||
throw new Error('Guild not pending');
|
||||
}
|
||||
if (!pendingRequest) throw new Error('Guild not pending');
|
||||
pendingRequest.sessionID = sessionID;
|
||||
this._checkPendingReady(guildID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the main gateway to join a voice channel
|
||||
* @param {VoiceChannel} channel the channel to join
|
||||
* @param {Object} [options] the options to provide
|
||||
* @param {VoiceChannel} channel The channel to join
|
||||
* @param {Object} [options] The options to provide
|
||||
*/
|
||||
_sendWSJoin(channel, options = {}) {
|
||||
options = mergeDefault({
|
||||
@@ -98,14 +92,12 @@ class ClientVoiceManager {
|
||||
|
||||
/**
|
||||
* Sets up a request to join a voice channel
|
||||
* @param {VoiceChannel} channel the voice channel to join
|
||||
* @param {VoiceChannel} channel The voice channel to join
|
||||
* @returns {Promise<VoiceConnection>}
|
||||
*/
|
||||
joinChannel(channel) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.pending.get(channel.guild.id)) {
|
||||
throw new Error('already connecting to a channel in this guild');
|
||||
}
|
||||
if (this.pending.get(channel.guild.id)) throw new Error('already connecting to a channel in this guild');
|
||||
const existingConn = this.connections.get(channel.guild.id);
|
||||
if (existingConn) {
|
||||
if (existingConn.channel.id !== channel.id) {
|
||||
|
||||
@@ -71,14 +71,14 @@ class VoiceConnection extends EventEmitter {
|
||||
/**
|
||||
* Executed whenever an error occurs with the UDP/WebSocket sub-client
|
||||
* @private
|
||||
* @param {Error} err The error that occurred
|
||||
* @param {Error} err The encountered error
|
||||
*/
|
||||
_onError(err) {
|
||||
this._reject(err);
|
||||
/**
|
||||
* Emitted whenever the connection encounters a fatal error.
|
||||
* @event VoiceConnection#error
|
||||
* @param {Error} error the encountered error
|
||||
* @param {Error} error The encountered error
|
||||
*/
|
||||
this.emit('error', err);
|
||||
this._shutdown(err);
|
||||
@@ -86,7 +86,7 @@ class VoiceConnection extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Disconnects the Client from the Voice Channel
|
||||
* @param {string} [reason='user requested'] the reason of the disconnection
|
||||
* @param {string} [reason='user requested'] The reason of the disconnection
|
||||
*/
|
||||
disconnect(reason = 'user requested') {
|
||||
this.manager.client.ws.send({
|
||||
@@ -107,19 +107,15 @@ class VoiceConnection extends EventEmitter {
|
||||
}
|
||||
|
||||
_shutdown(e) {
|
||||
if (!this.ready) {
|
||||
return;
|
||||
}
|
||||
if (!this.ready) return;
|
||||
this.ready = false;
|
||||
this.websocket._shutdown();
|
||||
this.player._shutdown();
|
||||
if (this.udp) {
|
||||
this.udp._shutdown();
|
||||
}
|
||||
if (this.udp) this.udp._shutdown();
|
||||
/**
|
||||
* Emit once the voice connection has disconnected.
|
||||
* @event VoiceConnection#disconnected
|
||||
* @param {Error} error the error, if any
|
||||
* @param {Error} error The encountered error, if any
|
||||
*/
|
||||
this.emit('disconnected', e);
|
||||
}
|
||||
@@ -149,9 +145,7 @@ class VoiceConnection extends EventEmitter {
|
||||
});
|
||||
this.once('ready', () => {
|
||||
setImmediate(() => {
|
||||
for (const item of this.queue) {
|
||||
this.emit(...item);
|
||||
}
|
||||
for (const item of this.queue) this.emit(...item);
|
||||
this.queue = [];
|
||||
});
|
||||
});
|
||||
@@ -197,21 +191,18 @@ class VoiceConnection extends EventEmitter {
|
||||
/**
|
||||
* Emitted whenever a user starts/stops speaking
|
||||
* @event VoiceConnection#speaking
|
||||
* @param {User} user the user that has started/stopped speaking
|
||||
* @param {boolean} speaking whether or not the user is speaking
|
||||
* @param {User} user The user that has started/stopped speaking
|
||||
* @param {boolean} speaking Whether or not the user is speaking
|
||||
*/
|
||||
if (this.ready) {
|
||||
this.emit('speaking', user, data.speaking);
|
||||
} else {
|
||||
this.queue.push(['speaking', user, data.speaking]);
|
||||
}
|
||||
if (this.ready) this.emit('speaking', user, data.speaking);
|
||||
else this.queue.push(['speaking', user, data.speaking]);
|
||||
guild._memberSpeakUpdate(data.user_id, data.speaking);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the given file in the voice connection
|
||||
* @param {string} file the path to the file
|
||||
* @param {string} file The path to the file
|
||||
* @returns {StreamDispatcher}
|
||||
* @example
|
||||
* // play files natively
|
||||
@@ -227,7 +218,7 @@ class VoiceConnection extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Plays and converts an audio stream in the voice connection
|
||||
* @param {ReadableStream} stream the audio stream to play
|
||||
* @param {ReadableStream} stream The audio stream to play
|
||||
* @returns {StreamDispatcher}
|
||||
* @example
|
||||
* // play streams using ytdl-core
|
||||
@@ -245,7 +236,7 @@ class VoiceConnection extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Plays a stream of 16-bit signed stereo PCM at 48KHz.
|
||||
* @param {ReadableStream} stream the audio stream to play.
|
||||
* @param {ReadableStream} stream The audio stream to play.
|
||||
* @returns {StreamDispatcher}
|
||||
*/
|
||||
playConvertedStream(stream) {
|
||||
|
||||
@@ -4,7 +4,6 @@ const Constants = require('../../util/Constants');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
class VoiceConnectionUDPClient extends EventEmitter {
|
||||
|
||||
constructor(voiceConnection, data) {
|
||||
super();
|
||||
this.voiceConnection = voiceConnection;
|
||||
@@ -38,9 +37,7 @@ class VoiceConnectionUDPClient extends EventEmitter {
|
||||
try {
|
||||
this.udpSocket.close();
|
||||
} catch (err) {
|
||||
if (err.message !== 'Not running') {
|
||||
this.emit('error', err);
|
||||
}
|
||||
if (err.message !== 'Not running') this.emit('error', err);
|
||||
}
|
||||
this.udpSocket = null;
|
||||
}
|
||||
@@ -55,10 +52,7 @@ class VoiceConnectionUDPClient extends EventEmitter {
|
||||
this.udpSocket.once('message', message => {
|
||||
const packet = new Buffer(message);
|
||||
this.localIP = '';
|
||||
for (let i = 4; i < packet.indexOf(0, i); i++) {
|
||||
this.localIP += String.fromCharCode(packet[i]);
|
||||
}
|
||||
|
||||
for (let i = 4; i < packet.indexOf(0, i); i++) this.localIP += String.fromCharCode(packet[i]);
|
||||
this.localPort = parseInt(packet.readUIntLE(packet.length - 2, 2).toString(10), 10);
|
||||
|
||||
this.voiceConnection.websocket.send({
|
||||
@@ -77,7 +71,6 @@ class VoiceConnectionUDPClient extends EventEmitter {
|
||||
this.udpSocket.on('error', (error, message) => {
|
||||
this.emit('error', { error, message });
|
||||
});
|
||||
|
||||
this.udpSocket.on('close', error => {
|
||||
this.emit('close', error);
|
||||
});
|
||||
@@ -86,7 +79,6 @@ class VoiceConnectionUDPClient extends EventEmitter {
|
||||
blankMessage.writeUIntBE(this.data.ssrc, 0, 4);
|
||||
this.send(blankMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = VoiceConnectionUDPClient;
|
||||
|
||||
@@ -26,15 +26,11 @@ class VoiceConnectionWebSocket extends EventEmitter {
|
||||
}
|
||||
|
||||
send(data) {
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify(data));
|
||||
}
|
||||
if (this.ws.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
_shutdown() {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
}
|
||||
if (this.ws) this.ws.close();
|
||||
clearInterval(this.heartbeat);
|
||||
}
|
||||
|
||||
@@ -97,9 +93,7 @@ class VoiceConnectionWebSocket extends EventEmitter {
|
||||
case Constants.VoiceOPCodes.SESSION_DESCRIPTION:
|
||||
this.encryptionMode = packet.d.mode;
|
||||
this.secretKey = new Uint8Array(new ArrayBuffer(packet.d.secret_key.length));
|
||||
for (const index in packet.d.secret_key) {
|
||||
this.secretKey[index] = packet.d.secret_key[index];
|
||||
}
|
||||
for (const index in packet.d.secret_key) this.secretKey[index] = packet.d.secret_key[index];
|
||||
this.emit('ready', this.secretKey);
|
||||
break;
|
||||
case Constants.VoiceOPCodes.SPEAKING:
|
||||
|
||||
@@ -34,10 +34,10 @@ class StreamDispatcher extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted when the dispatcher starts/stops speaking
|
||||
* @event StreamDispatcher#speaking
|
||||
* @param {boolean} value whether or not the dispatcher is speaking
|
||||
*/
|
||||
* Emitted when the dispatcher starts/stops speaking
|
||||
* @event StreamDispatcher#speaking
|
||||
* @param {boolean} value Whether or not the dispatcher is speaking
|
||||
*/
|
||||
_setSpeaking(value) {
|
||||
this.speaking = value;
|
||||
this.emit('speaking', value);
|
||||
@@ -62,27 +62,18 @@ class StreamDispatcher extends EventEmitter {
|
||||
packetBuffer.copy(nonce, 0, 0, 12);
|
||||
buffer = NaCl.secretbox(buffer, nonce, this.player.connection.data.secret);
|
||||
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
packetBuffer[i + 12] = buffer[i];
|
||||
}
|
||||
for (let i = 0; i < buffer.length; i++) packetBuffer[i + 12] = buffer[i];
|
||||
|
||||
return packetBuffer;
|
||||
}
|
||||
|
||||
_applyVolume(buffer) {
|
||||
if (this._volume === 1) {
|
||||
return buffer;
|
||||
}
|
||||
if (this._volume === 1) return buffer;
|
||||
|
||||
const out = new Buffer(buffer.length);
|
||||
|
||||
for (let i = 0; i < buffer.length; i += 2) {
|
||||
if (i >= buffer.length - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= buffer.length - 1) break;
|
||||
const uint = Math.min(32767, Math.max(-32767, Math.floor(this._volume * buffer.readInt16LE(i))));
|
||||
|
||||
out.writeInt16LE(uint, i);
|
||||
}
|
||||
|
||||
@@ -95,20 +86,24 @@ class StreamDispatcher extends EventEmitter {
|
||||
this._setSpeaking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = this.streamingData;
|
||||
|
||||
if (data.missed >= 5) {
|
||||
this._triggerTerminalState('error', new Error('stream is not generating fast enough'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.paused) {
|
||||
data.timestamp = data.timestamp + 4294967295 ? data.timestamp + 960 : 0;
|
||||
this.player.connection.manager.client.setTimeout(() => this._send(), data.length * 10);
|
||||
return;
|
||||
}
|
||||
const bufferLength = 1920 * data.channels;
|
||||
this._setSpeaking(true);
|
||||
let buffer = this.stream.read(bufferLength);
|
||||
|
||||
this._setSpeaking(true);
|
||||
|
||||
const bufferLength = 1920 * data.channels;
|
||||
let buffer = this.stream.read(bufferLength);
|
||||
if (!buffer) {
|
||||
data.missed++;
|
||||
this.player.connection.manager.client.setTimeout(() => this._send(), data.length * 10);
|
||||
@@ -132,7 +127,6 @@ class StreamDispatcher extends EventEmitter {
|
||||
this._sendBuffer(buffer, data.sequence, data.timestamp);
|
||||
|
||||
const nextTime = data.startTime + (data.count * data.length);
|
||||
|
||||
this.player.connection.manager.client.setTimeout(() => this._send(), data.length + (nextTime - Date.now()));
|
||||
} catch (e) {
|
||||
this._triggerTerminalState('error', e);
|
||||
@@ -140,33 +134,31 @@ class StreamDispatcher extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted once the stream has ended. Attach a `once` listener to this.
|
||||
* @event StreamDispatcher#end
|
||||
*/
|
||||
* Emitted once the stream has ended. Attach a `once` listener to this.
|
||||
* @event StreamDispatcher#end
|
||||
*/
|
||||
_triggerEnd() {
|
||||
this.emit('end');
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted once the stream has encountered an error. Attach a `once` listener to this. Also emits `end`.
|
||||
* @event StreamDispatcher#error
|
||||
* @param {Error} err the error encountered
|
||||
*/
|
||||
* Emitted once the stream has encountered an error. Attach a `once` listener to this. Also emits `end`.
|
||||
* @event StreamDispatcher#error
|
||||
* @param {Error} err The encountered error
|
||||
*/
|
||||
_triggerError(err) {
|
||||
this.emit('end');
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
_triggerTerminalState(state, err) {
|
||||
if (this._triggered) {
|
||||
return;
|
||||
}
|
||||
if (this._triggered) return;
|
||||
|
||||
/**
|
||||
* Emitted when the stream wants to give debug information.
|
||||
* @event StreamDispatcher#debug
|
||||
* @param {string} information the debug information
|
||||
*/
|
||||
* Emitted when the stream wants to give debug information.
|
||||
* @event StreamDispatcher#debug
|
||||
* @param {string} information The debug information
|
||||
*/
|
||||
this.emit('debug', `triggered terminal state ${state} - stream is now dead`);
|
||||
this._triggered = true;
|
||||
this._setSpeaking(false);
|
||||
@@ -188,17 +180,20 @@ class StreamDispatcher extends EventEmitter {
|
||||
this.emit('error', 'no stream');
|
||||
return;
|
||||
}
|
||||
|
||||
this.stream.on('end', err => this._triggerTerminalState('end', err));
|
||||
this.stream.on('error', err => this._triggerTerminalState('error', err));
|
||||
|
||||
const data = this.streamingData;
|
||||
data.length = 20;
|
||||
data.missed = 0;
|
||||
data.startTime = Date.now();
|
||||
|
||||
this.stream.once('readable', () => this._send());
|
||||
}
|
||||
|
||||
_pause(value) {
|
||||
if (value) {
|
||||
_setPaused(paused) {
|
||||
if (paused) {
|
||||
this.paused = true;
|
||||
this._setSpeaking(false);
|
||||
} else {
|
||||
@@ -225,7 +220,7 @@ class StreamDispatcher extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Sets the volume relative to the input stream - i.e. 1 is normal, 0.5 is half, 2 is double.
|
||||
* @param {number} volume the volume that you want to set
|
||||
* @param {number} volume The volume that you want to set
|
||||
*/
|
||||
setVolume(volume) {
|
||||
this._volume = volume;
|
||||
@@ -233,7 +228,7 @@ class StreamDispatcher extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Set the volume in decibels
|
||||
* @param {number} db the decibels
|
||||
* @param {number} db The decibels
|
||||
*/
|
||||
setVolumeDecibels(db) {
|
||||
this._volume = Math.pow(10, db / 20);
|
||||
@@ -241,7 +236,7 @@ class StreamDispatcher extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Set the volume so that a perceived value of 0.5 is half the perceived volume etc.
|
||||
* @param {number} value the value for the volume
|
||||
* @param {number} value The value for the volume
|
||||
*/
|
||||
setVolumeLogarithmic(value) {
|
||||
this._volume = Math.pow(value, 1.660964);
|
||||
@@ -251,14 +246,14 @@ class StreamDispatcher extends EventEmitter {
|
||||
* Stops sending voice packets to the voice connection (stream may still progress however)
|
||||
*/
|
||||
pause() {
|
||||
this._pause(true);
|
||||
this._setPaused(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes sending voice packets to the voice connection (may be further on in the stream than when paused)
|
||||
*/
|
||||
resume() {
|
||||
this._pause(false);
|
||||
this._setPaused(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ class NodeOpusEngine extends OpusEngine {
|
||||
constructor(player) {
|
||||
super(player);
|
||||
try {
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
opus = require('node-opus');
|
||||
} catch (err) {
|
||||
throw err;
|
||||
|
||||
@@ -3,10 +3,6 @@ const list = [
|
||||
require('./OpusScriptEngine'),
|
||||
];
|
||||
|
||||
exports.add = encoder => {
|
||||
list.push(encoder);
|
||||
};
|
||||
|
||||
function fetch(Encoder) {
|
||||
try {
|
||||
return new Encoder();
|
||||
@@ -15,12 +11,14 @@ function fetch(Encoder) {
|
||||
}
|
||||
}
|
||||
|
||||
exports.add = encoder => {
|
||||
list.push(encoder);
|
||||
};
|
||||
|
||||
exports.fetch = () => {
|
||||
for (const encoder of list) {
|
||||
const success = fetch(encoder);
|
||||
if (success) {
|
||||
return success;
|
||||
}
|
||||
const fetched = fetch(encoder);
|
||||
if (fetched) return fetched;
|
||||
}
|
||||
throw new Error('could not find an opus engine');
|
||||
};
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
const OpusEngine = require('./BaseOpusEngine');
|
||||
|
||||
let Opusscript;
|
||||
let OpusScript;
|
||||
|
||||
class NodeOpusEngine extends OpusEngine {
|
||||
constructor(player) {
|
||||
super(player);
|
||||
try {
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
Opusscript = require('opusscript');
|
||||
OpusScript = require('opusscript');
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
this.encoder = new Opusscript(48000, 2);
|
||||
this.encoder = new OpusScript(48000, 2);
|
||||
}
|
||||
|
||||
encode(buffer) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
class ConverterEngine extends EventEmitter {
|
||||
|
||||
constructor(player) {
|
||||
super();
|
||||
this.player = player;
|
||||
@@ -10,7 +9,6 @@ class ConverterEngine extends EventEmitter {
|
||||
createConvertStream() {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ConverterEngine;
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
const ConverterEngine = require('./ConverterEngine');
|
||||
const ChildProcess = require('child_process');
|
||||
|
||||
function chooseCommand() {
|
||||
for (const cmd of ['ffmpeg', 'avconv', './ffmpeg', './avconv']) {
|
||||
if (!ChildProcess.spawnSync(cmd, ['-h']).error) {
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class FfmpegConverterEngine extends ConverterEngine {
|
||||
constructor(player) {
|
||||
super(player);
|
||||
@@ -17,9 +8,7 @@ class FfmpegConverterEngine extends ConverterEngine {
|
||||
}
|
||||
|
||||
handleError(encoder, err) {
|
||||
if (encoder.destroy) {
|
||||
encoder.destroy();
|
||||
}
|
||||
if (encoder.destroy) encoder.destroy();
|
||||
this.emit('error', err);
|
||||
}
|
||||
|
||||
@@ -41,4 +30,11 @@ class FfmpegConverterEngine extends ConverterEngine {
|
||||
}
|
||||
}
|
||||
|
||||
function chooseCommand() {
|
||||
for (const cmd of ['ffmpeg', 'avconv', './ffmpeg', './avconv']) {
|
||||
if (!ChildProcess.spawnSync(cmd, ['-h']).error) return cmd;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = FfmpegConverterEngine;
|
||||
|
||||
@@ -5,7 +5,6 @@ const StreamDispatcher = require('../dispatcher/StreamDispatcher');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
|
||||
class VoiceConnectionPlayer extends EventEmitter {
|
||||
|
||||
constructor(connection) {
|
||||
super();
|
||||
this.connection = connection;
|
||||
@@ -38,9 +37,7 @@ class VoiceConnectionPlayer extends EventEmitter {
|
||||
|
||||
_shutdown() {
|
||||
this.speaking = false;
|
||||
for (const stream of this.processMap.keys()) {
|
||||
this.killStream(stream);
|
||||
}
|
||||
for (const stream of this.processMap.keys()) this.killStream(stream);
|
||||
}
|
||||
|
||||
killStream(stream) {
|
||||
@@ -79,9 +76,7 @@ class VoiceConnectionPlayer extends EventEmitter {
|
||||
}
|
||||
|
||||
setSpeaking(value) {
|
||||
if (this.speaking === value) {
|
||||
return;
|
||||
}
|
||||
if (this.speaking === value) return;
|
||||
this.speaking = value;
|
||||
this.connection.websocket.send({
|
||||
op: Constants.VoiceOPCodes.SPEAKING,
|
||||
@@ -100,7 +95,6 @@ class VoiceConnectionPlayer extends EventEmitter {
|
||||
this.dispatcher = dispatcher;
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = VoiceConnectionPlayer;
|
||||
|
||||
@@ -2,7 +2,6 @@ const BasePlayer = require('./BasePlayer');
|
||||
const fs = require('fs');
|
||||
|
||||
class DefaultPlayer extends BasePlayer {
|
||||
|
||||
playFile(file) {
|
||||
return this.playStream(fs.createReadStream(file));
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ class VoiceReadable extends Readable {
|
||||
return;
|
||||
}
|
||||
|
||||
$push(d) {
|
||||
if (this.open) {
|
||||
this.push(d);
|
||||
}
|
||||
_push(d) {
|
||||
if (this.open) this.push(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ class VoiceReceiver extends EventEmitter {
|
||||
/**
|
||||
* Creates a readable stream for a user that provides opus data while the user is speaking. When the user
|
||||
* stops speaking, the stream is destroyed.
|
||||
* @param {UserResolvable} user the user to create the stream for
|
||||
* @param {UserResolvable} user The user to create the stream for
|
||||
* @returns {ReadableStream}
|
||||
*/
|
||||
createOpusStream(user) {
|
||||
@@ -72,17 +72,13 @@ class VoiceReceiver extends EventEmitter {
|
||||
/**
|
||||
* Creates a readable stream for a user that provides PCM data while the user is speaking. When the user
|
||||
* stops speaking, the stream is destroyed. The stream is 16-bit signed stereo PCM at 48KHz.
|
||||
* @param {UserResolvable} user the user to create the stream for
|
||||
* @param {UserResolvable} user The user to create the stream for
|
||||
* @returns {ReadableStream}
|
||||
*/
|
||||
createPCMStream(user) {
|
||||
user = this.connection.manager.client.resolver.resolveUser(user);
|
||||
if (!user) {
|
||||
throw new Error('invalid user object supplied');
|
||||
}
|
||||
if (this.pcmStreams.get(user.id)) {
|
||||
throw new Error('there is already an existing stream for that user!');
|
||||
}
|
||||
if (!user) throw new Error('invalid user object supplied');
|
||||
if (this.pcmStreams.get(user.id)) throw new Error('there is already an existing stream for that user!');
|
||||
const stream = new Readable();
|
||||
this.pcmStreams.set(user.id, stream);
|
||||
return stream;
|
||||
@@ -95,34 +91,30 @@ class VoiceReceiver extends EventEmitter {
|
||||
/**
|
||||
* Emitted whenever a voice packet cannot be decrypted
|
||||
* @event VoiceReceiver#warn
|
||||
* @param {string} message the warning message
|
||||
* @param {string} message The warning message
|
||||
*/
|
||||
this.emit('warn', 'failed to decrypt voice packet');
|
||||
return;
|
||||
}
|
||||
data = new Buffer(data);
|
||||
/**
|
||||
* Emitted whenever voice data is received from the voice connection. This is _always_ emitted (unlike PCM).
|
||||
* @event VoiceReceiver#opus
|
||||
* @param {User} user the user that is sending the buffer (is speaking)
|
||||
* @param {Buffer} buffer the opus buffer
|
||||
*/
|
||||
if (this.opusStreams.get(user.id)) {
|
||||
this.opusStreams.get(user.id).$push(data);
|
||||
}
|
||||
if (this.opusStreams.get(user.id)) this.opusStreams.get(user.id)._push(data);
|
||||
/**
|
||||
* Emitted whenever voice data is received from the voice connection. This is _always_ emitted (unlike PCM).
|
||||
* @event VoiceReceiver#opus
|
||||
* @param {User} user The user that is sending the buffer (is speaking)
|
||||
* @param {Buffer} buffer The opus buffer
|
||||
*/
|
||||
this.emit('opus', user, data);
|
||||
if (this.listenerCount('pcm') > 0 || this.pcmStreams.size > 0) {
|
||||
/**
|
||||
* Emits decoded voice data when it's received. For performance reasons, the decoding will only
|
||||
* happen if there is at least one `pcm` listener on this receiver.
|
||||
* @event VoiceReceiver#pcm
|
||||
* @param {User} user the user that is sending the buffer (is speaking)
|
||||
* @param {Buffer} buffer the decoded buffer
|
||||
*/
|
||||
* Emits decoded voice data when it's received. For performance reasons, the decoding will only
|
||||
* happen if there is at least one `pcm` listener on this receiver.
|
||||
* @event VoiceReceiver#pcm
|
||||
* @param {User} user The user that is sending the buffer (is speaking)
|
||||
* @param {Buffer} buffer The decoded buffer
|
||||
*/
|
||||
const pcm = this.connection.player.opusEncoder.decode(data);
|
||||
if (this.pcmStreams.get(user.id)) {
|
||||
this.pcmStreams.get(user.id).$push(pcm);
|
||||
}
|
||||
if (this.pcmStreams.get(user.id)) this.pcmStreams.get(user.id)._push(pcm);
|
||||
this.emit('pcm', user, pcm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,12 @@ const PacketManager = require('./packets/WebSocketPacketManager');
|
||||
* @private
|
||||
*/
|
||||
class WebSocketManager {
|
||||
|
||||
constructor(client) {
|
||||
/**
|
||||
* The Client that instantiated this WebSocketManager
|
||||
* @type {Client}
|
||||
*/
|
||||
this.client = client;
|
||||
this.ws = null;
|
||||
/**
|
||||
* A WebSocket Packet manager, it handles all the messages
|
||||
* @type {PacketManager}
|
||||
@@ -26,43 +24,40 @@ class WebSocketManager {
|
||||
* @type {number}
|
||||
*/
|
||||
this.status = Constants.Status.IDLE;
|
||||
|
||||
/**
|
||||
* The session ID of the connection, null if not yet available.
|
||||
* @type {?string}
|
||||
*/
|
||||
this.sessionID = null;
|
||||
|
||||
/**
|
||||
* The packet count of the client, null if not yet available.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.sequence = -1;
|
||||
|
||||
/**
|
||||
* The gateway address for this WebSocket connection, null if not yet available.
|
||||
* @type {?string}
|
||||
*/
|
||||
this.gateway = null;
|
||||
|
||||
/**
|
||||
* Whether READY was emitted normally (all packets received) or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.normalReady = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects the client to a given gateway
|
||||
* @param {string} gateway the gateway to connect to
|
||||
*/
|
||||
connect(gateway) {
|
||||
this.normalReady = false;
|
||||
this.status = Constants.Status.CONNECTING;
|
||||
/**
|
||||
* The WebSocket connection to the gateway
|
||||
* @type {?WebSocket}
|
||||
*/
|
||||
this.ws = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects the client to a given gateway
|
||||
* @param {string} gateway The gateway to connect to
|
||||
*/
|
||||
connect(gateway) {
|
||||
this.normalReady = false;
|
||||
this.status = Constants.Status.CONNECTING;
|
||||
this.ws = new WebSocket(gateway);
|
||||
this.ws.onopen = () => this.eventOpen();
|
||||
this.ws.onclose = (d) => this.eventClose(d);
|
||||
@@ -113,15 +108,12 @@ class WebSocketManager {
|
||||
* Run whenever the gateway connections opens up
|
||||
*/
|
||||
eventOpen() {
|
||||
if (this.reconnecting) {
|
||||
this._sendResume();
|
||||
} else {
|
||||
this._sendNewIdentify();
|
||||
}
|
||||
if (this.reconnecting) this._sendResume();
|
||||
else this._sendNewIdentify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a gatway resume packet, in cases of unexpected disconnections.
|
||||
* Sends a gateway resume packet, in cases of unexpected disconnections.
|
||||
*/
|
||||
_sendResume() {
|
||||
const payload = {
|
||||
@@ -155,30 +147,23 @@ class WebSocketManager {
|
||||
|
||||
/**
|
||||
* Run whenever the connection to the gateway is closed, it will try to reconnect the client.
|
||||
* @param {Object} event the event
|
||||
* @param {Object} event The received websocket data
|
||||
*/
|
||||
eventClose(event) {
|
||||
if (event.code === 4004) {
|
||||
throw Constants.Errors.BAD_LOGIN;
|
||||
}
|
||||
if (!this.reconnecting && event.code !== 1000) {
|
||||
this.tryReconnect();
|
||||
}
|
||||
if (event.code === 4004) throw Constants.Errors.BAD_LOGIN;
|
||||
if (!this.reconnecting && event.code !== 1000) this.tryReconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run whenever a message is received from the WebSocket. Returns `true` if the message
|
||||
* was handled properly.
|
||||
* @param {Object} event the received websocket data
|
||||
* @param {Object} event The received websocket data
|
||||
* @returns {boolean}
|
||||
*/
|
||||
eventMessage(event) {
|
||||
let packet;
|
||||
try {
|
||||
if (event.binary) {
|
||||
event.data = zlib.inflateSync(event.data).toString();
|
||||
}
|
||||
|
||||
if (event.binary) event.data = zlib.inflateSync(event.data).toString();
|
||||
packet = JSON.parse(event.data);
|
||||
} catch (e) {
|
||||
return this.eventError(Constants.Errors.BAD_WS_MESSAGE);
|
||||
@@ -186,22 +171,19 @@ class WebSocketManager {
|
||||
|
||||
this.client.emit('raw', packet);
|
||||
|
||||
if (packet.op === 10) {
|
||||
this.client.manager.setupKeepAlive(packet.d.heartbeat_interval);
|
||||
}
|
||||
|
||||
if (packet.op === 10) this.client.manager.setupKeepAlive(packet.d.heartbeat_interval);
|
||||
return this.packetManager.handle(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run whenever an error occurs with the WebSocket connection. Tries to reconnect
|
||||
* @param {Error} err the error that occurred
|
||||
* @param {Error} err The encountered error
|
||||
*/
|
||||
eventError(err) {
|
||||
/**
|
||||
* Emitted whenever the Client encounters a serious connection error
|
||||
* @event Client#error
|
||||
* @param {Error} error the encountered error
|
||||
* @param {Error} error The encountered error
|
||||
*/
|
||||
this.client.emit('error', err);
|
||||
this.tryReconnect();
|
||||
@@ -210,7 +192,6 @@ class WebSocketManager {
|
||||
_emitReady(normal = true) {
|
||||
/**
|
||||
* Emitted when the Client becomes ready to start working
|
||||
*
|
||||
* @event Client#ready
|
||||
*/
|
||||
this.status = Constants.Status.READY;
|
||||
@@ -252,10 +233,9 @@ class WebSocketManager {
|
||||
this.ws.close();
|
||||
this.packetManager.handleQueue();
|
||||
/**
|
||||
* Emitted when the Client tries to reconnect after being disconnected
|
||||
*
|
||||
* @event Client#reconnecting
|
||||
*/
|
||||
* Emitted when the Client tries to reconnect after being disconnected
|
||||
* @event Client#reconnecting
|
||||
*/
|
||||
this.client.emit(Constants.Events.RECONNECTING);
|
||||
this.connect(this.client.ws.gateway);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ const BeforeReadyWhitelist = [
|
||||
];
|
||||
|
||||
class WebSocketPacketManager {
|
||||
|
||||
constructor(websocketManager) {
|
||||
this.ws = websocketManager;
|
||||
this.handlers = {};
|
||||
@@ -62,9 +61,7 @@ class WebSocketPacketManager {
|
||||
}
|
||||
|
||||
setSequence(s) {
|
||||
if (s && s > this.ws.sequence) {
|
||||
this.ws.sequence = s;
|
||||
}
|
||||
if (s && s > this.ws.sequence) this.ws.sequence = s;
|
||||
}
|
||||
|
||||
handle(packet) {
|
||||
@@ -93,13 +90,9 @@ class WebSocketPacketManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.handlers[packet.t]) {
|
||||
return this.handlers[packet.t].handle(packet);
|
||||
}
|
||||
|
||||
if (this.handlers[packet.t]) return this.handlers[packet.t].handle(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = WebSocketPacketManager;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class AbstractHandler {
|
||||
|
||||
constructor(packetManager) {
|
||||
this.packetManager = packetManager;
|
||||
}
|
||||
|
||||
@@ -3,25 +3,18 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class ChannelCreateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const response = client.actions.ChannelCreate.handle(data);
|
||||
|
||||
if (response.channel) {
|
||||
client.emit(Constants.Events.CHANNEL_CREATE, response.channel);
|
||||
}
|
||||
if (response.channel) client.emit(Constants.Events.CHANNEL_CREATE, response.channel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a Channel is created.
|
||||
*
|
||||
* @event Client#channelCreate
|
||||
* @param {Channel} channel The channel that was created
|
||||
*/
|
||||
* Emitted whenever a Channel is created.
|
||||
* @event Client#channelCreate
|
||||
* @param {Channel} channel The channel that was created
|
||||
*/
|
||||
|
||||
module.exports = ChannelCreateHandler;
|
||||
|
||||
@@ -3,25 +3,18 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class ChannelDeleteHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const response = client.actions.ChannelDelete.handle(data);
|
||||
|
||||
if (response.channel) {
|
||||
client.emit(Constants.Events.CHANNEL_DELETE, response.channel);
|
||||
}
|
||||
if (response.channel) client.emit(Constants.Events.CHANNEL_DELETE, response.channel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a Channel is deleted.
|
||||
*
|
||||
* @event Client#channelDelete
|
||||
* @param {Channel} channel The channel that was deleted
|
||||
*/
|
||||
* Emitted whenever a Channel is deleted.
|
||||
* @event Client#channelDelete
|
||||
* @param {Channel} channel The channel that was deleted
|
||||
*/
|
||||
|
||||
module.exports = ChannelDeleteHandler;
|
||||
|
||||
@@ -8,31 +8,24 @@ const Constants = require('../../../../util/Constants');
|
||||
d:
|
||||
{ last_pin_timestamp: '2016-08-28T17:37:13.171774+00:00',
|
||||
channel_id: '314866471639044027' } }
|
||||
*/
|
||||
*/
|
||||
|
||||
class ChannelPinsUpdate extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const channel = client.channels.get(data.channel_id);
|
||||
const time = new Date(data.last_pin_timestamp);
|
||||
|
||||
if (channel && time) {
|
||||
client.emit(Constants.Events.CHANNEL_PINS_UPDATE, channel, time);
|
||||
}
|
||||
if (channel && time) client.emit(Constants.Events.CHANNEL_PINS_UPDATE, channel, time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever the pins of a Channel are updated. Due to the nature of the WebSocket event, not much information
|
||||
* can be provided easily here - you need to manually check the pins yourself.
|
||||
*
|
||||
* @event Client#channelPinsUpdate
|
||||
* @param {Channel} channel The channel that the pins update occured in
|
||||
* @param {Date} time the time of the pins update
|
||||
*/
|
||||
* Emitted whenever the pins of a Channel are updated. Due to the nature of the WebSocket event, not much information
|
||||
* can be provided easily here - you need to manually check the pins yourself.
|
||||
* @event Client#channelPinsUpdate
|
||||
* @param {Channel} channel The channel that the pins update occured in
|
||||
* @param {Date} time The time of the pins update
|
||||
*/
|
||||
|
||||
module.exports = ChannelPinsUpdate;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class ChannelUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.ChannelUpdate.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ChannelUpdateHandler;
|
||||
|
||||
@@ -4,27 +4,20 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class GuildBanAddHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
const user = client.users.get(data.user.id);
|
||||
|
||||
if (guild && user) {
|
||||
client.emit(Constants.Events.GUILD_BAN_ADD, guild, user);
|
||||
}
|
||||
if (guild && user) client.emit(Constants.Events.GUILD_BAN_ADD, guild, user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a member is banned from a guild.
|
||||
*
|
||||
* @event Client#guildBanAdd
|
||||
* @param {Guild} guild The guild that the ban occurred in
|
||||
* @param {User} user The user that was banned
|
||||
*/
|
||||
* Emitted whenever a member is banned from a guild.
|
||||
* @event Client#guildBanAdd
|
||||
* @param {Guild} guild The guild that the ban occurred in
|
||||
* @param {User} user The user that was banned
|
||||
*/
|
||||
|
||||
module.exports = GuildBanAddHandler;
|
||||
|
||||
@@ -3,22 +3,18 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildBanRemoveHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildBanRemove.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a member is unbanned from a guild.
|
||||
*
|
||||
* @event Client#guildBanRemove
|
||||
* @param {Guild} guild The guild that the unban occurred in
|
||||
* @param {User} user The user that was unbanned
|
||||
*/
|
||||
* Emitted whenever a member is unbanned from a guild.
|
||||
* @event Client#guildBanRemove
|
||||
* @param {Guild} guild The guild that the unban occurred in
|
||||
* @param {User} user The user that was unbanned
|
||||
*/
|
||||
|
||||
module.exports = GuildBanRemoveHandler;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildCreateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const data = packet.d;
|
||||
|
||||
const guild = client.guilds.get(data.id);
|
||||
|
||||
if (guild) {
|
||||
if (!guild.available && !data.unavailable) {
|
||||
// a newly available guild
|
||||
@@ -19,7 +17,6 @@ class GuildCreateHandler extends AbstractHandler {
|
||||
client.dataManager.newGuild(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildCreateHandler;
|
||||
|
||||
@@ -2,25 +2,18 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class GuildDeleteHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const response = client.actions.GuildDelete.handle(data);
|
||||
|
||||
if (response.guild) {
|
||||
client.emit(Constants.Events.GUILD_DELETE, response.guild);
|
||||
}
|
||||
if (response.guild) client.emit(Constants.Events.GUILD_DELETE, response.guild);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a Guild is deleted/left.
|
||||
*
|
||||
* @event Client#guildDelete
|
||||
* @param {Guild} guild The guild that was deleted
|
||||
*/
|
||||
* Emitted whenever a Guild is deleted/left.
|
||||
* @event Client#guildDelete
|
||||
* @param {Guild} guild The guild that was deleted
|
||||
*/
|
||||
|
||||
module.exports = GuildDeleteHandler;
|
||||
|
||||
@@ -3,19 +3,15 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildMemberAddHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
|
||||
if (guild) {
|
||||
guild.memberCount++;
|
||||
guild._addMember(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildMemberAddHandler;
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildMemberRemoveHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildMemberRemove.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildMemberRemoveHandler;
|
||||
|
||||
@@ -3,21 +3,16 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildMemberUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const data = packet.d;
|
||||
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
|
||||
if (guild) {
|
||||
const member = guild.members.get(data.user.id);
|
||||
if (member) {
|
||||
guild._updateMember(member, data);
|
||||
}
|
||||
if (member) guild._updateMember(member, data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildMemberUpdateHandler;
|
||||
|
||||
@@ -4,31 +4,26 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class GuildMembersChunkHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const data = packet.d;
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
const members = [];
|
||||
|
||||
if (guild) {
|
||||
for (const member of data.members) {
|
||||
members.push(guild._addMember(member, true));
|
||||
}
|
||||
for (const member of data.members) members.push(guild._addMember(member, true));
|
||||
}
|
||||
|
||||
guild._checkChunks();
|
||||
client.emit(Constants.Events.GUILD_MEMBERS_CHUNK, guild, members);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a chunk of Guild members is received
|
||||
*
|
||||
* @event Client#guildMembersChunk
|
||||
* @param {Guild} guild The guild that the chunks relate to
|
||||
* @param {Array<GuildMember>} members The members in the chunk
|
||||
*/
|
||||
* Emitted whenever a chunk of Guild members is received
|
||||
* @event Client#guildMembersChunk
|
||||
* @param {Guild} guild The guild that the chunks relate to
|
||||
* @param {GuildMember[]} members The members in the chunk
|
||||
*/
|
||||
|
||||
module.exports = GuildMembersChunkHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildRoleCreateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildRoleCreate.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildRoleCreateHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildRoleDeleteHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildRoleDelete.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildRoleDeleteHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildRoleUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildRoleUpdate.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildRoleUpdateHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildSyncHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildSync.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildSyncHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class GuildUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.GuildUpdate.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GuildUpdateHandler;
|
||||
|
||||
@@ -2,25 +2,18 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class MessageCreateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const response = client.actions.MessageCreate.handle(data);
|
||||
|
||||
if (response.message) {
|
||||
client.emit(Constants.Events.MESSAGE_CREATE, response.message);
|
||||
}
|
||||
if (response.message) client.emit(Constants.Events.MESSAGE_CREATE, response.message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a message is created
|
||||
*
|
||||
* @event Client#message
|
||||
* @param {Message} message The created message
|
||||
*/
|
||||
* Emitted whenever a message is created
|
||||
* @event Client#message
|
||||
* @param {Message} message The created message
|
||||
*/
|
||||
|
||||
module.exports = MessageCreateHandler;
|
||||
|
||||
@@ -2,25 +2,18 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class MessageDeleteHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
const response = client.actions.MessageDelete.handle(data);
|
||||
|
||||
if (response.message) {
|
||||
client.emit(Constants.Events.MESSAGE_DELETE, response.message);
|
||||
}
|
||||
if (response.message) client.emit(Constants.Events.MESSAGE_DELETE, response.message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a message is deleted
|
||||
*
|
||||
* @event Client#messageDelete
|
||||
* @param {Message} message The deleted message
|
||||
*/
|
||||
* Emitted whenever a message is deleted
|
||||
* @event Client#messageDelete
|
||||
* @param {Message} message The deleted message
|
||||
*/
|
||||
|
||||
module.exports = MessageDeleteHandler;
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class MessageDeleteBulkHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.MessageDeleteBulk.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a messages are deleted in bulk
|
||||
*
|
||||
* @event Client#messageDeleteBulk
|
||||
* @param {Collection<string, Message>} messages The deleted messages, mapped by their ID
|
||||
*/
|
||||
* Emitted whenever messages are deleted in bulk
|
||||
* @event Client#messageDeleteBulk
|
||||
* @param {Collection<string, Message>} messages The deleted messages, mapped by their ID
|
||||
*/
|
||||
|
||||
module.exports = MessageDeleteBulkHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class MessageUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.MessageUpdate.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = MessageUpdateHandler;
|
||||
|
||||
@@ -3,21 +3,16 @@ const Constants = require('../../../../util/Constants');
|
||||
const cloneObject = require('../../../../util/CloneObject');
|
||||
|
||||
class PresenceUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const data = packet.d;
|
||||
let user = client.users.get(data.user.id);
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
|
||||
function makeUser(newUser) {
|
||||
return client.dataManager.newUser(newUser);
|
||||
}
|
||||
|
||||
// step 1
|
||||
if (!user) {
|
||||
if (data.user.username) {
|
||||
user = makeUser(data.user);
|
||||
user = client.dataManager.newUser(data.user);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -39,7 +34,6 @@ class PresenceUpdateHandler extends AbstractHandler {
|
||||
data.user.username = data.user.username || user.username;
|
||||
data.user.id = data.user.id || user.id;
|
||||
data.user.discriminator = data.user.discriminator || user.discriminator;
|
||||
|
||||
// comment out avatar patching as it causes bugs (see #297)
|
||||
// data.user.avatar = data.user.avatar || user.avatar;
|
||||
data.user.status = data.status || user.status;
|
||||
@@ -58,24 +52,20 @@ class PresenceUpdateHandler extends AbstractHandler {
|
||||
client.emit(Constants.Events.PRESENCE_UPDATE, oldUser, user);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a user changes one of their details or starts/stop playing a game
|
||||
*
|
||||
* @event Client#presenceUpdate
|
||||
* @param {User} oldUser the user before the presence update
|
||||
* @param {User} newUser the user after the presence update
|
||||
*/
|
||||
* Emitted whenever a user changes one of their details or starts/stop playing a game
|
||||
* @event Client#presenceUpdate
|
||||
* @param {User} oldUser The user before the presence update
|
||||
* @param {User} newUser The user after the presence update
|
||||
*/
|
||||
|
||||
/**
|
||||
* Emitted whenever a member becomes available in a large Guild
|
||||
*
|
||||
* @event Client#guildMemberAvailable
|
||||
* @param {Guild} guild The guild that the member became available in
|
||||
* @param {GuildMember} member the member that became available
|
||||
*/
|
||||
|
||||
* Emitted whenever a member becomes available in a large Guild
|
||||
* @event Client#guildMemberAvailable
|
||||
* @param {Guild} guild The guild that the member became available in
|
||||
* @param {GuildMember} member The member that became available
|
||||
*/
|
||||
|
||||
module.exports = PresenceUpdateHandler;
|
||||
|
||||
@@ -4,40 +4,28 @@ const getStructure = name => require(`../../../../structures/${name}`);
|
||||
const ClientUser = getStructure('ClientUser');
|
||||
|
||||
class ReadyHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const data = packet.d;
|
||||
|
||||
const clientUser = new ClientUser(client, data.user);
|
||||
client.user = clientUser;
|
||||
client.readyTime = Date.now();
|
||||
client.users.set(clientUser.id, clientUser);
|
||||
for (const guild of data.guilds) {
|
||||
client.dataManager.newGuild(guild);
|
||||
}
|
||||
|
||||
for (const privateDM of data.private_channels) {
|
||||
client.dataManager.newChannel(privateDM);
|
||||
}
|
||||
|
||||
if (!client.user.bot) {
|
||||
client.setInterval(client.syncGuilds.bind(client), 30000);
|
||||
}
|
||||
for (const guild of data.guilds) client.dataManager.newGuild(guild);
|
||||
for (const privateDM of data.private_channels) client.dataManager.newChannel(privateDM);
|
||||
|
||||
if (!client.user.bot) client.setInterval(client.syncGuilds.bind(client), 30000);
|
||||
client.once('ready', client.syncGuilds.bind(client));
|
||||
|
||||
client.setTimeout(() => {
|
||||
if (!client.ws.normalReady) {
|
||||
client.ws._emitReady(false);
|
||||
}
|
||||
if (!client.ws.normalReady) client.ws._emitReady(false);
|
||||
}, 1200 * data.guilds.length);
|
||||
|
||||
this.packetManager.ws.sessionID = data.session_id;
|
||||
|
||||
this.packetManager.ws.checkIfReady();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ReadyHandler;
|
||||
|
||||
@@ -1,28 +1,10 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
const Constants = require('../../../../util/Constants');
|
||||
|
||||
class TypingData {
|
||||
constructor(since, lastTimestamp, _timeout) {
|
||||
this.since = since;
|
||||
this.lastTimestamp = lastTimestamp;
|
||||
this._timeout = _timeout;
|
||||
}
|
||||
|
||||
resetTimeout(_timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = _timeout;
|
||||
}
|
||||
|
||||
get elapsedTime() {
|
||||
return Date.now() - this.since;
|
||||
}
|
||||
}
|
||||
|
||||
class TypingStartHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const data = packet.d;
|
||||
const channel = client.channels.get(data.channel_id);
|
||||
const user = client.users.get(data.user_id);
|
||||
const timestamp = new Date(data.timestamp * 1000);
|
||||
@@ -46,23 +28,37 @@ class TypingStartHandler extends AbstractHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TypingData {
|
||||
constructor(since, lastTimestamp, _timeout) {
|
||||
this.since = since;
|
||||
this.lastTimestamp = lastTimestamp;
|
||||
this._timeout = _timeout;
|
||||
}
|
||||
|
||||
resetTimeout(_timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = _timeout;
|
||||
}
|
||||
|
||||
get elapsedTime() {
|
||||
return Date.now() - this.since;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a user starts typing in a channel
|
||||
*
|
||||
* @event Client#typingStart
|
||||
* @param {Channel} channel the channel the user started typing in
|
||||
* @param {User} user the user that started typing
|
||||
*/
|
||||
* Emitted whenever a user starts typing in a channel
|
||||
* @event Client#typingStart
|
||||
* @param {Channel} channel The channel the user started typing in
|
||||
* @param {User} user The user that started typing
|
||||
*/
|
||||
|
||||
/**
|
||||
* Emitted whenever a user stops typing in a channel
|
||||
*
|
||||
* @event Client#typingStop
|
||||
* @param {Channel} channel the channel the user stopped typing in
|
||||
* @param {User} user the user that stopped typing
|
||||
*/
|
||||
* Emitted whenever a user stops typing in a channel
|
||||
* @event Client#typingStop
|
||||
* @param {Channel} channel The channel the user stopped typing in
|
||||
* @param {User} user The user that stopped typing
|
||||
*/
|
||||
|
||||
module.exports = TypingStartHandler;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
const AbstractHandler = require('./AbstractHandler');
|
||||
|
||||
class UserUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
client.actions.UserUpdate.handle(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = UserUpdateHandler;
|
||||
|
||||
@@ -9,16 +9,13 @@ const AbstractHandler = require('./AbstractHandler');
|
||||
*/
|
||||
|
||||
class VoiceServerUpdate extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
|
||||
const data = packet.d;
|
||||
if (client.voice.pending.has(data.guild_id)) {
|
||||
client.voice._receivedVoiceServer(data.guild_id, data.token, data.endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = VoiceServerUpdate;
|
||||
|
||||
@@ -4,12 +4,11 @@ const Constants = require('../../../../util/Constants');
|
||||
const cloneObject = require('../../../../util/CloneObject');
|
||||
|
||||
class VoiceStateUpdateHandler extends AbstractHandler {
|
||||
|
||||
handle(packet) {
|
||||
const data = packet.d;
|
||||
const client = this.packetManager.client;
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
const data = packet.d;
|
||||
|
||||
const guild = client.guilds.get(data.guild_id);
|
||||
if (guild) {
|
||||
const member = guild.members.get(data.user_id);
|
||||
if (member) {
|
||||
@@ -19,18 +18,14 @@ class VoiceStateUpdateHandler extends AbstractHandler {
|
||||
}
|
||||
|
||||
// if the member left the voice channel, unset their speaking property
|
||||
if (!data.channel_id) {
|
||||
member.speaking = null;
|
||||
}
|
||||
if (!data.channel_id) member.speaking = null;
|
||||
|
||||
if (client.voice.pending.has(guild.id) && member.user.id === client.user.id && data.channel_id) {
|
||||
client.voice._receivedVoiceStateUpdate(data.guild_id, data.session_id);
|
||||
}
|
||||
|
||||
const newChannel = client.channels.get(data.channel_id);
|
||||
if (newChannel) {
|
||||
newChannel.members.set(member.user.id, member);
|
||||
}
|
||||
if (newChannel) newChannel.members.set(member.user.id, member);
|
||||
|
||||
member.serverMute = data.mute;
|
||||
member.serverDeaf = data.deaf;
|
||||
@@ -42,15 +37,13 @@ class VoiceStateUpdateHandler extends AbstractHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitted whenever a user changes voice state - e.g. joins/leaves a channel, mutes/unmutes.
|
||||
*
|
||||
* @event Client#voiceStateUpdate
|
||||
* @param {GuildMember} oldMember the member before the voice state update
|
||||
* @param {GuildMember} newMember the member before the voice state update
|
||||
*/
|
||||
* Emitted whenever a user changes voice state - e.g. joins/leaves a channel, mutes/unmutes.
|
||||
* @event Client#voiceStateUpdate
|
||||
* @param {GuildMember} oldMember The member before the voice state update
|
||||
* @param {GuildMember} newMember The member after the voice state update
|
||||
*/
|
||||
|
||||
module.exports = VoiceStateUpdateHandler;
|
||||
|
||||
Reference in New Issue
Block a user