ESLint stuff...

This commit is contained in:
Amish Shah
2016-08-13 14:44:49 +01:00
parent 53d767ec04
commit b8db4c4f4b
74 changed files with 2574 additions and 2956 deletions

16
.eslintrc.js Normal file
View File

@@ -0,0 +1,16 @@
module.exports = {
"extends": "airbnb",
"plugins": [
"react",
"jsx-a11y",
"import"
],
"rules" : {
"max-len": [2, 120, 2],
"no-underscore-dangle": 0,
"global-require": 0,
"guard-for-in": 0,
"no-restricted-syntax": 0,
"no-param-reassign": 0,
}
};

View File

@@ -4,7 +4,7 @@
"description": "A way to interface with the Discord API", "description": "A way to interface with the Discord API",
"main": "./src/index", "main": "./src/index",
"scripts": { "scripts": {
"test": "jscs src && node test/random" "test": "node test/random"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -34,6 +34,11 @@
"devDependencies": { "devDependencies": {
"babel-preset-es2015": "^6.6.0", "babel-preset-es2015": "^6.6.0",
"babel-preset-stage-3": "^6.5.0", "babel-preset-stage-3": "^6.5.0",
"eslint": "^3.3.0",
"eslint-config-airbnb": "^10.0.1",
"eslint-plugin-import": "^1.13.0",
"eslint-plugin-jsx-a11y": "^2.1.0",
"eslint-plugin-react": "^6.0.0",
"grunt": "^0.4.5", "grunt": "^0.4.5",
"grunt-babel": "^6.0.0", "grunt-babel": "^6.0.0",
"grunt-browserify": "^4.0.1", "grunt-browserify": "^4.0.1",

View File

@@ -1,10 +1,8 @@
'use strict';
const EventEmitter = require('events').EventEmitter; const EventEmitter = require('events').EventEmitter;
const MergeDefault = require('../util/MergeDefault'); const mergeDefault = require('../util/MergeDefault');
const Constants = require('../util/Constants'); const Constants = require('../util/Constants');
const RESTManager = require('./rest/RestManager'); const RESTManager = require('./rest/RESTManager');
const ClientDataStore = require('../structures/DataStore/ClientDataStore'); const ClientDataStore = require('../structures/datastore/ClientDataStore');
const ClientManager = require('./ClientManager'); const ClientManager = require('./ClientManager');
const ClientDataResolver = require('./ClientDataResolver'); const ClientDataResolver = require('./ClientDataResolver');
const WebSocketManager = require('./websocket/WebSocketManager'); const WebSocketManager = require('./websocket/WebSocketManager');
@@ -17,47 +15,46 @@ const ActionsManager = require('./actions/ActionsManager');
* const client = new Discord.Client(); * const client = new Discord.Client();
* ``` * ```
*/ */
class Client extends EventEmitter{ class Client extends EventEmitter {
constructor(options) { constructor(options) {
super(); super();
this.options = MergeDefault(Constants.DefaultOptions, options); this.options = mergeDefault(Constants.DefaultOptions, options);
this.rest = new RESTManager(this); this.rest = new RESTManager(this);
this.store = new ClientDataStore(this); this.store = new ClientDataStore(this);
this.manager = new ClientManager(this); this.manager = new ClientManager(this);
this.ws = new WebSocketManager(this); this.ws = new WebSocketManager(this);
this.resolver = new ClientDataResolver(this); this.resolver = new ClientDataResolver(this);
this.actions = new ActionsManager(this); this.actions = new ActionsManager(this);
} }
/** /**
* Logs the client in. If successful, resolves with the account's token. * Logs the client in. If successful, resolves with the account's token.
* @param {string} emailOrToken The email or token used for the account. If it is an email, a password _must_ be * @param {string} emailOrToken The email or token used for the account. If it is an email, a password _must_ be
* provided. * provided.
* @param {string} [password] The password for the account, only needed if an email was provided. * @param {string} [password] The password for the account, only needed if an email was provided.
* @return {Promise<String>} * @return {Promise<String>}
* @example * @example
* client.login("token"); * client.login("token");
* // or * // or
* client.login("email", "password"); * client.login("email", "password");
*/ */
login(email, password) { login(email, password) {
if (password) { if (password) {
// login with email and password // login with email and password
return this.rest.methods.LoginEmailPassword(email, password); return this.rest.methods.loginEmailPassword(email, password);
} else { }
// login with token // login with token
return this.rest.methods.LoginToken(email); return this.rest.methods.loginToken(email);
} }
}
/** /**
* The User of the logged in Client, only available after `READY` has been fired. * The User of the logged in Client, only available after `READY` has been fired.
* @return {ClientUser} [description] * @return {ClientUser} [description]
*/ */
get user() { get user() {
return this.store.user; return this.store.user;
} }
} }

View File

@@ -1,90 +1,90 @@
'use strict'; const getStructure = name => require(`../structures/${name}`);
const Structure = name => require(`../structures/${name}`); const User = getStructure('User');
const Message = getStructure('Message');
const User = Structure('User'); const Guild = getStructure('Guild');
const Message = Structure('Message'); const Channel = getStructure('Channel');
const Guild = Structure('Guild'); const GuildMember = getStructure('GuildMember');
const Channel = Structure('Channel');
const ServerChannel = Structure('ServerChannel');
const TextChannel = Structure('TextChannel');
const VoiceChannel = Structure('VoiceChannel');
const GuildMember = Structure('GuildMember');
function $string(obj) { function $string(obj) {
return (typeof obj === 'string' || obj instanceof String); return (typeof obj === 'string' || obj instanceof String);
} }
class ClientDataResolver { class ClientDataResolver {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
} }
ResolveUser(user) { resolveUser(user) {
if (user instanceof User) { if (user instanceof User) {
return user; return user;
}else if ($string(user)) { } else if ($string(user)) {
return this.client.store.get('users', user); return this.client.store.get('users', user);
}else if (user instanceof Message) { } else if (user instanceof Message) {
return user.author; return user.author;
}else if (user instanceof Guild) { } else if (user instanceof Guild) {
return user.owner; return user.owner;
} }
return null; return null;
} }
ResolveGuild(guild) { resolveGuild(guild) {
if (guild instanceof Guild) { if (guild instanceof Guild) {
return guild; return guild;
} }
} return null;
}
ResolveGuildMember(guild, user) { resolveGuildMember($guild, $user) {
if (user instanceof GuildMember) { let guild = $guild;
return user; let user = $user;
} if (user instanceof GuildMember) {
return user;
}
guild = this.ResolveGuild(guild); guild = this.resolveGuild(guild);
user = this.ResolveUser(user); user = this.resolveUser(user);
if (!guild || !user) { if (!guild || !user) {
return null; return null;
} }
return guild.store.get('members', user.id); return guild.store.get('members', user.id);
} }
ResolveBase64(data) { resolveBase64(data) {
if (data instanceof Buffer) { if (data instanceof Buffer) {
return 'data:image/jpg;base64,' + data.toString('base64'); return `data:image/jpg;base64,${data.toString('base64')}`;
} }
return data; return data;
} }
ResolveChannel(channel) { resolveChannel(channel) {
if (channel instanceof Channel) { if (channel instanceof Channel) {
return channel; return channel;
} }
if ($string(channel)) { if ($string(channel)) {
return this.client.store.get('channels', channel); return this.client.store.get('channels', channel);
} }
}
ResolveString(data) { return null;
if (data instanceof String) { }
return data;
}
if (data instanceof Array) { resolveString(data) {
return data.join('\n'); if (data instanceof String) {
} return data;
}
return String(data); if (data instanceof Array) {
} return data.join('\n');
}
return String(data);
}
} }
module.exports = ClientDataResolver; module.exports = ClientDataResolver;

View File

@@ -1,34 +1,32 @@
'use strict';
const Constants = require('../util/Constants'); const Constants = require('../util/Constants');
class ClientManager { class ClientManager {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
this.heartbeatInterval = null; this.heartbeatInterval = null;
} }
connectToWebSocket(token, resolve, reject) { connectToWebSocket(token, resolve, reject) {
this.client.store.token = token; this.client.store.token = token;
this.client.rest.methods.GetGateway() this.client.rest.methods.getGateway()
.then(gateway => { .then(gateway => {
this.client.ws.connect(gateway); this.client.ws.connect(gateway);
this.client.once(Constants.Events.READY, () => resolve(token)); this.client.once(Constants.Events.READY, () => resolve(token));
}) })
.catch(reject); .catch(reject);
setTimeout(() => reject(Constants.Errors.TOOK_TOO_LONG), 1000 * 15); setTimeout(() => reject(Constants.Errors.TOOK_TOO_LONG), 1000 * 15);
} }
setupKeepAlive(time) { setupKeepAlive(time) {
this.heartbeatInterval = setInterval(() => { this.heartbeatInterval = setInterval(() => {
this.client.ws.send({ this.client.ws.send({
op: Constants.OPCodes.HEARTBEAT, op: Constants.OPCodes.HEARTBEAT,
d: Date.now(), d: Date.now(),
}); });
}, time); }, time);
} }
} }
module.exports = ClientManager; module.exports = ClientManager;

View File

@@ -1,5 +1,3 @@
'use strict';
/* /*
ABOUT ACTIONS ABOUT ACTIONS
@@ -14,14 +12,14 @@ that WebSocket events don't clash with REST methods.
class GenericAction { class GenericAction {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
} }
handle(data) { handle(data) {
return data;
}
} }
};
module.exports = GenericAction; module.exports = GenericAction;

View File

@@ -1,30 +1,28 @@
'use strict';
const requireAction = name => require(`./${name}`); const requireAction = name => require(`./${name}`);
class ActionsManager { class ActionsManager {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
this.register('MessageCreate'); this.register('MessageCreate');
this.register('MessageDelete'); this.register('MessageDelete');
this.register('MessageUpdate'); this.register('MessageUpdate');
this.register('ChannelCreate'); this.register('ChannelCreate');
this.register('ChannelDelete'); this.register('ChannelDelete');
this.register('ChannelUpdate'); this.register('ChannelUpdate');
this.register('GuildDelete'); this.register('GuildDelete');
this.register('GuildUpdate'); this.register('GuildUpdate');
this.register('GuildMemberRemove'); this.register('GuildMemberRemove');
this.register('GuildRoleCreate'); this.register('GuildRoleCreate');
this.register('GuildRoleDelete'); this.register('GuildRoleDelete');
this.register('GuildRoleUpdate'); this.register('GuildRoleUpdate');
this.register('UserUpdate'); this.register('UserUpdate');
} }
register(name) { register(name) {
let Action = requireAction(name); const Action = requireAction(name);
this[name] = new Action(this.client); this[name] = new Action(this.client);
} }
} }
module.exports = ActionsManager; module.exports = ActionsManager;

View File

@@ -1,23 +1,15 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants');
const Message = require('../../structures/Message');
class ChannelCreateAction extends Action { class ChannelCreateAction extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
} const channel = client.store.newChannel(data);
handle(data) { return {
let client = this.client; channel,
let channel = client.store.NewChannel(data); };
}
return { }
channel,
};
}
};
module.exports = ChannelCreateAction; module.exports = ChannelCreateAction;

View File

@@ -1,44 +1,36 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants');
const Message = require('../../structures/Message');
class ChannelDeleteAction extends Action { class ChannelDeleteAction extends Action {
constructor(client) { constructor(client) {
super(client); super(client);
this.timeouts = []; this.timeouts = [];
this.deleted = {}; this.deleted = {};
} }
handle(data) { handle(data) {
let client = this.client; const client = this.client;
let channel = client.store.get('channels', data.id); let channel = client.store.get('channels', data.id);
if (channel) { if (channel) {
client.store.killChannel(channel);
this.deleted[channel.id] = channel;
this.scheduleForDeletion(channel.id);
} else if (this.deleted[data.id]) {
channel = this.deleted[data.id];
}
client.store.KillChannel(channel); return {
this.deleted[channel.id] = channel; channel,
this.scheduleForDeletion(channel.id); };
}
} else if (this.deleted[data.id]) { scheduleForDeletion(id) {
this.timeouts.push(
channel = this.deleted[data.id]; setTimeout(() => delete this.deleted[id],
this.client.options.rest_ws_bridge_timeout)
} );
}
return { }
channel,
};
}
scheduleForDeletion(id) {
this.timeouts.push(
setTimeout(() => delete this.deleted[id],
this.client.options.rest_ws_bridge_timeout)
);
}
};
module.exports = ChannelDeleteAction; module.exports = ChannelDeleteAction;

View File

@@ -1,39 +1,31 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const CloneObject = require('../../util/CloneObject'); const cloneObject = require('../../util/CloneObject');
const Message = require('../../structures/Message');
class ChannelUpdateAction extends Action { class ChannelUpdateAction extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
} const channel = client.store.get('channels', data.id);
handle(data) { if (channel) {
const oldChannel = cloneObject(channel);
channel.setup(data);
if (!oldChannel.equals(data)) {
client.emit(Constants.Events.CHANNEL_UPDATE, oldChannel, channel);
}
let client = this.client; return {
let channel = client.store.get('channels', data.id); old: oldChannel,
updated: channel,
};
}
if (channel) { return {
let oldChannel = CloneObject(channel); old: null,
channel.setup(data); updated: null,
if (!oldChannel.equals(data)) { };
client.emit(Constants.Events.CHANNEL_UPDATE, oldChannel, channel); }
} }
return {
old: oldChannel,
updated: channel,
};
}
return {
old: null,
updated: null,
};
}
};
module.exports = ChannelUpdateAction; module.exports = ChannelUpdateAction;

View File

@@ -1,54 +1,49 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const Message = require('../../structures/Message');
class GuildDeleteAction extends Action { class GuildDeleteAction extends Action {
constructor(client) { constructor(client) {
super(client); super(client);
this.deleted = {}; this.deleted = {};
this.timeouts = []; this.timeouts = [];
} }
handle(data) { handle(data) {
const client = this.client;
let guild = client.store.get('guilds', data.id);
let client = this.client; if (guild) {
let guild = client.store.get('guilds', data.id); if (guild.available && data.unavailable) {
// guild is unavailable
guild.available = false;
client.emit(Constants.Events.GUILD_UNAVAILABLE, guild);
if (guild) { // stops the GuildDelete packet thinking a guild was actually deleted,
if (guild.available && data.unavailable) { // handles emitting of event itself
// guild is unavailable return {
guild.available = false; guild: null,
client.emit(Constants.Events.GUILD_UNAVAILABLE, guild); };
}
// delete guild
client.store.remove('guilds', guild);
this.deleted[guild.id] = guild;
this.scheduleForDeletion(guild.id);
} else if (this.deleted[data.id]) {
guild = this.deleted[data.id];
}
// stops the GuildDelete packet thinking a guild was actually deleted, return {
// handles emitting of event itself guild,
return { };
guild: null, }
};
} else {
// delete guild
client.store.remove('guilds', guild);
this.deleted[guild.id] = guild;
this.scheduleForDeletion(guild.id);
}
} else if (this.deleted[data.id]) {
guild = this.deleted[data.id];
}
return { scheduleForDeletion(id) {
guild, this.timeouts.push(
}; setTimeout(() => delete this.deleted[id],
} this.client.options.rest_ws_bridge_timeout)
);
scheduleForDeletion(id) { }
this.timeouts.push( }
setTimeout(() => delete this.deleted[id],
this.client.options.rest_ws_bridge_timeout)
);
}
};
module.exports = GuildDeleteAction; module.exports = GuildDeleteAction;

View File

@@ -1,51 +1,48 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const Message = require('../../structures/Message');
class GuildMemberRemoveAction extends Action { class GuildMemberRemoveAction extends Action {
constructor(client) { constructor(client) {
super(client); super(client);
this.timeouts = []; this.timeouts = [];
this.deleted = {}; this.deleted = {};
} }
handle(data) { handle(data) {
let client = this.client; const client = this.client;
let guild = client.store.get('guilds', data.guild_id); const guild = client.store.get('guilds', data.guild_id);
if (guild) { if (guild) {
let member = guild.store.get('members', data.user.id); let member = guild.store.get('members', data.user.id);
if (member) { if (member) {
guild._removeMember(member); guild._removeMember(member);
this.deleted[guild.id + data.user.id] = member; this.deleted[guild.id + data.user.id] = member;
client.emit(Constants.Events.GUILD_MEMBER_REMOVE, guild, member); client.emit(Constants.Events.GUILD_MEMBER_REMOVE, guild, member);
this.scheduleForDeletion(guild.id, data.user.id); this.scheduleForDeletion(guild.id, data.user.id);
} }
if (!member) { if (!member) {
member = this.deleted[guild.id + data.user.id]; member = this.deleted[guild.id + data.user.id];
} }
return { return {
g: guild, g: guild,
m: member, m: member,
}; };
} }
return { return {
g: guild, g: guild,
m: null, m: null,
}; };
} }
scheduleForDeletion(guildID, userID) { scheduleForDeletion(guildID, userID) {
this.timeouts.push( this.timeouts.push(
setTimeout(() => delete this.deleted[guildID + userID], setTimeout(() => delete this.deleted[guildID + userID],
this.client.options.rest_ws_bridge_timeout) this.client.options.rest_ws_bridge_timeout)
); );
} }
}; }
module.exports = GuildMemberRemoveAction; module.exports = GuildMemberRemoveAction;

View File

@@ -1,38 +1,31 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const Role = require('../../structures/Role'); const Role = require('../../structures/Role');
class GuildRoleCreate extends Action { class GuildRoleCreate extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
} const guild = client.store.get('guilds', data.guild_id);
handle(data) { if (guild) {
const already = guild.store.get('roles', data.role.id);
const role = new Role(guild, data.role);
guild.store.add('roles', role);
let client = this.client; if (!already) {
let guild = client.store.get('guilds', data.guild_id); client.emit(Constants.Events.GUILD_ROLE_CREATE, guild, role);
}
if (guild) { return {
let already = guild.store.get('roles', data.role.id); role,
let role = new Role(guild, data.role); };
guild.store.add('roles', role); }
if (!already) { return {
client.emit(Constants.Events.GUILD_ROLE_CREATE, guild, role); role: null,
} };
}
return { }
role,
};
}
return {
role: null,
};
}
};
module.exports = GuildRoleCreate; module.exports = GuildRoleCreate;

View File

@@ -1,50 +1,47 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const Message = require('../../structures/Message');
class GuildRoleDeleteAction extends Action { class GuildRoleDeleteAction extends Action {
constructor(client) { constructor(client) {
super(client); super(client);
this.timeouts = []; this.timeouts = [];
this.deleted = {}; this.deleted = {};
} }
handle(data) { handle(data) {
let client = this.client; const client = this.client;
let guild = client.store.get('guilds', data.guild_id); const guild = client.store.get('guilds', data.guild_id);
if (guild) { if (guild) {
let exists = guild.store.get('roles', data.role_id); let exists = guild.store.get('roles', data.role_id);
if (exists) { if (exists) {
guild.store.remove('roles', data.role_id); guild.store.remove('roles', data.role_id);
this.deleted[guild.id + data.role_id] = exists; this.deleted[guild.id + data.role_id] = exists;
this.scheduleForDeletion(guild.id, data.role_id); this.scheduleForDeletion(guild.id, data.role_id);
client.emit(Constants.Events.GUILD_ROLE_DELETE, guild, exists); client.emit(Constants.Events.GUILD_ROLE_DELETE, guild, exists);
} }
if (!exists) { if (!exists) {
exists = this.deleted[guild.id + data.role_id]; exists = this.deleted[guild.id + data.role_id];
} }
return { return {
role: exists, role: exists,
}; };
} }
return { return {
role: null, role: null,
}; };
} }
scheduleForDeletion(guildID, roleID) { scheduleForDeletion(guildID, roleID) {
this.timeouts.push( this.timeouts.push(
setTimeout(() => delete this.deleted[guildID + roleID], setTimeout(() => delete this.deleted[guildID + roleID],
this.client.options.rest_ws_bridge_timeout) this.client.options.rest_ws_bridge_timeout)
); );
} }
}; }
module.exports = GuildRoleDeleteAction; module.exports = GuildRoleDeleteAction;

View File

@@ -1,44 +1,36 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const CloneObject = require('../../util/CloneObject'); const cloneObject = require('../../util/CloneObject');
const Message = require('../../structures/Message');
class GuildRoleUpdateAction extends Action { class GuildRoleUpdateAction extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
} const guild = client.store.get('guilds', data.guild_id);
handle(data) { const roleData = data.role;
let client = this.client; if (guild) {
let guild = client.store.get('guilds', data.guild_id); let oldRole;
const existingRole = guild.store.get('roles', roleData.id);
// exists and not the same
if (existingRole && !existingRole.equals(roleData)) {
oldRole = cloneObject(existingRole);
existingRole.setup(data.role);
client.emit(Constants.Events.GUILD_ROLE_UPDATE, guild, oldRole, existingRole);
}
let roleData = data.role; return {
old: oldRole,
updated: existingRole,
};
}
if (guild) { return {
let oldRole; old: null,
let existingRole = guild.store.get('roles', roleData.id); updated: null,
// exists and not the same };
if (existingRole && !existingRole.equals(roleData)) { }
oldRole = CloneObject(existingRole); }
existingRole.setup(data.role);
client.emit(Constants.Events.GUILD_ROLE_UPDATE, guild, oldRole, existingRole);
}
return {
old: oldRole,
updated: existingRole,
};
}
return {
old: null,
updated: null,
};
}
};
module.exports = GuildRoleUpdateAction; module.exports = GuildRoleUpdateAction;

View File

@@ -1,42 +1,38 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const CloneObject = require('../../util/CloneObject'); const cloneObject = require('../../util/CloneObject');
const Message = require('../../structures/Message');
class GuildUpdateAction extends Action { class GuildUpdateAction extends Action {
constructor(client) { constructor(client) {
super(client); super(client);
this.deleted = {}; this.deleted = {};
this.timeouts = []; this.timeouts = [];
} }
handle(data) { handle(data) {
const client = this.client;
const guild = client.store.get('guilds', data.id);
let client = this.client; if (guild) {
let guild = client.store.get('guilds', data.id); const oldGuild = cloneObject(guild);
guild.setup(data);
if (guild) { if (!oldGuild.equals(data)) {
let oldGuild = CloneObject(guild); client.emit(Constants.Events.GUILD_UPDATE, oldGuild, guild);
guild.setup(data); }
if (!oldGuild.equals(data)) { return {
client.emit(Constants.Events.GUILD_UPDATE, oldGuild, guild); old: oldGuild,
} updated: guild,
};
}
return { return {
old: oldGuild, old: null,
updated: guild, updated: null,
}; };
} }
}
return {
old: null,
updated: null,
};
}
};
module.exports = GuildUpdateAction; module.exports = GuildUpdateAction;

View File

@@ -1,31 +1,23 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants');
const Message = require('../../structures/Message'); const Message = require('../../structures/Message');
class MessageCreateAction extends Action { class MessageCreateAction extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
} const channel = client.store.get('channels', data.channel_id);
handle(data) { if (channel) {
const message = channel._cacheMessage(new Message(channel, data, client));
return {
m: message,
};
}
let client = this.client; return {
let channel = client.store.get('channels', data.channel_id); m: null,
};
if (channel) { }
let message = channel._cacheMessage(new Message(channel, data, client)); }
return {
m: message,
};
}
return {
m: null,
};
}
};
module.exports = MessageCreateAction; module.exports = MessageCreateAction;

View File

@@ -1,51 +1,43 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants');
const Message = require('../../structures/Message');
class MessageDeleteAction extends Action { class MessageDeleteAction extends Action {
constructor(client) { constructor(client) {
super(client); super(client);
this.timeouts = []; this.timeouts = [];
this.deleted = {}; this.deleted = {};
} }
handle(data) { handle(data) {
let client = this.client; const client = this.client;
let channel = client.store.get('channels', data.channel_id); const channel = client.store.get('channels', data.channel_id);
if (channel) { if (channel) {
let message = channel.store.get('messages', data.id); let message = channel.store.get('messages', data.id);
if (message) { if (message) {
channel.store.remove('messages', message.id);
this.deleted[channel.id + message.id] = message;
this.scheduleForDeletion(channel.id, message.id);
} else if (this.deleted[channel.id + data.id]) {
message = this.deleted[channel.id + data.id];
}
channel.store.remove('messages', message.id); return {
this.deleted[channel.id + message.id] = message; m: message,
this.scheduleForDeletion(channel.id, message.id); };
}
} else if (this.deleted[channel.id + data.id]) { return {
m: null,
};
}
message = this.deleted[channel.id + data.id]; scheduleForDeletion(channelID, messageID) {
this.timeouts.push(
} setTimeout(() => delete this.deleted[channelID + messageID],
this.client.options.rest_ws_bridge_timeout)
return { );
m: message, }
}; }
}
return {
m: null,
};
}
scheduleForDeletion(channelID, messageID) {
this.timeouts.push(
setTimeout(() => delete this.deleted[channelID + messageID],
this.client.options.rest_ws_bridge_timeout)
);
}
};
module.exports = MessageDeleteAction; module.exports = MessageDeleteAction;

View File

@@ -1,44 +1,36 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const CloneObject = require('../../util/CloneObject'); const cloneObject = require('../../util/CloneObject');
const Message = require('../../structures/Message');
class MessageUpdateAction extends Action { class MessageUpdateAction extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
} const channel = client.store.get('channels', data.channel_id);
handle(data) { if (channel) {
const message = channel.store.get('messages', data.id);
if (message && !message.equals(data, true)) {
const oldMessage = cloneObject(message);
message.patch(data);
client.emit(Constants.Events.MESSAGE_UPDATE, oldMessage, message);
return {
old: oldMessage,
updated: message,
};
}
let client = this.client; return {
let channel = client.store.get('channels', data.channel_id); old: message,
updated: message,
};
}
if (channel) { return {
let message = channel.store.get('messages', data.id); old: null,
if (message && !message.equals(data, true)) { updated: null,
let oldMessage = CloneObject(message); };
message.patch(data); }
return { }
old: oldMessage,
updated: message,
};
client.emit(Constants.Events.MESSAGE_UPDATE, oldMessage, message);
}
return {
old: message,
updated: message,
};
}
return {
old: null,
updated: null,
};
}
};
module.exports = MessageUpdateAction; module.exports = MessageUpdateAction;

View File

@@ -1,44 +1,36 @@
'use strict';
const Action = require('./Action'); const Action = require('./Action');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const CloneObject = require('../../util/CloneObject'); const cloneObject = require('../../util/CloneObject');
const Message = require('../../structures/Message');
class UserUpdateAction extends Action { class UserUpdateAction extends Action {
constructor(client) { handle(data) {
super(client); const client = this.client;
}
handle(data) { if (client.store.user) {
if (client.store.user.equals(data)) {
return {
old: client.store.user,
updated: client.store.user,
};
}
let client = this.client; const oldUser = cloneObject(client.store.user);
client.store.user.setup(data);
if (client.store.user) { client.emit(Constants.Events.USER_UPDATE, oldUser, client.store.user);
if (client.store.user.equals(data)) {
return {
old: client.store.user,
updated: client.store.user,
};
}
let oldUser = CloneObject(client.store.user); return {
client.store.user.setup(data); old: oldUser,
updated: client.store.user,
};
}
client.emit(Constants.Events.USER_UPDATE, oldUser, client.store.user); return {
old: null,
return { updated: null,
old: oldUser, };
updated: client.store.user, }
}; }
}
return {
old: null,
updated: null,
};
}
};
module.exports = UserUpdateAction; module.exports = UserUpdateAction;

View File

@@ -1,105 +1,110 @@
'use strict';
const request = require('superagent'); const request = require('superagent');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const UserAgentManager = require('./UserAgentManager'); const UserAgentManager = require('./UserAgentManager');
const RESTMethods = require('./RESTMethods'); const RESTMethods = require('./RESTMethods');
class RESTManager{ class RESTManager {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
this.queue = []; this.queue = [];
this.userAgentManager = new UserAgentManager(this); this.userAgentManager = new UserAgentManager(this);
this.methods = new RESTMethods(this); this.methods = new RESTMethods(this);
this.rateLimitedEndpoints = {}; this.rateLimitedEndpoints = {};
} }
addRequestToQueue(method, url, auth, data, file, resolve, reject) { addRequestToQueue(method, url, auth, data, file, resolve, reject) {
let endpoint = url.replace(/\/[0-9]+/g, '/:id'); const endpoint = url.replace(/\/[0-9]+/g, '/:id');
let rateLimitedEndpoint = this.rateLimitedEndpoints[endpoint]; const rateLimitedEndpoint = this.rateLimitedEndpoints[endpoint];
rateLimitedEndpoint.queue = rateLimitedEndpoint.queue || []; rateLimitedEndpoint.queue = rateLimitedEndpoint.queue || [];
rateLimitedEndpoint.queue.push({ rateLimitedEndpoint.queue.push({
method, url, auth, data, file, resolve, reject, method,
}); url,
} auth,
data,
file,
resolve,
reject,
});
}
processQueue(endpoint) { processQueue(endpoint) {
let rateLimitedEndpoint = this.rateLimitedEndpoints[endpoint]; const rateLimitedEndpoint = this.rateLimitedEndpoints[endpoint];
// prevent multiple queue processes // prevent multiple queue processes
if (!rateLimitedEndpoint.timeout) { if (!rateLimitedEndpoint.timeout) {
return; return;
} }
// lock the queue // lock the queue
clearTimeout(rateLimitedEndpoint.timeout); clearTimeout(rateLimitedEndpoint.timeout);
rateLimitedEndpoint.timeout = null; rateLimitedEndpoint.timeout = null;
for (let item of rateLimitedEndpoint.queue) { for (const item of rateLimitedEndpoint.queue) {
this.makeRequest(item.method, item.url, item.auth, item.data, item.file) this.makeRequest(item.method, item.url, item.auth, item.data, item.file)
.then(item.resolve) .then(item.resolve)
.catch(item.reject); .catch(item.reject);
} }
rateLimitedEndpoint.queue = []; rateLimitedEndpoint.queue = [];
} }
makeRequest(method, url, auth, data, file, fromQueue) { makeRequest(method, url, auth, data, file) {
/* /*
file is {file, name} file is {file, name}
*/ */
let apiRequest = request[method](url); console.log(url);
const apiRequest = request[method](url);
let endpoint = url.replace(/\/[0-9]+/g, '/:id'); const endpoint = url.replace(/\/[0-9]+/g, '/:id');
if (this.rateLimitedEndpoints[endpoint] && this.rateLimitedEndpoints[endpoint].timeout) { if (this.rateLimitedEndpoints[endpoint] && this.rateLimitedEndpoints[endpoint].timeout) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.addRequestToQueue(method, url, auth, data, file, resolve, reject); this.addRequestToQueue(method, url, auth, data, file, resolve, reject);
}); });
} }
if (auth) { if (auth) {
if (this.client.store.token) { if (this.client.store.token) {
apiRequest.set('authorization', this.client.store.token); apiRequest.set('authorization', this.client.store.token);
} else { } else {
throw Constants.Errors.NO_TOKEN; throw Constants.Errors.NO_TOKEN;
} }
} }
if (data) { if (data) {
apiRequest.send(data); apiRequest.send(data);
} }
if (file) { if (file) {
apiRequest.attach('file', file.file, file.name); apiRequest.attach('file', file.file, file.name);
} }
apiRequest.set('User-Agent', this.userAgentManager.userAgent); apiRequest.set('User-Agent', this.userAgentManager.userAgent);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
apiRequest.end((err, res) => { apiRequest.end((err, res) => {
if (err) { if (err) {
let retry = res.headers['retry-after'] || res.headers['Retry-After']; const retry = res.headers['retry-after'] || res.headers['Retry-After'];
if (retry) { if (retry) {
this.rateLimitedEndpoints[endpoint] = {}; this.rateLimitedEndpoints[endpoint] = {};
this.addRequestToQueue(method, url, auth, data, file, resolve, reject); this.addRequestToQueue(method, url, auth, data, file, resolve, reject);
this.rateLimitedEndpoints[endpoint].timeout = setTimeout(() => { this.rateLimitedEndpoints[endpoint].timeout = setTimeout(() => {
this.processQueue(endpoint); this.processQueue(endpoint);
}, retry); }, retry);
return; return;
} }
reject(err); reject(err);
} else { } else {
resolve(res ? res.body || {} : {}); resolve(res ? res.body || {} : {});
} }
}); });
}); });
} }
}; }
module.exports = RESTManager; module.exports = RESTManager;

View File

@@ -1,329 +1,328 @@
'use strict';
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const Structure = name => require('../../structures/' + name);
const User = Structure('User');
const GuildMember = Structure('GuildMember');
const Message = Structure('Message');
class RESTMethods{ const getStructure = name => require(`../../structures/${name}`);
constructor(restManager) { const User = getStructure('User');
this.rest = restManager; const GuildMember = getStructure('GuildMember');
}
LoginEmailPassword(email, password) { class RESTMethods {
return new Promise((resolve, reject) => { constructor(restManager) {
this.rest.client.store.email = email; this.rest = restManager;
this.rest.client.store.password = password; }
this.rest.makeRequest('post', Constants.Endpoints.LOGIN, false, { email, password })
.then(data => {
this.rest.client.manager.connectToWebSocket(data.token, resolve, reject);
})
.catch(reject);
}); loginEmailPassword(email, password) {
} return new Promise((resolve, reject) => {
this.rest.client.store.email = email;
this.rest.client.store.password = password;
this.rest.makeRequest('post', Constants.Endpoints.login, false, { email, password })
.then(data => {
this.rest.client.manager.connectToWebSocket(data.token, resolve, reject);
})
.catch(reject);
});
}
LoginToken(token) { loginToken(token) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.client.manager.connectToWebSocket(token, resolve, reject); this.rest.client.manager.connectToWebSocket(token, resolve, reject);
}); });
} }
GetGateway() { getGateway() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('get', Constants.Endpoints.GATEWAY, true) this.rest.makeRequest('get', Constants.Endpoints.gateway, true)
.then(res => resolve(res.url)) .then(res => resolve(res.url))
.catch(reject); .catch(reject);
}); });
} }
SendMessage(channel, content, tts, nonce) { sendMessage($channel, content, tts, nonce) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const $this = this;
let channel = $channel;
var _this = this; function req() {
$this.rest.makeRequest('post', Constants.Endpoints.channelMessages(channel.id), true, {
content, tts, nonce,
})
.then(data => resolve($this.rest.client.actions.MessageCreate.handle(data).m))
.catch(reject);
}
if (channel instanceof User || channel instanceof GuildMember) { if (channel instanceof User || channel instanceof GuildMember) {
this.CreateDM(channel).then(chan => { this.createDM(channel).then(chan => {
channel = chan; channel = chan;
req(); req();
}) })
.catch(reject); .catch(reject);
} else { } else {
req(); req();
} }
});
}
function req() { deleteMessage(message) {
_this.rest.makeRequest('post', Constants.Endpoints.CHANNEL_MESSAGES(channel.id), true, { return new Promise((resolve, reject) => {
content, tts, nonce, this.rest.makeRequest('del', Constants.Endpoints.channelMessage(message.channel.id, message.id), true)
}) .then(() => {
.then(data => resolve(_this.rest.client.actions.MessageCreate.handle(data).m)) resolve(this.rest.client.actions.MessageDelete.handle({
.catch(reject); id: message.id,
} channel_id: message.channel.id,
}); }).m);
} })
.catch(reject);
});
}
DeleteMessage(message) { updateMessage(message, content) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('del', Constants.Endpoints.CHANNEL_MESSAGE(message.channel.id, message.id), true) this.rest.makeRequest('patch', Constants.Endpoints.channelMessage(message.channel.id, message.id), true, {
.then(data => { content,
resolve(this.rest.client.actions.MessageDelete.handle({ })
id: message.id, .then(data => {
channel_id: message.channel.id, resolve(this.rest.client.actions.MessageUpdate.handle(data).updated);
}).m); })
}) .catch(reject);
.catch(reject); });
}); }
}
UpdateMessage(message, content) { createChannel(guild, channelName, channelType) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('patch', Constants.Endpoints.CHANNEL_MESSAGE(message.channel.id, message.id), true, { this.rest.makeRequest('post', Constants.Endpoints.guildChannels(guild.id), true, {
content, name: channelName,
}) type: channelType,
.then(data => { })
resolve(this.rest.client.actions.MessageUpdate.handle(data).updated); .then(data => {
}) resolve(this.rest.client.actions.ChannelCreate.handle(data).channel);
.catch(reject); })
}); .catch(reject);
} });
}
CreateChannel(guild, channelName, channelType) { getExistingDM(recipient) {
return new Promise((resolve, reject) => { const dmChannel = this.rest.client.store.getAsArray('channels')
this.rest.makeRequest('post', Constants.Endpoints.GUILD_CHANNELS(guild.id), true, { .filter(channel => channel.recipient)
name: channelName, .filter(channel => channel.recipient.id === recipient.id);
type: channelType,
})
.then(data => {
resolve(this.rest.client.actions.ChannelCreate.handle(data).channel);
})
.catch(reject);
});
}
GetExistingDM(recipient) { return dmChannel[0];
let dmChannel = this.rest.client.store.getAsArray('channels') }
.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);
CreateDM(recipient) { if (dmChannel) {
return new Promise((resolve, reject) => { return resolve(dmChannel);
}
let dmChannel = this.GetExistingDM(recipient); return this.rest.makeRequest('post', Constants.Endpoints.userChannels(this.rest.client.store.user.id), true, {
recipient_id: recipient.id,
})
.then(data => resolve(this.rest.client.actions.ChannelCreate.handle(data).channel))
.catch(reject);
});
}
if (dmChannel) { deleteChannel($channel) {
return resolve(dmChannel); let channel = $channel;
} return new Promise((resolve, reject) => {
if (channel instanceof User || channel instanceof GuildMember) {
channel = this.getExistingDM(channel);
}
this.rest.makeRequest('post', Constants.Endpoints.USER_CHANNELS(this.rest.client.store.user.id), true, { this.rest.makeRequest('del', Constants.Endpoints.channel(channel.id), true)
recipient_id: recipient.id, .then($data => {
}) const data = $data;
.then(data => resolve(this.rest.client.actions.ChannelCreate.handle(data).channel)) data.id = channel.id;
.catch(reject); resolve(this.rest.client.actions.ChannelDelete.handle(data).channel);
}); })
} .catch(reject);
});
}
DeleteChannel(channel) { updateChannel(channel, $data) {
return new Promise((resolve, reject) => { const data = $data;
if (channel instanceof User || channel instanceof GuildMember) { return new Promise((resolve, reject) => {
channel = this.GetExistingDM(channel); 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('del', Constants.Endpoints.CHANNEL(channel.id), true) this.rest.makeRequest('patch', Constants.Endpoints.channel(channel.id), true, data)
.then(data => { .then(newData => {
data.id = channel.id; resolve(this.rest.client.actions.ChannelUpdate.handle(newData).updated);
resolve(this.rest.client.actions.ChannelDelete.handle(data).channel); })
}) .catch(reject);
.catch(reject); });
}); }
}
UpdateChannel(channel, data) { leaveGuild(guild) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
data.name = (data.name || channel.name).trim(); this.rest.makeRequest('del', Constants.Endpoints.meGuild(guild.id), true)
data.topic = data.topic || channel.topic; .then(() => {
data.position = data.position || channel.position; resolve(this.rest.client.actions.GuildDelete.handle({ id: guild.id }).guild);
data.bitrate = data.bitrate || channel.bitrate; })
.catch(reject);
});
}
this.rest.makeRequest('patch', Constants.Endpoints.CHANNEL(channel.id), true, data) // untested but probably will work
.then(data => { deleteGuild(guild) {
resolve(this.rest.client.actions.ChannelUpdate.handle(data).updated); return new Promise((resolve, reject) => {
}) this.rest.makeRequest('del', Constants.Endpoints.guild(guild.id), true)
.catch(reject); .then(() => {
}); resolve(this.rest.client.actions.GuildDelete.handle({ id: guild.id }).guild);
} })
.catch(reject);
});
}
LeaveGuild(guild) { updateCurrentUser(_data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('del', Constants.Endpoints.ME_GUILD(guild.id), true) const user = this.rest.client.store.user;
.then(() => { const data = {};
resolve(this.rest.client.actions.GuildDelete.handle({ id:guild.id }).guild);
})
.catch(reject);
});
}
// untested but probably will work data.username = _data.username || user.username;
DeleteGuild(guild) { data.avatar = this.rest.client.resolver.resolveBase64(_data.avatar) || user.avatar;
return new Promise((resolve, reject) => { if (!user.bot) {
this.rest.makeRequest('del', Constants.Endpoints.GUILD(guild.id), true) data.password = this.rest.client.store.password;
.then(() => { data.email = _data.email || this.rest.client.store.email;
resolve(this.rest.client.actions.GuildDelete.handle({ id:guild.id }).guild); data.new_password = _data.newPassword;
}) }
.catch(reject);
});
}
UpdateCurrentUser(_data) { this.rest.makeRequest('patch', Constants.Endpoints.me, true, data)
return new Promise((resolve, reject) => { .then(newData => resolve(this.rest.client.actions.UserUpdate.handle(newData).updated))
let user = this.rest.client.store.user; .catch(reject);
let data = {}; });
}
data.username = _data.username || user.username; updateGuild(guild, _data) {
data.avatar = this.rest.client.resolver.ResolveBase64(_data.avatar) || user.avatar; return new Promise((resolve, reject) => {
if (!user.bot) { /*
data.password = this.rest.client.store.password; can contain:
data.email = _data.email || this.rest.client.store.email; name, region, verificationLevel, afkChannel, afkTimeout, icon, owner, splash
data.new_password = _data.newPassword; */
}
this.rest.makeRequest('patch', Constants.Endpoints.ME, true, data) const data = {};
.then(data => resolve(this.rest.client.actions.UserUpdate.handle(data).updated))
.catch(reject);
});
}
UpdateGuild(guild, _data) { if (_data.name) {
return new Promise((resolve, reject) => { data.name = _data.name;
/* }
can contain:
name, region, verificationLevel, afkChannel, afkTimeout, icon, owner, splash
*/
let data = {}; if (_data.region) {
data.region = _data.region;
}
if (_data.name) { if (_data.verificationLevel) {
data.name = _data.name; data.verification_level = Number(_data.verificationLevel);
} }
if (_data.region) { if (_data.afkChannel) {
data.region = _data.region; data.afk_channel_id = this.rest.client.resolver.resolveChannel(_data.afkChannel).id;
} }
if (_data.verificationLevel) { if (_data.afkTimeout) {
data.verification_level = Number(_data.verificationLevel); data.afk_timeout = Number(_data.afkTimeout);
} }
if (_data.afkChannel) { if (_data.icon) {
data.afk_channel_id = this.rest.client.resolver.ResolveChannel(_data.afkChannel).id; data.icon = this.rest.client.resolver.resolveBase64(_data.icon);
} }
if (_data.afkTimeout) { if (_data.owner) {
data.afk_timeout = Number(_data.afkTimeout); data.owner_id = this.rest.client.resolver.resolveUser(_data.owner).id;
} }
if (_data.icon) { if (_data.splash) {
data.icon = this.rest.client.resolver.ResolveBase64(_data.icon); data.splash = this.rest.client.resolver.resolveBase64(_data.splash);
} }
if (_data.owner) { this.rest.makeRequest('patch', Constants.Endpoints.guild(guild.id), true, data)
data.owner_id = this.rest.client.resolver.ResolveUser(_data.owner).id; .then(newData => resolve(this.rest.client.actions.GuildUpdate.handle(newData).updated))
} .catch(reject);
});
}
if (_data.splash) { kickGuildMember(guild, member) {
data.splash = this.rest.client.resolver.ResolveBase64(_data.splash); 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,
}).m);
})
.catch(reject);
});
}
this.rest.makeRequest('patch', Constants.Endpoints.GUILD(guild.id), true, data) createGuildRole(guild) {
.then(data => resolve(this.rest.client.actions.GuildUpdate.handle(data).updated)) return new Promise((resolve, reject) => {
.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);
});
}
KickGuildMember(guild, member) { deleteGuildRole(role) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('del', Constants.Endpoints.GUILD_MEMBER(guild.id, member.id), true) this.rest.makeRequest('del', Constants.Endpoints.guildRole(role.guild.id, role.id), true)
.then(() => { .then(() => {
resolve(this.rest.client.actions.GuildMemberRemove.handle({ resolve(this.rest.client.actions.GuildRoleDelete.handle({
guild_id: guild.id, guild_id: role.guild.id,
user: member.user, role_id: role.id,
}).m); }).role);
}) })
.catch(reject); .catch(reject);
}); });
} }
CreateGuildRole(guild) { updateGuildRole(role, _data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.rest.makeRequest('post', Constants.Endpoints.GUILD_ROLES(guild.id), true) /*
.then(role => { can contain:
resolve(this.rest.client.actions.GuildRoleCreate.handle({ name, position, permissions, color, hoist
guild_id: guild.id, */
role,
}).role);
})
.catch(reject);
});
}
DeleteGuildRole(role) { const data = {};
return new Promise((resolve, reject) => {
this.rest.makeRequest('del', Constants.Endpoints.GUILD_ROLE(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);
});
}
UpdateGuildRole(role, _data) { data.name = _data.name || role.name;
return new Promise((resolve, reject) => { data.position = _data.position || role.position;
/* data.color = _data.color || role.color;
can contain:
name, position, permissions, color, hoist
*/
let data = {}; if (typeof _data.hoist !== 'undefined') {
data.hoist = _data.hoist;
} else {
data.hoist = role.hoist;
}
data.name = _data.name || role.name; if (_data.permissions) {
data.position = _data.position || role.position; let perms = 0;
data.color = _data.color || role.color; for (let perm of _data.permissions) {
if (perm instanceof String || typeof perm === 'string') {
perm = Constants.PermissionFlags[perm];
}
perms |= perm;
}
data.permissions = perms;
} else {
data.permissions = role.permissions;
}
if (typeof _data.hoist !== 'undefined') { this.rest.makeRequest('patch', Constants.Endpoints.guildRole(role.guild.id, role.id), true, data)
data.hoist = _data.hoist; .then(_role => {
} else { resolve(this.rest.client.actions.GuildRoleUpdate.handle({
data.hoist = role.hoist; role: _role,
} guild_id: role.guild.id,
}).updated);
if (_data.permissions) { })
let perms = 0; .catch(reject);
for (let perm of _data.permissions) { });
if (perm instanceof String || typeof perm === 'string') { }
perm = Constants.PermissionFlags[perm];
}
perms |= perm;
}
data.permissions = perms;
} else {
data.permissions = role.permissions;
}
console.log(data);
this.rest.makeRequest('patch', Constants.Endpoints.GUILD_ROLE(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);
});
}
} }
module.exports = RESTMethods; module.exports = RESTMethods;

View File

@@ -1,24 +1,22 @@
'use strict';
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
class UserAgentManager{ class UserAgentManager {
constructor(restManager) { constructor(restManager) {
this.restManager = restManager; this.restManager = restManager;
this._userAgent = { this._userAgent = {
url: 'https://github.com/hydrabolt/discord.js', url: 'https://github.com/hydrabolt/discord.js',
version: Constants.Package.version, version: Constants.Package.version,
}; };
} }
set(info) { set(info) {
this._userAgent.url = info.url || 'https://github.com/hydrabolt/discord.js'; this._userAgent.url = info.url || 'https://github.com/hydrabolt/discord.js';
this._userAgent.version = info.version || Constants.Package.version; this._userAgent.version = info.version || Constants.Package.version;
} }
get userAgent() { get userAgent() {
return `DiscordBot (${this._userAgent.url}, ${this._userAgent.version})`; return `DiscordBot (${this._userAgent.url}, ${this._userAgent.version})`;
} }
} }
module.exports = UserAgentManager; module.exports = UserAgentManager;

View File

@@ -1,5 +1,3 @@
'use strict';
const WebSocket = require('ws'); const WebSocket = require('ws');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const zlib = require('zlib'); const zlib = require('zlib');
@@ -8,111 +6,111 @@ const WebSocketManagerDataStore = require('../../structures/datastore/WebSocketM
class WebSocketManager { class WebSocketManager {
constructor(client) { constructor(client) {
this.client = client; this.client = client;
this.ws = null; this.ws = null;
this.packetManager = new PacketManager(this); this.packetManager = new PacketManager(this);
this.store = new WebSocketManagerDataStore(); this.store = new WebSocketManagerDataStore();
this.status = Constants.Status.IDLE; this.status = Constants.Status.IDLE;
} }
connect(gateway) { connect(gateway) {
this.status = Constants.Status.CONNECTING; this.status = Constants.Status.CONNECTING;
this.store.gateway = gateway; this.store.gateway = `${gateway}/?v=${this.client.options.protocol_version}`;
gateway += `/?v=${this.client.options.protocol_version}`; this.ws = new WebSocket(gateway);
this.ws = new WebSocket(gateway); this.ws.onopen = () => this.eventOpen();
this.ws.onopen = () => this.EventOpen(); this.ws.onclose = () => this.eventClose();
this.ws.onclose = () => this.EventClose(); this.ws.onmessage = (e) => this.eventMessage(e);
this.ws.onmessage = (e) => this.EventMessage(e); this.ws.onerror = (e) => this.eventError(e);
this.ws.onerror = (e) => this.EventError(e); }
}
send(data) { send(data) {
if (this.ws.readyState === WebSocket.OPEN) { if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data)); this.ws.send(JSON.stringify(data));
} }
} }
EventOpen() { eventOpen() {
if (this.reconnecting) { if (this.reconnecting) {
this._sendResume(); this._sendResume();
} else { } else {
this._sendNewIdentify(); this._sendNewIdentify();
} }
} }
_sendResume() { _sendResume() {
let payload = { const payload = {
token: this.client.store.token, token: this.client.store.token,
session_id: this.store.sessionID, session_id: this.store.sessionID,
seq: this.store.sequence, seq: this.store.sequence,
}; };
this.send({ this.send({
op: Constants.OPCodes.RESUME, op: Constants.OPCodes.RESUME,
d: payload, d: payload,
}); });
} }
_sendNewIdentify() { _sendNewIdentify() {
this.reconnecting = false; this.reconnecting = false;
let payload = this.client.options.ws; const payload = this.client.options.ws;
payload.token = this.client.store.token; payload.token = this.client.store.token;
this.send({ this.send({
op: Constants.OPCodes.IDENTIFY, op: Constants.OPCodes.IDENTIFY,
d: payload, d: payload,
}); });
} }
EventClose() { eventClose() {
if (!this.reconnecting) { if (!this.reconnecting) {
this.tryReconnect(); this.tryReconnect();
} }
} }
EventMessage(event) { eventMessage($event) {
let packet; let packet;
try { const event = $event;
if (event.binary) { try {
event.data = zlib.inflateSync(event.data).toString(); if (event.binary) {
} event.data = zlib.inflateSync(event.data).toString();
}
packet = JSON.parse(event.data); packet = JSON.parse(event.data);
} catch (e) { } catch (e) {
return this.EventError(Constants.Errors.BAD_WS_MESSAGE); return this.eventError(Constants.Errors.BAD_WS_MESSAGE);
} }
this.packetManager.handle(packet); return this.packetManager.handle(packet);
} }
EventError(e) { EventError() {
this.tryReconnect(); this.tryReconnect();
} }
checkIfReady() { checkIfReady() {
if (this.status !== Constants.Status.READY) { if (this.status !== Constants.Status.READY) {
let unavailableCount = 0; let unavailableCount = 0;
for (let guildID in this.client.store.data.guilds) { for (const guildID in this.client.store.data.guilds) {
unavailableCount += this.client.store.data.guilds[guildID].available ? 0 : 1; unavailableCount += this.client.store.data.guilds[guildID].available ? 0 : 1;
} }
if (unavailableCount === 0) { if (unavailableCount === 0) {
this.status = Constants.Status.READY; this.status = Constants.Status.READY;
this.client.emit(Constants.Events.READY); this.client.emit(Constants.Events.READY);
this.packetManager.handleQueue(); this.packetManager.handleQueue();
} }
} }
} }
tryReconnect() { tryReconnect() {
this.status = Constants.Status.RECONNECTING; this.status = Constants.Status.RECONNECTING;
this.ws.close(); this.ws.close();
this.packetManager.handleQueue(); this.packetManager.handleQueue();
this.client.emit(Constants.Events.RECONNECTING); this.client.emit(Constants.Events.RECONNECTING);
this.connect(this.store.gateway); this.connect(this.store.gateway);
} }
} }
module.exports = WebSocketManager; module.exports = WebSocketManager;

View File

@@ -1,100 +1,97 @@
'use strict';
const Constants = require('../../../util/Constants'); const Constants = require('../../../util/Constants');
const BeforeReadyWhitelist = [ const BeforeReadyWhitelist = [
Constants.WSEvents.READY, Constants.WSEvents.READY,
Constants.WSEvents.GUILD_CREATE, Constants.WSEvents.GUILD_CREATE,
Constants.WSEvents.GUILD_DELETE, Constants.WSEvents.GUILD_DELETE,
]; ];
class WebSocketPacketManager { class WebSocketPacketManager {
constructor(websocketManager) { constructor(websocketManager) {
this.ws = websocketManager; this.ws = websocketManager;
this.handlers = {}; this.handlers = {};
this.queue = []; this.queue = [];
this.register(Constants.WSEvents.READY, 'Ready'); this.register(Constants.WSEvents.READY, 'Ready');
this.register(Constants.WSEvents.GUILD_CREATE, 'GuildCreate'); this.register(Constants.WSEvents.GUILD_CREATE, 'GuildCreate');
this.register(Constants.WSEvents.GUILD_DELETE, 'GuildDelete'); this.register(Constants.WSEvents.GUILD_DELETE, 'GuildDelete');
this.register(Constants.WSEvents.GUILD_UPDATE, 'GuildUpdate'); this.register(Constants.WSEvents.GUILD_UPDATE, 'GuildUpdate');
this.register(Constants.WSEvents.GUILD_BAN_ADD, 'GuildBanAdd'); this.register(Constants.WSEvents.GUILD_BAN_ADD, 'GuildBanAdd');
this.register(Constants.WSEvents.GUILD_BAN_REMOVE, 'GuildBanRemove'); this.register(Constants.WSEvents.GUILD_BAN_REMOVE, 'GuildBanRemove');
this.register(Constants.WSEvents.GUILD_MEMBER_ADD, 'GuildMemberAdd'); this.register(Constants.WSEvents.GUILD_MEMBER_ADD, 'GuildMemberAdd');
this.register(Constants.WSEvents.GUILD_MEMBER_REMOVE, 'GuildMemberRemove'); this.register(Constants.WSEvents.GUILD_MEMBER_REMOVE, 'GuildMemberRemove');
this.register(Constants.WSEvents.GUILD_MEMBER_UPDATE, 'GuildMemberUpdate'); this.register(Constants.WSEvents.GUILD_MEMBER_UPDATE, 'GuildMemberUpdate');
this.register(Constants.WSEvents.GUILD_ROLE_CREATE, 'GuildRoleCreate'); this.register(Constants.WSEvents.GUILD_ROLE_CREATE, 'GuildRoleCreate');
this.register(Constants.WSEvents.GUILD_ROLE_DELETE, 'GuildRoleDelete'); this.register(Constants.WSEvents.GUILD_ROLE_DELETE, 'GuildRoleDelete');
this.register(Constants.WSEvents.GUILD_ROLE_UPDATE, 'GuildRoleUpdate'); this.register(Constants.WSEvents.GUILD_ROLE_UPDATE, 'GuildRoleUpdate');
this.register(Constants.WSEvents.GUILD_MEMBERS_CHUNK, 'GuildMembersChunk'); this.register(Constants.WSEvents.GUILD_MEMBERS_CHUNK, 'GuildMembersChunk');
this.register(Constants.WSEvents.CHANNEL_CREATE, 'ChannelCreate'); this.register(Constants.WSEvents.CHANNEL_CREATE, 'ChannelCreate');
this.register(Constants.WSEvents.CHANNEL_DELETE, 'ChannelDelete'); this.register(Constants.WSEvents.CHANNEL_DELETE, 'ChannelDelete');
this.register(Constants.WSEvents.CHANNEL_UPDATE, 'ChannelUpdate'); this.register(Constants.WSEvents.CHANNEL_UPDATE, 'ChannelUpdate');
this.register(Constants.WSEvents.PRESENCE_UPDATE, 'PresenceUpdate'); this.register(Constants.WSEvents.PRESENCE_UPDATE, 'PresenceUpdate');
this.register(Constants.WSEvents.USER_UPDATE, 'UserUpdate'); this.register(Constants.WSEvents.USER_UPDATE, 'UserUpdate');
this.register(Constants.WSEvents.VOICE_STATE_UPDATE, 'VoiceStateUpdate'); this.register(Constants.WSEvents.VOICE_STATE_UPDATE, 'VoiceStateUpdate');
this.register(Constants.WSEvents.TYPING_START, 'TypingStart'); this.register(Constants.WSEvents.TYPING_START, 'TypingStart');
this.register(Constants.WSEvents.MESSAGE_CREATE, 'MessageCreate'); this.register(Constants.WSEvents.MESSAGE_CREATE, 'MessageCreate');
this.register(Constants.WSEvents.MESSAGE_DELETE, 'MessageDelete'); this.register(Constants.WSEvents.MESSAGE_DELETE, 'MessageDelete');
this.register(Constants.WSEvents.MESSAGE_UPDATE, 'MessageUpdate'); this.register(Constants.WSEvents.MESSAGE_UPDATE, 'MessageUpdate');
} }
get client() { get client() {
return this.ws.client; return this.ws.client;
} }
register(event, handle) { register(event, handle) {
let Handler = require(`./handlers/${handle}`); const Handler = require(`./handlers/${handle}`);
this.handlers[event] = new Handler(this); this.handlers[event] = new Handler(this);
} }
handleQueue() { handleQueue() {
for (let packetIndex in this.queue) { this.queue.forEach((element, index) => {
this.handle(this.queue[packetIndex]); this.handle(this.queue[index]);
this.queue.splice(packetIndex, 1); this.queue.splice(index, 1);
} });
} }
setSequence(s) { setSequence(s) {
if (s && s > this.ws.store.sequence) { if (s && s > this.ws.store.sequence) {
this.ws.store.sequence = s; this.ws.store.sequence = s;
} }
} }
handle(packet) { handle(packet) {
if (packet.op === Constants.OPCodes.RECONNECT) {
this.setSequence(packet.s);
this.ws.tryReconnect();
return false;
}
if (packet.op === Constants.OPCodes.RECONNECT) { if (packet.op === Constants.OPCodes.INVALID_SESSION) {
this.setSequence(packet.s); this.ws._sendNewIdentify();
this.ws.tryReconnect(); return false;
return; }
}
if (packet.op === Constants.OPCodes.INVALID_SESSION) { if (this.ws.reconnecting) {
this.ws._sendNewIdentify(); this.ws.reconnecting = false;
return; this.ws.checkIfReady();
} }
if (this.ws.reconnecting) { this.setSequence(packet.s);
this.ws.reconnecting = false;
this.ws.checkIfReady();
}
this.setSequence(packet.s); if (this.ws.status !== Constants.Status.READY) {
if (BeforeReadyWhitelist.indexOf(packet.t) === -1) {
this.queue.push(packet);
return false;
}
}
if (this.ws.status !== Constants.Status.READY) { if (this.handlers[packet.t]) {
if (BeforeReadyWhitelist.indexOf(packet.t) === -1) { return this.handlers[packet.t].handle(packet);
this.queue.push(packet); }
return;
}
}
if (this.handlers[packet.t]) { return false;
return this.handlers[packet.t].handle(packet); }
}
return false;
}
} }

View File

@@ -1,14 +1,12 @@
'use strict';
class AbstractHandler { class AbstractHandler {
constructor(packetManager) { constructor(packetManager) {
this.packetManager = packetManager; this.packetManager = packetManager;
} }
handle(packet) { handle(packet) {
return packet;
} }
} }
module.exports = AbstractHandler; module.exports = AbstractHandler;

View File

@@ -1,32 +1,20 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const DMChannel = Structure('DMChannel');
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
class ChannelCreateHandler extends AbstractHandler { class ChannelCreateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const response = client.actions.ChannelCreate.handle(data);
let data = packet.d;
let client = this.packetManager.client;
let 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);
}
}
};
module.exports = ChannelCreateHandler; module.exports = ChannelCreateHandler;

View File

@@ -1,31 +1,20 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const ServerChannel = Structure('ServerChannel');
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
class ChannelDeleteHandler extends AbstractHandler { class ChannelDeleteHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const response = client.actions.ChannelDelete.handle(data);
let data = packet.d;
let client = this.packetManager.client;
let 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);
}
}
};
module.exports = ChannelDeleteHandler; module.exports = ChannelDeleteHandler;

View File

@@ -1,28 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const ServerChannel = Structure('ServerChannel');
const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
class ChannelUpdateHandler extends AbstractHandler { class ChannelUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.ChannelUpdate.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
client.actions.ChannelUpdate.handle(data); }
}
};
module.exports = ChannelUpdateHandler; module.exports = ChannelUpdateHandler;

View File

@@ -1,33 +1,22 @@
'use strict';
// ##untested handler## // ##untested handler##
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
class GuildBanAddHandler extends AbstractHandler { class GuildBanAddHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const guild = client.store.get('guilds', data.guild_id);
let data = packet.d; const user = client.store.get('users', data.user.id);
let client = this.packetManager.client;
let guild = client.store.get('guilds', data.guild_id); if (guild && user) {
let user = client.store.get('users', data.user.id); client.emit(Constants.Events.GUILD_BAN_ADD, guild, user);
}
}
if (guild && user) { }
client.emit(Constants.Events.GUILD_BAN_ADD, guild, user);
}
}
};
module.exports = GuildBanAddHandler; module.exports = GuildBanAddHandler;

View File

@@ -1,33 +1,23 @@
'use strict';
// ##untested handler## // ##untested handler##
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
class GuildBanRemoveHandler extends AbstractHandler { class GuildBanRemoveHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const guild = client.store.get('guilds', data.guild_id);
let data = packet.d; const user = client.store.get('users', data.user.id);
let client = this.packetManager.client;
let guild = client.store.get('guilds', data.guild_id); if (guild && user) {
let user = client.store.get('users', data.user.id); client.emit(Constants.Events.GUILD_BAN_REMOVE, guild, user);
}
}
if (guild && user) { }
client.emit(Constants.Events.GUILD_BAN_REMOVE, guild, user);
}
}
};
module.exports = GuildBanRemoveHandler; module.exports = GuildBanRemoveHandler;

View File

@@ -1,38 +1,25 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants');
class GuildCreateHandler extends AbstractHandler { class GuildCreateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const guild = client.store.get('guilds', data.id);
let data = packet.d;
let client = this.packetManager.client;
let guild = client.store.get('guilds', data.id); if (guild) {
if (!guild.available && !data.unavailable) {
// a newly available guild
guild.setup(data);
this.packetManager.ws.checkIfReady();
}
} else {
// a new guild
client.store.newGuild(data);
}
}
if (guild) { }
if (!guild.available && !data.unavailable) {
// a newly available guild
guild.setup(data);
this.packetManager.ws.checkIfReady();
}
} else {
// a new guild
client.store.NewGuild(data);
}
}
};
module.exports = GuildCreateHandler; module.exports = GuildCreateHandler;

View File

@@ -1,31 +1,19 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
class GuildDeleteHandler extends AbstractHandler { class GuildDeleteHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const response = client.actions.GuildDelete.handle(data);
let data = packet.d;
let client = this.packetManager.client;
let 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);
}
}
};
module.exports = GuildDeleteHandler; module.exports = GuildDeleteHandler;

View File

@@ -1,32 +1,20 @@
'use strict';
// ##untested handler## // ##untested handler##
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants');
class GuildMemberAddHandler extends AbstractHandler { class GuildMemberAddHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const guild = client.store.get('guilds', data.guild_id);
let data = packet.d;
let client = this.packetManager.client;
let guild = client.store.get('guilds', data.guild_id); if (guild) {
guild._addMember(data);
}
}
if (guild) { }
guild._addMember(data);
}
}
};
module.exports = GuildMemberAddHandler; module.exports = GuildMemberAddHandler;

View File

@@ -1,28 +1,16 @@
'use strict';
// ##untested handler## // ##untested handler##
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants');
class GuildMemberRemoveHandler extends AbstractHandler { class GuildMemberRemoveHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.GuildMemberRemove.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.GuildMemberRemove.handle(data); }
}
};
module.exports = GuildMemberRemoveHandler; module.exports = GuildMemberRemoveHandler;

View File

@@ -1,35 +1,23 @@
'use strict';
// ##untested handler## // ##untested handler##
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants');
class GuildMemberUpdateHandler extends AbstractHandler { class GuildMemberUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const guild = client.store.get('guilds', data.guild_id);
let data = packet.d;
let client = this.packetManager.client;
let guild = client.store.get('guilds', data.guild_id); if (guild) {
const member = guild.store.get('members', data.user.id);
if (member) {
guild._updateMember(member, data);
}
}
}
if (guild) { }
let member = guild.store.get('members', data.user.id);
if (member) {
guild._updateMember(member, data);
}
}
}
};
module.exports = GuildMemberUpdateHandler; module.exports = GuildMemberUpdateHandler;

View File

@@ -1,33 +1,25 @@
'use strict';
// ##untested## // ##untested##
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
class GuildMembersChunkHandler extends AbstractHandler { class GuildMembersChunkHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
const guild = client.store.get('guilds', data.guild_id);
handle(packet) { const members = [];
let data = packet.d; if (guild) {
let client = this.packetManager.client; for (const member of guild.members) {
let guild = client.store.get('guilds', data.guild_id); members.push(guild._addMember(member, true));
}
}
let members = []; client.emit(Constants.Events.GUILD_MEMBERS_CHUNK, guild, members);
if (guild) { }
for (let member of guild.members) {
members.push(guild._addMember(member, true));
}
}
client.emit(Constants.Events.GUILD_MEMBERS_CHUNK, guild, members); }
}
};
module.exports = GuildMembersChunkHandler; module.exports = GuildMembersChunkHandler;

View File

@@ -1,25 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants');
const Role = Structure('Role');
const Guild = Structure('Guild');
class GuildRoleCreateHandler extends AbstractHandler { class GuildRoleCreateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.GuildRoleCreate.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.GuildRoleCreate.handle(data); }
}
};
module.exports = GuildRoleCreateHandler; module.exports = GuildRoleCreateHandler;

View File

@@ -1,25 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants');
const Role = Structure('Role');
const Guild = Structure('Guild');
class GuildRoleDeleteHandler extends AbstractHandler { class GuildRoleDeleteHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.GuildRoleDelete.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.GuildRoleDelete.handle(data); }
}
};
module.exports = GuildRoleDeleteHandler; module.exports = GuildRoleDeleteHandler;

View File

@@ -1,26 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
const Role = Structure('Role');
const Guild = Structure('Guild');
class GuildRoleUpdateHandler extends AbstractHandler { class GuildRoleUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.GuildRoleUpdate.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.GuildRoleUpdate.handle(data); }
}
};
module.exports = GuildRoleUpdateHandler; module.exports = GuildRoleUpdateHandler;

View File

@@ -1,28 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
class GuildUpdateHandler extends AbstractHandler { class GuildUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.GuildUpdate.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.GuildUpdate.handle(data); }
}
};
module.exports = GuildUpdateHandler; module.exports = GuildUpdateHandler;

View File

@@ -1,29 +1,19 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
const Message = Structure('Message');
const Guild = Structure('Guild');
class MessageCreateHandler extends AbstractHandler { class MessageCreateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const response = client.actions.MessageCreate.handle(data);
let data = packet.d;
let client = this.packetManager.client;
let response = client.actions.MessageCreate.handle(data); if (response.m) {
client.emit(Constants.Events.MESSAGE_CREATE, response.m);
}
}
if (response.m) { }
client.emit(Constants.Events.MESSAGE_CREATE, response.m);
}
}
};
module.exports = MessageCreateHandler; module.exports = MessageCreateHandler;

View File

@@ -1,29 +1,19 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
const Message = Structure('Message');
const Guild = Structure('Guild');
class MessageDeleteHandler extends AbstractHandler { class MessageDeleteHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { const response = client.actions.MessageDelete.handle(data);
let data = packet.d;
let client = this.packetManager.client;
let response = client.actions.MessageDelete.handle(data); if (response.m) {
client.emit(Constants.Events.MESSAGE_DELETE, response.m);
}
}
if (response.m) { }
client.emit(Constants.Events.MESSAGE_DELETE, response.m);
}
}
};
module.exports = MessageDeleteHandler; module.exports = MessageDeleteHandler;

View File

@@ -1,27 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
const Message = Structure('Message');
const Guild = Structure('Guild');
class MessageUpdateHandler extends AbstractHandler { class MessageUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.MessageUpdate.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.MessageUpdate.handle(data); }
}
};
module.exports = MessageUpdateHandler; module.exports = MessageUpdateHandler;

View File

@@ -1,75 +1,66 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject'); const cloneObject = require('../../../../util/CloneObject');
const Role = Structure('User');
class PresenceUpdateHandler extends AbstractHandler { class PresenceUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
let user = client.store.get('users', data.user.id);
const guild = client.store.get('guilds', data.guild_id);
handle(packet) { function makeUser(newUser) {
let data = packet.d; return client.store.newUser(newUser);
let client = this.packetManager.client; }
let user = client.store.get('users', data.user.id);
let guild = client.store.get('guilds', data.guild_id);
function makeUser(user) { // step 1
return client.store.NewUser(user); if (!user) {
} if (data.user.username) {
user = makeUser(data.user);
} else {
return;
}
}
// step 1 if (guild) {
if (!user) { const memberInGuild = guild.store.get('members', user.id);
if (data.user.username) { if (!memberInGuild) {
user = makeUser(data.user); const member = guild._addMember({
}else { user,
return; roles: data.roles,
} deaf: false,
} mute: false,
}, true);
client.emit(Constants.Events.GUILD_MEMBER_AVAILABLE, guild, member);
}
}
if (guild) { data.user.username = data.user.username || user.username;
let memberInGuild = guild.store.get('members', user.id); data.user.id = data.user.id || user.id;
if (!memberInGuild) { data.user.discriminator = data.user.discriminator || user.discriminator;
let member = guild._addMember({
user,
roles: data.roles,
deaf: false,
mute: false,
}, true);
client.emit(Constants.Events.GUILD_MEMBER_AVAILABLE, guild, member);
}
}
data.user.username = data.user.username || user.username; // comment out avatar patching as it causes bugs (see #297)
data.user.id = data.user.id || user.id; // data.user.avatar = data.user.avatar || user.avatar;
data.user.discriminator = data.user.discriminator || user.discriminator; data.user.status = data.status || user.status;
data.user.game = data.game;
// comment out avatar patching as it causes bugs (see #297) const same = (
// data.user.avatar = data.user.avatar || user.avatar; data.user.username === user.username &&
data.user.status = data.status || user.status; data.user.id === user.id &&
data.user.game = data.game; data.user.discriminator === user.discriminator &&
data.user.avatar === user.avatar &&
data.user.status === user.status &&
JSON.stringify(data.user.game) === JSON.stringify(user.game)
);
let same = ( if (!same) {
data.user.username === user.username && const oldUser = cloneObject(user);
data.user.id === user.id && user.setup(data.user);
data.user.discriminator === user.discriminator && client.emit(Constants.Events.PRESENCE_UPDATE, oldUser, user);
data.user.avatar === user.avatar && }
data.user.status === user.status && }
JSON.stringify(data.user.game) === JSON.stringify(user.game)
);
if (!same) { }
let oldUser = CloneObject(user);
user.setup(data.user);
client.emit(Constants.Events.PRESENCE_UPDATE, oldUser, user);
}
}
};
module.exports = PresenceUpdateHandler; module.exports = PresenceUpdateHandler;

View File

@@ -1,39 +1,30 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const ClientUser = Structure('ClientUser'); const getStructure = name => require(`../../../../structures/${name}`);
const Guild = Structure('Guild'); const ClientUser = getStructure('ClientUser');
const DMChannel = Structure('DMChannel');
class ReadyHandler extends AbstractHandler { class ReadyHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
client.manager.setupKeepAlive(data.heartbeat_interval);
handle(packet) { client.store.user = client.store.add('users', new ClientUser(client, data.user));
let data = packet.d;
let client = this.packetManager.client;
client.manager.setupKeepAlive(data.heartbeat_interval);
client.store.user = client.store.add('users', new ClientUser(client, data.user)); for (const guild of data.guilds) {
client.store.newGuild(guild);
}
for (let guild of data.guilds) { for (const privateDM of data.private_channels) {
client.store.NewGuild(guild); client.store.newChannel(privateDM);
} }
for (let privateDM of data.private_channels) { this.packetManager.ws.store.sessionID = data.session_id;
client.store.NewChannel(privateDM);
}
this.packetManager.ws.store.sessionID = data.session_id; this.packetManager.ws.checkIfReady();
}
this.packetManager.ws.checkIfReady(); }
}
};
module.exports = ReadyHandler; module.exports = ReadyHandler;

View File

@@ -1,60 +1,52 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants'); const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
class TypingData { class TypingData {
constructor(since, lastTimestamp, _timeout) { constructor(since, lastTimestamp, _timeout) {
this.since = since; this.since = since;
this.lastTimestamp = lastTimestamp; this.lastTimestamp = lastTimestamp;
this._timeout = _timeout; this._timeout = _timeout;
} }
resetTimeout(_timeout) { resetTimeout(_timeout) {
clearTimeout(this._timeout); clearTimeout(this._timeout);
this._timeout = _timeout; this._timeout = _timeout;
} }
get elapsedTime() { get elapsedTime() {
return Date.now() - this.since; return Date.now() - this.since;
} }
} }
class TypingStartHandler extends AbstractHandler { class TypingStartHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
const channel = client.store.get('channels', data.channel_id);
const user = client.store.get('users', data.user_id);
const timestamp = new Date(data.timestamp * 1000);
handle(packet) { function tooLate() {
let data = packet.d; return setTimeout(() => {
let client = this.packetManager.client; client.emit(Constants.Events.TYPING_STOP, channel, user, channel.typingMap[user.id]);
let channel = client.store.get('channels', data.channel_id); delete channel.typingMap[user.id];
let user = client.store.get('users', data.user_id); }, 6000);
let timestamp = new Date(data.timestamp * 1000); }
if (channel && user) { if (channel && user) {
if (channel.typingMap[user.id]) { if (channel.typingMap[user.id]) {
// already typing, renew // already typing, renew
let mapping = channel.typingMap[user.id]; const mapping = channel.typingMap[user.id];
mapping.lastTimestamp = timestamp; mapping.lastTimestamp = timestamp;
mapping.resetTimeout(tooLate()); mapping.resetTimeout(tooLate());
} else { } else {
channel.typingMap[user.id] = new TypingData(timestamp, timestamp, tooLate()); channel.typingMap[user.id] = new TypingData(timestamp, timestamp, tooLate());
client.emit(Constants.Events.TYPING_START, channel, user); client.emit(Constants.Events.TYPING_START, channel, user);
} }
} }
}
function tooLate() { }
return setTimeout(() => {
client.emit(Constants.Events.TYPING_STOP, channel, user, channel.typingMap[user.id]);
delete channel.typingMap[user.id];
}, 6000);
}
}
};
module.exports = TypingStartHandler; module.exports = TypingStartHandler;

View File

@@ -1,28 +1,14 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const CloneObject = name => require(`../../../../util/CloneObject`);
const Constants = require(`../../../../util/Constants`);
const ClientUser = Structure('ClientUser');
const Guild = Structure('Guild');
const DMChannel = Structure('DMChannel');
class UserUpdateHandler extends AbstractHandler { class UserUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
handle(packet) { client.actions.UserUpdate.handle(data);
let data = packet.d; }
let client = this.packetManager.client;
let response = client.actions.UserUpdate.handle(data); }
}
};
module.exports = UserUpdateHandler; module.exports = UserUpdateHandler;

View File

@@ -1,43 +1,34 @@
'use strict';
const AbstractHandler = require('./AbstractHandler'); const AbstractHandler = require('./AbstractHandler');
const Structure = name => require(`../../../../structures/${name}`);
const Constants = require('../../../../util/Constants');
const CloneObject = require('../../../../util/CloneObject');
const Role = Structure('User'); const Constants = require('../../../../util/Constants');
const cloneObject = require('../../../../util/CloneObject');
class VoiceStateUpdateHandler extends AbstractHandler { class VoiceStateUpdateHandler extends AbstractHandler {
constructor(packetManager) { handle(packet) {
super(packetManager); const data = packet.d;
} const client = this.packetManager.client;
const guild = client.store.get('guilds', data.guild_id);
handle(packet) { if (guild) {
let data = packet.d; const member = guild.store.get('members', data.user_id);
let client = this.packetManager.client; if (member) {
let guild = client.store.get('guilds', data.guild_id); const oldVoiceChannelMember = cloneObject(member);
if (member.voiceChannel && member.voiceChannel.id !== data.channel_id) {
member.voiceChannel.store.remove('members', oldVoiceChannelMember);
}
if (guild) { member.serverMute = data.mute;
let member = guild.store.get('members', data.user_id); member.serverDeaf = data.deaf;
let channel = guild.store.get('channels', data.channel_id); member.selfMute = data.self_mute;
if (member) { member.selfDeaf = data.self_deaf;
let oldVoiceChannelMember = CloneObject(member); member.voiceSessionID = data.session_id;
if (member.voiceChannel && member.voiceChannel.id !== data.channel_id) { member.voiceChannelID = data.channel_id;
member.voiceChannel.store.remove('members', oldVoiceChannelMember); client.emit(Constants.Events.VOICE_STATE_UPDATE, oldVoiceChannelMember, member);
} }
}
}
member.serverMute = data.mute; }
member.serverDeaf = data.deaf;
member.selfMute = data.self_mute;
member.selfDeaf = data.self_deaf;
member.voiceSessionID = data.session_id;
member.voiceChannelID = data.channel_id;
client.emit(Constants.Events.VOICE_STATE_UPDATE, oldVoiceChannelMember, member);
}
}
}
};
module.exports = VoiceStateUpdateHandler; module.exports = VoiceStateUpdateHandler;

View File

@@ -1,10 +1,8 @@
'use strict';
const values = require('object.values'); const values = require('object.values');
const Client = require('./client/Client'); const Client = require('./client/Client');
if (!Object.values) { if (!Object.values) {
values.shim(); values.shim();
} }
exports.Client = Client; exports.Client = Client;

View File

@@ -1,26 +1,24 @@
'use strict';
class Channel { class Channel {
constructor(client, data, guild) { constructor(client, data, guild) {
this.client = client; this.client = client;
this.typingMap = {}; this.typingMap = {};
this.typingTimeouts = []; this.typingTimeouts = [];
if (guild) { if (guild) {
this.guild = guild; this.guild = guild;
} }
if (data) { if (data) {
this.setup(data); this.setup(data);
} }
} }
setup(data) { setup(data) {
this.id = data.id; this.id = data.id;
} }
delete() { delete() {
return this.client.rest.methods.DeleteChannel(this); return this.client.rest.methods.deleteChannel(this);
} }
} }
module.exports = Channel; module.exports = Channel;

View File

@@ -1,37 +1,31 @@
'use strict';
const User = require('./User'); const User = require('./User');
class ClientUser extends User { class ClientUser extends User {
constructor(client, data) { setup(data) {
super(client, data); super.setup(data);
} this.verified = data.verified;
this.email = data.email;
}
setup(data) { setUsername(username) {
super.setup(data); return this.client.rest.methods.updateCurrentUser({ username });
this.verified = data.verified; }
this.email = data.email;
}
setUsername(username) { setEmail(email) {
return this.client.rest.methods.UpdateCurrentUser({ username, }); return this.client.rest.methods.updateCurrentUser({ email });
} }
setEmail(email) { setPassword(password) {
return this.client.rest.methods.UpdateCurrentUser({ email, }); return this.client.rest.methods.updateCurrentUser({ password });
} }
setPassword(password) { setAvatar(avatar) {
return this.client.rest.methods.UpdateCurrentUser({ password, }); return this.client.rest.methods.updateCurrentUser({ avatar });
} }
setAvatar(avatar) { edit(data) {
return this.client.rest.methods.UpdateCurrentUser({ avatar, }); return this.client.rest.methods.updateCurrentUser(data);
} }
edit(data) {
return this.client.rest.methods.UpdateCurrentUser(data);
}
} }
module.exports = ClientUser; module.exports = ClientUser;

View File

@@ -1,40 +1,38 @@
'use strict';
const Channel = require('./Channel'); const Channel = require('./Channel');
const TextBasedChannel = require('./interface/TextBasedChannel'); const TextBasedChannel = require('./interface/TextBasedChannel');
const User = require('./User'); const User = require('./User');
const TextChannelDataStore = require('./datastore/TextChannelDataStore'); const TextChannelDataStore = require('./datastore/TextChannelDataStore');
class DMChannel extends Channel{ class DMChannel extends Channel {
constructor(client, data) { constructor(client, data) {
super(client, data); super(client, data);
this.store = new TextChannelDataStore(); this.store = new TextChannelDataStore();
} }
_cacheMessage(message) { _cacheMessage(message) {
let maxSize = this.client.options.max_message_cache; const maxSize = this.client.options.max_message_cache;
if (maxSize === 0) { if (maxSize === 0) {
// saves on performance // saves on performance
return; return;
} }
let storeKeys = Object.keys(this.store); const storeKeys = Object.keys(this.store);
if (storeKeys.length >= maxSize) { if (storeKeys.length >= maxSize) {
this.store.remove(storeKeys[0]); this.store.remove(storeKeys[0]);
} }
this.store.add('messages', message); this.store.add('messages', message);
} }
setup(data) { setup(data) {
super.setup(data); super.setup(data);
this.recipient = this.client.store.add('users', new User(this.client, data.recipient)); this.recipient = this.client.store.add('users', new User(this.client, data.recipient));
this.lastMessageID = data.last_message_id; this.lastMessageID = data.last_message_id;
} }
toString() { toString() {
return this.recipient.toString(); return this.recipient.toString();
} }
} }
TextBasedChannel.applyToClass(DMChannel); TextBasedChannel.applyToClass(DMChannel);

View File

@@ -1,39 +1,37 @@
'use strict'; const Constants = require('../util/Constants');
const Constants = require('../Util/Constants');
class EvaluatedPermissions { class EvaluatedPermissions {
constructor(member, permissions) { constructor(member, permissions) {
this.member = member; this.member = member;
this.permissions = permissions; this.permissions = permissions;
} }
serialize() { serialize() {
let serializedPermissions = {}; const serializedPermissions = {};
for (let permissionName in Constants.PermissionFlags) { for (const permissionName in Constants.PermissionFlags) {
serializedPermissions[permissionName] = this.hasPermission(permissionName); serializedPermissions[permissionName] = this.hasPermission(permissionName);
} }
return serializedPermissions; return serializedPermissions;
} }
hasPermission(permission, explicit) { hasPermission(permission, explicit) {
if (permission instanceof String || typeof permission === 'string') { if (permission instanceof String || typeof permission === 'string') {
permission = Constants.PermissionFlags[permission]; permission = Constants.PermissionFlags[permission];
} }
if (!permission) { if (!permission) {
throw Constants.Errors.NOT_A_PERMISSION; throw Constants.Errors.NOT_A_PERMISSION;
} }
if (!explicit) { if (!explicit) {
if ((this.permissions & Constants.PermissionFlags.ADMINISTRATOR) > 0) { if ((this.permissions & Constants.PermissionFlags.ADMINISTRATOR) > 0) {
return true; return true;
} }
} }
return ((this.permissions & permission) > 0); return ((this.permissions & permission) > 0);
} }
} }
module.exports = EvaluatedPermissions; module.exports = EvaluatedPermissions;

View File

@@ -1,244 +1,240 @@
'use strict';
const User = require('./User'); const User = require('./User');
const GuildMember = require('./GuildMember'); const GuildMember = require('./GuildMember');
const GuildDataStore = require('./datastore/GuildDataStore'); const GuildDataStore = require('./datastore/GuildDataStore');
const TextChannel = require('./TextChannel'); const Constants = require('../util/Constants');
const VoiceChannel = require('./VoiceChannel');
const Constants = require('../Util/Constants');
const Role = require('./Role'); const Role = require('./Role');
function arraysEqual(a, b) { function arraysEqual(a, b) {
if (a === b) return true; if (a === b) return true;
if (a.length !== b.length) return false; if (a.length !== b.length) return false;
for (let itemInd in a) { for (const itemInd in a) {
let item = a[itemInd]; const item = a[itemInd];
let ind = b.indexOf(item); const ind = b.indexOf(item);
if (ind) { if (ind) {
b.splice(ind, 1); b.splice(ind, 1);
} }
} }
return b.length === 0; return b.length === 0;
} }
class Guild { class Guild {
constructor(client, data) { constructor(client, data) {
this.client = client; this.client = client;
this.store = new GuildDataStore(); this.store = new GuildDataStore();
if (!data) { if (!data) {
return; return;
} }
if (data.unavailable) { if (data.unavailable) {
this.available = false; this.available = false;
this.id = data.id; this.id = data.id;
} else { } else {
this.available = true; this.available = true;
this.setup(data); this.setup(data);
} }
} }
_addMember(guildUser, noEvent) { _addMember(guildUser, noEvent) {
if (!(guildUser.user instanceof User)) { if (!(guildUser.user instanceof User)) {
guildUser.user = this.client.store.NewUser(guildUser.user); guildUser.user = this.client.store.newUser(guildUser.user);
} }
guildUser.joined_at = guildUser.joined_at || 0; guildUser.joined_at = guildUser.joined_at || 0;
let member = this.store.add('members', new GuildMember(this, guildUser)); const member = this.store.add('members', new GuildMember(this, guildUser));
if (this.client.ws.status === Constants.Status.READY && !noEvent) { if (this.client.ws.status === Constants.Status.READY && !noEvent) {
this.client.emit(Constants.Events.GUILD_MEMBER_ADD, this, member); this.client.emit(Constants.Events.GUILD_MEMBER_ADD, this, member);
} }
return member; return member;
} }
_updateMember(member, data) { _updateMember(member, data) {
let oldRoles = member.roles; const oldRoles = member.roles;
member._roles = data.roles; member._roles = data.roles;
if (this.client.ws.status === Constants.Status.READY) { if (this.client.ws.status === Constants.Status.READY) {
this.client.emit(Constants.Events.GUILD_MEMBER_ROLES_UPDATE, this, oldRoles, member.roles); this.client.emit(Constants.Events.GUILD_MEMBER_ROLES_UPDATE, this, oldRoles, member.roles);
} }
} }
_removeMember(guildMember) { _removeMember(guildMember) {
this.store.remove('members', guildMember); this.store.remove('members', guildMember);
} }
toString() { toString() {
return this.name; return this.name;
} }
kick(member) { kick(member) {
return this.member(member).kick(); return this.member(member).kick();
} }
member(user) { member(user) {
return this.client.resolver.ResolveGuildMember(this, user); return this.client.resolver.resolveGuildMember(this, user);
} }
equals(data) { equals(data) {
let base = let base =
this.id === data.id && this.id === data.id &&
this.available === !data.unavailable && this.available === !data.unavailable &&
this.splash === data.splash && this.splash === data.splash &&
this.region === data.region && this.region === data.region &&
this.name === data.name && this.name === data.name &&
this.memberCount === data.member_count && this.memberCount === data.member_count &&
this.large === data.large && this.large === data.large &&
this.icon === data.icon && this.icon === data.icon &&
arraysEqual(this.features, data.features) && arraysEqual(this.features, data.features) &&
this.owner.id === data.owner_id && this.owner.id === data.owner_id &&
this.verificationLevel === data.verification_level && this.verificationLevel === data.verification_level &&
this.embedEnabled === data.embed_enabled; this.embedEnabled === data.embed_enabled;
if (base) { if (base) {
if (this.embedChannel) { if (this.embedChannel) {
if (this.embedChannel.id !== data.embed_channel_id) { if (this.embedChannel.id !== data.embed_channel_id) {
base = false; base = false;
} }
} else if (data.embed_channel_id) { } else if (data.embed_channel_id) {
base = false; base = false;
} }
} }
return base; return base;
} }
setup(data) { setup(data) {
this.id = data.id; this.id = data.id;
this.available = !data.unavailable; this.available = !data.unavailable;
this.splash = data.splash; this.splash = data.splash;
this.region = data.region; this.region = data.region;
this.name = data.name; this.name = data.name;
this.memberCount = data.member_count; this.memberCount = data.member_count;
this.large = data.large; this.large = data.large;
this.joinDate = new Date(data.joined_at); this.joinDate = new Date(data.joined_at);
this.icon = data.icon; this.icon = data.icon;
this.features = data.features; this.features = data.features;
this.emojis = data.emojis; this.emojis = data.emojis;
this.afkTimeout = data.afk_timeout; this.afkTimeout = data.afk_timeout;
this.afkChannelID = data.afk_channel_id; this.afkChannelID = data.afk_channel_id;
this.embedEnabled = data.embed_enabled; this.embedEnabled = data.embed_enabled;
this.verificationLevel = data.verification_level; this.verificationLevel = data.verification_level;
this.features = data.features || []; this.features = data.features || [];
if (data.members) { if (data.members) {
this.store.clear('members'); this.store.clear('members');
for (let guildUser of data.members) { for (const guildUser of data.members) {
this._addMember(guildUser); this._addMember(guildUser);
} }
} }
this.owner = this.store.get('members', data.owner_id); this.owner = this.store.get('members', data.owner_id);
if (data.channels) { if (data.channels) {
this.store.clear('channels'); this.store.clear('channels');
for (let channel of data.channels) { for (const channel of data.channels) {
this.client.store.NewChannel(channel, this); this.client.store.newChannel(channel, this);
} }
} }
this.embedChannel = this.store.get('channels', data.embed_channel_id); this.embedChannel = this.store.get('channels', data.embed_channel_id);
if (data.roles) { if (data.roles) {
this.store.clear('roles'); this.store.clear('roles');
for (let role of data.roles) { for (const role of data.roles) {
this.store.add('roles', new Role(this, role)); this.store.add('roles', new Role(this, role));
} }
} }
if (data.presences) { if (data.presences) {
for (let presence of data.presences) { for (const presence of data.presences) {
let user = this.client.store.get('users', presence.user.id); const user = this.client.store.get('users', presence.user.id);
if (user) { if (user) {
user.status = presence.status; user.status = presence.status;
user.game = presence.game; user.game = presence.game;
} }
} }
} }
if (data.voice_states) { if (data.voice_states) {
for (let voiceState of data.voice_states) { for (const voiceState of data.voice_states) {
let member = this.store.get('members', voiceState.user_id); const member = this.store.get('members', voiceState.user_id);
if (member) { if (member) {
member.serverMute = voiceState.mute; member.serverMute = voiceState.mute;
member.serverDeaf = voiceState.deaf; member.serverDeaf = voiceState.deaf;
member.selfMute = voiceState.self_mute; member.selfMute = voiceState.self_mute;
member.selfDeaf = voiceState.self_deaf; member.selfDeaf = voiceState.self_deaf;
member.voiceSessionID = voiceState.session_id; member.voiceSessionID = voiceState.session_id;
member.voiceChannelID = voiceState.channel_id; member.voiceChannelID = voiceState.channel_id;
} }
} }
} }
} }
createChannel(name, type) { createChannel(name, type) {
return this.client.rest.methods.CreateChannel(this, name, type); return this.client.rest.methods.createChannel(this, name, type);
} }
createRole() { createRole() {
return this.client.rest.methods.CreateGuildRole(this); return this.client.rest.methods.createGuildRole(this);
} }
leave() { leave() {
return this.client.rest.methods.LeaveGuild(this); return this.client.rest.methods.leaveGuild(this);
} }
delete() { delete() {
return this.client.rest.methods.DeleteGuild(this); return this.client.rest.methods.deleteGuild(this);
} }
edit(data) { edit(data) {
return this.client.rest.methods.UpdateGuild(this, data); return this.client.rest.methods.updateGuild(this, data);
} }
setName(name) { setName(name) {
return this.edit({ name, }); return this.edit({ name });
} }
setRegion(region) { setRegion(region) {
return this.edit({ region, }); return this.edit({ region });
} }
setVerificationLevel(verificationLevel) { setVerificationLevel(verificationLevel) {
return this.edit({ verificationLevel, }); return this.edit({ verificationLevel });
} }
setAFKChannel(afkchannel) { setAFKChannel(afkChannel) {
return this.edit({ afkChannel, }); return this.edit({ afkChannel });
} }
setAFKTimeout(afkTimeout) { setAFKTimeout(afkTimeout) {
return this.edit({ afkTimeout, }); return this.edit({ afkTimeout });
} }
setIcon(icon) { setIcon(icon) {
return this.edit({ icon, }); return this.edit({ icon });
} }
setOwner(owner) { setOwner(owner) {
return this.edit({ owner, }); return this.edit({ owner });
} }
setSplash(splash) { setSplash(splash) {
return this.edit({ splash, }); return this.edit({ splash });
} }
get channels() { return this.store.getAsArray('channels'); } get channels() { return this.store.getAsArray('channels'); }
get $channels() { return this.store.data.channels; } get $channels() { return this.store.data.channels; }
get roles() { return this.store.getAsArray('roles'); } get roles() { return this.store.getAsArray('roles'); }
get $roles() { return this.store.data.roles; } get $roles() { return this.store.data.roles; }
get members() { return this.store.getAsArray('members'); } get members() { return this.store.getAsArray('members'); }
get $members() { return this.store.data.members; } get $members() { return this.store.data.members; }
} }
module.exports = Guild; module.exports = Guild;

View File

@@ -1,71 +1,69 @@
'use strict';
const TextBasedChannel = require('./interface/TextBasedChannel'); const TextBasedChannel = require('./interface/TextBasedChannel');
class GuildMember { class GuildMember {
constructor(guild, data) { constructor(guild, data) {
this.client = guild.client; this.client = guild.client;
this.guild = guild; this.guild = guild;
this.user = {}; this.user = {};
this._roles = []; this._roles = [];
if (data) { if (data) {
this.setup(data); this.setup(data);
} }
} }
setup(data) { setup(data) {
this.user = data.user; this.user = data.user;
this.serverDeaf = data.deaf; this.serverDeaf = data.deaf;
this.serverMute = data.mute; this.serverMute = data.mute;
this.selfMute = data.self_mute; this.selfMute = data.self_mute;
this.selfDeaf = data.self_deaf; this.selfDeaf = data.self_deaf;
this.voiceSessionID = data.session_id; this.voiceSessionID = data.session_id;
this.voiceChannelID = data.channel_id; this.voiceChannelID = data.channel_id;
this.joinDate = new Date(data.joined_at); this.joinDate = new Date(data.joined_at);
this._roles = data.roles; this._roles = data.roles;
} }
get roles() { get roles() {
let list = []; const list = [];
let everyoneRole = this.guild.store.get('roles', this.guild.id); const everyoneRole = this.guild.store.get('roles', this.guild.id);
if (everyoneRole) { if (everyoneRole) {
list.push(everyoneRole); list.push(everyoneRole);
} }
for (let roleID of this._roles) { for (const roleID of this._roles) {
let role = this.guild.store.get('roles', roleID); const role = this.guild.store.get('roles', roleID);
if (role) { if (role) {
list.push(role); list.push(role);
} }
} }
return list; return list;
} }
get mute() { get mute() {
return this.selfMute || this.serverMute; return this.selfMute || this.serverMute;
} }
get deaf() { get deaf() {
return this.selfDeaf || this.serverDeaf; return this.selfDeaf || this.serverDeaf;
} }
get voiceChannel() { get voiceChannel() {
return this.guild.store.get('channels', this.voiceChannelID); return this.guild.store.get('channels', this.voiceChannelID);
} }
get id() { get id() {
return this.user.id; return this.user.id;
} }
deleteDM() { deleteDM() {
return this.client.rest.methods.DeleteChannel(this); return this.client.rest.methods.deleteChannel(this);
} }
kick() { kick() {
return this.client.rest.methods.KickGuildMember(this.guild, this); return this.client.rest.methods.kickGuildMember(this.guild, this);
} }
} }
TextBasedChannel.applyToClass(GuildMember); TextBasedChannel.applyToClass(GuildMember);

View File

@@ -1,111 +1,117 @@
'use strict';
class Message { class Message {
constructor(channel, data, client) { constructor(channel, data, client) {
this.channel = channel; this.channel = channel;
if (channel.guild) { if (channel.guild) {
this.guild = channel.guild; this.guild = channel.guild;
} }
this.client = client; this.client = client;
if (data) { if (data) {
this.setup(data); this.setup(data);
} }
} }
setup(data) { setup(data) {
this.author = this.client.store.NewUser(data.author); this.author = this.client.store.newUser(data.author);
this.content = data.content; this.content = data.content;
this.timestamp = new Date(data.timestamp); this.timestamp = new Date(data.timestamp);
this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp) : null; this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp) : null;
this.tts = data.tts; this.tts = data.tts;
this.mentionEveryone = data.mention_everyone; this.mentionEveryone = data.mention_everyone;
this.nonce = data.nonce; this.nonce = data.nonce;
this.embeds = data.embeds; this.embeds = data.embeds;
this.attachments = data.attachments; this.attachments = data.attachments;
this.mentions = []; this.mentions = [];
this.id = data.id; this.id = data.id;
for (let mention of data.mentions) { for (const mention of data.mentions) {
let user = this.client.store.get('users', mention.id); let user = this.client.store.get('users', mention.id);
if (user) { if (user) {
this.mentions.push(user); this.mentions.push(user);
} else { } else {
user = this.client.store.NewUser(mention); user = this.client.store.newUser(mention);
this.mentions.push(user); this.mentions.push(user);
} }
} }
} }
patch(data) { patch(data) {
if (data.author) if (data.author) {
this.author = this.client.store.get('users', data.author.id); this.author = this.client.store.get('users', data.author.id);
if (data.content) }
this.content = data.content; if (data.content) {
if (data.timestamp) this.content = data.content;
this.timestamp = new Date(data.timestamp); }
if (data.edited_timestamp) if (data.timestamp) {
this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp) : null; this.timestamp = new Date(data.timestamp);
if (data.tts) }
this.tts = data.tts; if (data.edited_timestamp) {
if (data.mention_everyone) this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp) : null;
this.mentionEveryone = data.mention_everyone; }
if (data.nonce) if (data.tts) {
this.nonce = data.nonce; this.tts = data.tts;
if (data.embeds) }
this.embeds = data.embeds; if (data.mention_everyone) {
if (data.attachments) this.mentionEveryone = data.mention_everyone;
this.attachments = data.attachments; }
if (data.mentions) { if (data.nonce) {
for (let mention of data.mentions) { this.nonce = data.nonce;
let user = this.client.store.get('users', mention.id); }
if (user) { if (data.embeds) {
this.mentions.push(user); this.embeds = data.embeds;
} else { }
user = this.client.store.NewUser(mention); if (data.attachments) {
this.mentions.push(user); this.attachments = data.attachments;
} }
} if (data.mentions) {
} for (const mention of data.mentions) {
let user = this.client.store.get('users', mention.id);
if (user) {
this.mentions.push(user);
} else {
user = this.client.store.newUser(mention);
this.mentions.push(user);
}
}
}
if (data.id) if (data.id) {
this.id = data.id; this.id = data.id;
} }
}
equals(message, rawData) { equals(message, rawData) {
const embedUpdate = !message.author && !message.attachments;
let embedUpdate = !message.author && !message.attachments; if (embedUpdate) {
const base = this.id === message.id &&
this.embeds.length === message.embeds.length;
return base;
}
let base = this.id === message.id &&
this.author.id === message.author.id &&
this.content === message.content &&
this.tts === message.tts &&
this.nonce === message.nonce &&
this.embeds.length === message.embeds.length &&
this.attachments.length === message.attachments.length;
if (embedUpdate) { if (base && rawData) {
let base = this.id === message.id && base = this.mentionEveryone === message.mentionEveryone &&
this.embeds.length === message.embeds.length; this.timestamp.getTime() === new Date(rawData.timestamp).getTime() &&
return base; this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
} else { }
let base = this.id === message.id &&
this.author.id === message.author.id &&
this.content === message.content &&
this.tts === message.tts &&
this.nonce === message.nonce &&
this.embeds.length === message.embeds.length &&
this.attachments.length === message.attachments.length;
if (base && rawData) { return base;
base = this.mentionEveryone === message.mentionEveryone && }
this.timestamp.getTime() === new Date(data.timestamp).getTime() &&
this.editedTimestamp === new Date(data.edited_timestamp).getTime();
}
return base; delete() {
} return this.client.rest.methods.deleteMessage(this);
} }
delete() { edit(content) {
return this.client.rest.methods.DeleteMessage(this); return this.client.rest.methods.updateMessage(this, content);
} }
edit(content) {
return this.client.rest.methods.UpdateMessage(this, content);
}
} }
module.exports = Message; module.exports = Message;

View File

@@ -1,19 +1,17 @@
'use strict';
class PermissionOverwrites { class PermissionOverwrites {
constructor(serverChannel, data) { constructor(serverChannel, data) {
this.channel = serverChannel; this.channel = serverChannel;
if (data) { if (data) {
this.setup(data); this.setup(data);
} }
} }
setup(data) { setup(data) {
this.type = data.type; this.type = data.type;
this.id = data.id; this.id = data.id;
this.denyData = data.deny; this.denyData = data.deny;
this.allowData = data.allow; this.allowData = data.allow;
} }
} }
module.exports = PermissionOverwrites; module.exports = PermissionOverwrites;

View File

@@ -1,92 +1,90 @@
'use strict'; const Constants = require('../util/Constants');
const Constants = require('../Util/Constants');
class Role { class Role {
constructor(guild, data) { constructor(guild, data) {
this.guild = guild; this.guild = guild;
this.client = guild.client; this.client = guild.client;
if (data) { if (data) {
this.setup(data); this.setup(data);
} }
} }
equals(role) { equals(role) {
return ( return (
this.id === role.id && this.id === role.id &&
this.name === role.name && this.name === role.name &&
this.color === role.color && this.color === role.color &&
this.hoist === role.hoist && this.hoist === role.hoist &&
this.position === role.position && this.position === role.position &&
this.permissions === role.permissions && this.permissions === role.permissions &&
this.managed === role.managed this.managed === role.managed
); );
} }
setup(data) { setup(data) {
this.id = data.id; this.id = data.id;
this.name = data.name; this.name = data.name;
this.color = data.color; this.color = data.color;
this.hoist = data.hoist; this.hoist = data.hoist;
this.position = data.position; this.position = data.position;
this.permissions = data.permissions; this.permissions = data.permissions;
this.managed = data.managed; this.managed = data.managed;
} }
delete() { delete() {
return this.client.rest.methods.DeleteGuildRole(this); return this.client.rest.methods.deleteGuildRole(this);
} }
edit(data) { edit(data) {
return this.client.rest.methods.UpdateGuildRole(this, data); return this.client.rest.methods.updateGuildRole(this, data);
} }
setName(name) { setName(name) {
return this.client.rest.methods.UpdateGuildRole(this, {name,}); return this.client.rest.methods.updateGuildRole(this, { name });
} }
setColor(color) { setColor(color) {
return this.client.rest.methods.UpdateGuildRole(this, {color,}); return this.client.rest.methods.updateGuildRole(this, { color });
} }
setHoist(hoist) { setHoist(hoist) {
return this.client.rest.methods.UpdateGuildRole(this, {hoist,}); return this.client.rest.methods.updateGuildRole(this, { hoist });
} }
setPosition(position) { setPosition(position) {
return this.client.rest.methods.UpdateGuildRole(this, {position,}); return this.client.rest.methods.updateGuildRole(this, { position });
} }
setPermissions(permissions) { setPermissions(permissions) {
return this.client.rest.methods.UpdateGuildRole(this, {permissions,}); return this.client.rest.methods.updateGuildRole(this, { permissions });
} }
serialize() { serialize() {
let serializedPermissions = {}; const serializedPermissions = {};
for (let permissionName in Constants.PermissionFlags) { for (const permissionName in Constants.PermissionFlags) {
serializedPermissions[permissionName] = this.hasPermission(permissionName); serializedPermissions[permissionName] = this.hasPermission(permissionName);
} }
return serializedPermissions; return serializedPermissions;
} }
hasPermission(permission, explicit) { hasPermission(permission, explicit) {
if (permission instanceof String || typeof permission === 'string') { if (permission instanceof String || typeof permission === 'string') {
permission = Constants.PermissionFlags[permission]; permission = Constants.PermissionFlags[permission];
} }
if (!permission) { if (!permission) {
throw Constants.Errors.NOT_A_PERMISSION; throw Constants.Errors.NOT_A_PERMISSION;
} }
if (!explicit) { if (!explicit) {
if ((this.permissions & Constants.PermissionFlags.ADMINISTRATOR) > 0) { if ((this.permissions & Constants.PermissionFlags.ADMINISTRATOR) > 0) {
return true; return true;
} }
} }
return ((this.permissions & permission) > 0); return ((this.permissions & permission) > 0);
} }
} }
module.exports = Role; module.exports = Role;

View File

@@ -1,151 +1,149 @@
'use strict';
const Channel = require('./Channel'); const Channel = require('./Channel');
const PermissionOverwrites = require('./PermissionOverwrites'); const PermissionOverwrites = require('./PermissionOverwrites');
const EvaluatedPermissions = require('./EvaluatedPermissions'); const EvaluatedPermissions = require('./EvaluatedPermissions');
const Constants = require('../util/Constants'); const Constants = require('../util/Constants');
function arraysEqual(a, b) { function arraysEqual(a, b) {
if (a === b) return true; if (a === b) return true;
if (a.length !== b.length) return false; if (a.length !== b.length) return false;
for (let itemInd in a) { for (const itemInd in a) {
let item = a[itemInd]; const item = a[itemInd];
let ind = b.indexOf(item); const ind = b.indexOf(item);
if (ind) { if (ind) {
b.splice(ind, 1); b.splice(ind, 1);
} }
} }
return b.length === 0; return b.length === 0;
} }
class ServerChannel extends Channel{ class ServerChannel extends Channel {
constructor(guild, data) { constructor(guild, data) {
super(guild.client, data, guild); super(guild.client, data, guild);
} }
setup(data) { setup(data) {
super.setup(data); super.setup(data);
this.type = data.type; this.type = data.type;
this.topic = data.topic; this.topic = data.topic;
this.position = data.position; this.position = data.position;
this.name = data.name; this.name = data.name;
this.lastMessageID = data.last_message_id; this.lastMessageID = data.last_message_id;
this.ow = data.permission_overwrites; this.ow = data.permission_overwrites;
this.permissionOverwrites = []; this.permissionOverwrites = [];
if (data.permission_overwrites) { if (data.permission_overwrites) {
for (let overwrite of data.permission_overwrites) { for (const overwrite of data.permission_overwrites) {
this.permissionOverwrites.push(new PermissionOverwrites(this, overwrite)); this.permissionOverwrites.push(new PermissionOverwrites(this, overwrite));
} }
} }
} }
equals(other) { equals(other) {
let base = ( let base = (
this.type === other.type && this.type === other.type &&
this.topic === other.topic && this.topic === other.topic &&
this.position === other.position && this.position === other.position &&
this.name === other.name && this.name === other.name &&
this.id === other.id this.id === other.id
); );
if (base) { if (base) {
if (other.permission_overwrites) { if (other.permission_overwrites) {
let thisIDSet = this.permissionOverwrites.map(overwrite => overwrite.id); const thisIDSet = this.permissionOverwrites.map(overwrite => overwrite.id);
let otherIDSet = other.permission_overwrites.map(overwrite => overwrite.id); const otherIDSet = other.permission_overwrites.map(overwrite => overwrite.id);
if (arraysEqual(thisIDSet, otherIDSet)) { if (arraysEqual(thisIDSet, otherIDSet)) {
base = true; base = true;
} else { } else {
base = false; base = false;
} }
} else { } else {
base = false; base = false;
} }
} }
return base; return base;
} }
permissionsFor(member) { permissionsFor(member) {
member = this.client.resolver.ResolveGuildMember(this.guild, member); member = this.client.resolver.resolveGuildMember(this.guild, member);
if (member) { if (member) {
if (this.guild.owner.id === member.id) { if (this.guild.owner.id === member.id) {
return new EvaluatedPermissions(member, Constants.ALL_PERMISSIONS); return new EvaluatedPermissions(member, Constants.ALL_PERMISSIONS);
} }
let roles = member.roles; const roles = member.roles;
let permissions = 0; let permissions = 0;
let overwrites = this.overwritesFor(member, true); const overwrites = this.overwritesFor(member, true);
for (let role of roles) { for (const role of roles) {
permissions |= role.permissions; permissions |= role.permissions;
} }
for (let overwrite of overwrites.role.concat(overwrites.member)) { for (const overwrite of overwrites.role.concat(overwrites.member)) {
permissions = permissions & ~overwrite.denyData; permissions &= ~overwrite.denyData;
permissions = permissions | overwrite.allowData; permissions |= overwrite.allowData;
} }
if (!!(permissions & (Constants.PermissionFlags.MANAGE_ROLES))) { const admin = Boolean(permissions & (Constants.PermissionFlags.MANAGE_ROLES));
permissions = Constants.ALL_PERMISSIONS; if (admin) {
} permissions = Constants.ALL_PERMISSIONS;
}
return new EvaluatedPermissions(member, permissions); return new EvaluatedPermissions(member, permissions);
} }
} return null;
}
overwritesFor(member, verified) { overwritesFor(member, verified) {
// for speed // for speed
if (!verified) if (!verified) member = this.client.resolver.resolveGuildMember(this.guild, member);
member = this.client.resolver.ResolveGuildMember(this.guild, member); if (member) {
if (member) { const memberRoles = member._roles;
let found = [];
let memberRoles = member._roles;
let roleOverwrites = []; const roleOverwrites = [];
let memberOverwrites = []; const memberOverwrites = [];
for (let overwrite of this.permissionOverwrites) { for (const overwrite of this.permissionOverwrites) {
if (overwrite.id === member.id) { if (overwrite.id === member.id) {
memberOverwrites.push(overwrite); memberOverwrites.push(overwrite);
} else if (memberRoles.indexOf(overwrite.id) > -1) { } else if (memberRoles.indexOf(overwrite.id) > -1) {
roleOverwrites.push(overwrite); roleOverwrites.push(overwrite);
} }
} }
return { return {
role: roleOverwrites, role: roleOverwrites,
member: memberOverwrites, member: memberOverwrites,
}; };
} }
return []; return [];
} }
edit(data) { edit(data) {
return this.client.rest.methods.UpdateChannel(this, data); return this.client.rest.methods.updateChannel(this, data);
} }
setName(name) { setName(name) {
return this.client.rest.methods.UpdateChannel(this, { name, }); return this.client.rest.methods.updateChannel(this, { name });
} }
setPosition(position) { setPosition(position) {
return this.rest.client.rest.methods.UpdateChannel(this, { position, }); return this.rest.client.rest.methods.updateChannel(this, { position });
} }
setTopic(topic) { setTopic(topic) {
return this.rest.client.rest.methods.UpdateChannel(this, { topic, }); return this.rest.client.rest.methods.updateChannel(this, { topic });
} }
setBitrate() { setBitrate(bitrate) {
return this.rest.client.rest.methods.UpdateChannel(this, { bitrate, }); return this.rest.client.rest.methods.updateChannel(this, { bitrate });
} }
toString() { toString() {
return this.name; return this.name;
} }
} }
module.exports = ServerChannel; module.exports = ServerChannel;

View File

@@ -1,30 +1,28 @@
'use strict';
const ServerChannel = require('./ServerChannel'); const ServerChannel = require('./ServerChannel');
const TextChannelDataStore = require('./datastore/TextChannelDataStore'); const TextChannelDataStore = require('./datastore/TextChannelDataStore');
const TextBasedChannel = require('./interface/TextBasedChannel'); const TextBasedChannel = require('./interface/TextBasedChannel');
class TextChannel extends ServerChannel { class TextChannel extends ServerChannel {
constructor(guild, data) { constructor(guild, data) {
super(guild, data); super(guild, data);
this.store = new TextChannelDataStore(); this.store = new TextChannelDataStore();
} }
_cacheMessage(message) { _cacheMessage(message) {
let maxSize = this.client.options.max_message_cache; const maxSize = this.client.options.max_message_cache;
if (maxSize === 0) { if (maxSize === 0) {
// saves on performance // saves on performance
return; return null;
} }
let storeKeys = Object.keys(this.store); const storeKeys = Object.keys(this.store);
if (storeKeys.length >= maxSize) { if (storeKeys.length >= maxSize) {
this.store.remove(storeKeys[0]); this.store.remove(storeKeys[0]);
} }
return this.store.add('messages', message); return this.store.add('messages', message);
} }
} }
TextBasedChannel.applyToClass(TextChannel); TextBasedChannel.applyToClass(TextChannel);

View File

@@ -1,89 +1,87 @@
'use strict';
const TextBasedChannel = require('./interface/TextBasedChannel'); const TextBasedChannel = require('./interface/TextBasedChannel');
/** /**
* Represents a User on Discord. * Represents a User on Discord.
*/ */
class User { class User {
constructor(client, data) { constructor(client, data) {
this.client = client; this.client = client;
if (data) { if (data) {
this.setup(data); this.setup(data);
} }
} }
setup(data) { setup(data) {
/** /**
* The username of the User * The username of the User
* @type {String} * @type {String}
*/ */
this.username = data.username; this.username = data.username;
/** /**
* The ID of the User * The ID of the User
* @type {String} * @type {String}
*/ */
this.id = data.id; this.id = data.id;
/** /**
* A discriminator based on username for the User * A discriminator based on username for the User
* @type {String} * @type {String}
*/ */
this.discriminator = data.discriminator; this.discriminator = data.discriminator;
/** /**
* The ID of the user's avatar * The ID of the user's avatar
* @type {String} * @type {String}
*/ */
this.avatar = data.avatar; this.avatar = data.avatar;
/** /**
* Whether or not the User is a Bot. * Whether or not the User is a Bot.
* @type {Boolean} * @type {Boolean}
*/ */
this.bot = Boolean(data.bot); this.bot = Boolean(data.bot);
/** /**
* The status of the user: * The status of the user:
* *
* * **`online`** - user is online * * **`online`** - user is online
* * **`offline`** - user is offline * * **`offline`** - user is offline
* * **`idle`** - user is AFK * * **`idle`** - user is AFK
* @type {String} * @type {String}
*/ */
this.status = data.status || this.status || 'offline'; this.status = data.status || this.status || 'offline';
this.game = data.game || this.game; this.game = data.game || this.game;
} }
toString() { toString() {
return `<@${this.id}>`; return `<@${this.id}>`;
} }
/** /**
* Deletes a DM Channel (if one exists) between the Client and the User. Resolves with the Channel if successful. * Deletes a DM Channel (if one exists) between the Client and the User. Resolves with the Channel if successful.
* @return {Promise<DMChannel>} * @return {Promise<DMChannel>}
*/ */
deleteDM() { deleteDM() {
return this.client.rest.methods.DeleteChannel(this); return this.client.rest.methods.deleteChannel(this);
} }
equals(user) { equals(user) {
let base = ( let base = (
this.username === user.username && this.username === user.username &&
this.id === user.id && this.id === user.id &&
this.discriminator === user.discriminator && this.discriminator === user.discriminator &&
this.avatar === user.avatar && this.avatar === user.avatar &&
this.bot === Boolean(user.bot) this.bot === Boolean(user.bot)
); );
if (base) { if (base) {
if (user.status) { if (user.status) {
base = this.status === user.status; base = this.status === user.status;
} }
if (user.game) { if (user.game) {
base = this.game === user.game; base = this.game === user.game;
} }
} }
return base; return base;
} }
} }
TextBasedChannel.applyToClass(User); TextBasedChannel.applyToClass(User);

View File

@@ -1,18 +1,16 @@
'use strict';
const ServerChannel = require('./ServerChannel'); const ServerChannel = require('./ServerChannel');
const VoiceChannelDataStore = require('./datastore/VoiceChannelDataStore'); const VoiceChannelDataStore = require('./datastore/VoiceChannelDataStore');
class VoiceChannel extends ServerChannel { class VoiceChannel extends ServerChannel {
constructor(guild, data) { constructor(guild, data) {
super(guild, data); super(guild, data);
this.store = new VoiceChannelDataStore(); this.store = new VoiceChannelDataStore();
} }
setup(data) { setup(data) {
super.setup(data); super.setup(data);
this.bitrate = data.bitrate; this.bitrate = data.bitrate;
} }
} }
module.exports = VoiceChannel; module.exports = VoiceChannel;

View File

@@ -1,43 +1,40 @@
'use strict'; class AbstractDataStore {
constructor() {
this.data = {};
}
class AbstractDataStore{ register(name) {
constructor() { this.data[name] = {};
this.data = {}; }
}
register(name) { add(location, object) {
this.data[name] = {}; if (this.data[location][object.id]) {
} return this.data[location][object.id];
}
this.data[location][object.id] = object;
return object;
}
add(location, object) { clear(location) {
if (this.data[location][object.id]) { this.data[location] = {};
return this.data[location][object.id]; }
} else {
return this.data[location][object.id] = object;
}
}
clear(location) { remove(location, object) {
this.data[location] = {}; const id = (typeof object === 'string' || object instanceof String) ? object : object.id;
} if (this.data[location][id]) {
delete this.data[location][id];
return true;
}
return false;
}
remove(location, object) { get(location, value) {
let id = (typeof object === 'string' || object instanceof String) ? object : object.id; return this.data[location][value];
if (this.data[location][id]) { }
delete this.data[location][id];
return true;
} else {
return false;
}
}
get(location, value) { getAsArray(location) {
return this.data[location][value]; return Object.values(this.data[location]);
} }
getAsArray(location) {
return Object.values(this.data[location]);
}
} }
module.exports = AbstractDataStore; module.exports = AbstractDataStore;

View File

@@ -1,8 +1,6 @@
'use strict';
const AbstractDataStore = require('./AbstractDataStore'); const AbstractDataStore = require('./AbstractDataStore');
const Constants = require('../../util/Constants'); const Constants = require('../../util/Constants');
const CloneObject = require('../../util/CloneObject'); const cloneObject = require('../../util/CloneObject');
const Guild = require('../Guild'); const Guild = require('../Guild');
const User = require('../User'); const User = require('../User');
const DMChannel = require('../DMChannel'); const DMChannel = require('../DMChannel');
@@ -10,98 +8,99 @@ const TextChannel = require('../TextChannel');
const VoiceChannel = require('../VoiceChannel'); const VoiceChannel = require('../VoiceChannel');
const ServerChannel = require('../ServerChannel'); const ServerChannel = require('../ServerChannel');
class ClientDataStore extends AbstractDataStore{ class ClientDataStore extends AbstractDataStore {
constructor(client) { constructor(client) {
super(); super();
this.client = client; this.client = client;
this.token = null; this.token = null;
this.session = null; this.session = null;
this.user = null; this.user = null;
this.email = null; this.email = null;
this.password = null; this.password = null;
this.register('users'); this.register('users');
this.register('guilds'); this.register('guilds');
this.register('channels'); this.register('channels');
} }
get pastReady() { get pastReady() {
return this.client.ws.status === Constants.Status.READY; return this.client.ws.status === Constants.Status.READY;
} }
NewGuild(data) { newGuild(data) {
let already = this.get('guilds', data.id); const already = this.get('guilds', data.id);
let guild = this.add('guilds', new Guild(this.client, data)); const guild = this.add('guilds', new Guild(this.client, data));
if (this.pastReady && !already) { if (this.pastReady && !already) {
this.client.emit(Constants.Events.GUILD_CREATE, guild); this.client.emit(Constants.Events.GUILD_CREATE, guild);
} }
return guild; return guild;
} }
NewUser(data) { newUser(data) {
return this.add('users', new User(this.client, data)); return this.add('users', new User(this.client, data));
} }
NewChannel(data, guild) { newChannel(data, $guild) {
let already = this.get('channels', data.id); let guild = $guild;
let channel; const already = this.get('channels', data.id);
if (data.is_private) { let channel;
channel = new DMChannel(this.client, data); if (data.is_private) {
}else { channel = new DMChannel(this.client, data);
guild = guild || this.get('guilds', data.guild_id); } else {
if (guild) { guild = guild || this.get('guilds', data.guild_id);
if (data.type === 'text') { if (guild) {
channel = new TextChannel(guild, data); if (data.type === 'text') {
guild.store.add('channels', channel); channel = new TextChannel(guild, data);
}else if (data.type === 'voice') { guild.store.add('channels', channel);
channel = new VoiceChannel(guild, data); } else if (data.type === 'voice') {
guild.store.add('channels', channel); channel = new VoiceChannel(guild, data);
} guild.store.add('channels', channel);
} }
} }
}
if (channel) { if (channel) {
if (this.pastReady && !already) { if (this.pastReady && !already) {
this.client.emit(Constants.Events.CHANNEL_CREATE, channel); this.client.emit(Constants.Events.CHANNEL_CREATE, channel);
} }
return this.add('channels', channel); return this.add('channels', channel);
} }
} return null;
}
KillGuild(guild) { killGuild(guild) {
let already = this.get('guilds', guilds.id); const already = this.get('guilds', guild.id);
this.remove('guilds', guild); this.remove('guilds', guild);
if (already && this.pastReady) { if (already && this.pastReady) {
this.client.emit(Constants.Events.GUILD_DELETE, guild); this.client.emit(Constants.Events.GUILD_DELETE, guild);
} }
} }
KillUser(user) { killUser(user) {
this.remove('users', user); this.remove('users', user);
} }
KillChannel(channel) { killChannel(channel) {
this.remove('channels', channel); this.remove('channels', channel);
if (channel instanceof ServerChannel) { if (channel instanceof ServerChannel) {
channel.guild.store.remove('channels', channel); channel.guild.store.remove('channels', channel);
} }
} }
UpdateGuild(currentGuild, newData) { updateGuild(currentGuild, newData) {
let oldGuild = CloneObject(currentGuild); const oldGuild = cloneObject(currentGuild);
currentGuild.setup(newData); currentGuild.setup(newData);
if (this.pastReady) { if (this.pastReady) {
this.client.emit(Constants.Events.GUILD_UPDATE, oldGuild, currentGuild); this.client.emit(Constants.Events.GUILD_UPDATE, oldGuild, currentGuild);
} }
} }
UpdateChannel(currentChannel, newData) { updateChannel(currentChannel, newData) {
let oldChannel = CloneObject(currentChannel); currentChannel.setup(newData);
currentChannel.setup(newData); }
}
} }
module.exports = ClientDataStore; module.exports = ClientDataStore;

View File

@@ -1,14 +1,12 @@
'use strict';
const AbstractDataStore = require('./AbstractDataStore'); const AbstractDataStore = require('./AbstractDataStore');
class GuildDataStore extends AbstractDataStore{ class GuildDataStore extends AbstractDataStore {
constructor() { constructor() {
super(); super();
this.register('members'); this.register('members');
this.register('channels'); this.register('channels');
} }
} }
module.exports = GuildDataStore; module.exports = GuildDataStore;

View File

@@ -1,12 +1,10 @@
'use strict';
const AbstractDataStore = require('./AbstractDataStore'); const AbstractDataStore = require('./AbstractDataStore');
class TextChannelDataStore extends AbstractDataStore{ class TextChannelDataStore extends AbstractDataStore {
constructor() { constructor() {
super(); super();
this.register('messages'); this.register('messages');
} }
} }
module.exports = TextChannelDataStore; module.exports = TextChannelDataStore;

View File

@@ -1,12 +1,10 @@
'use strict';
const AbstractDataStore = require('./AbstractDataStore'); const AbstractDataStore = require('./AbstractDataStore');
class VoiceChannelDataStore extends AbstractDataStore{ class VoiceChannelDataStore extends AbstractDataStore {
constructor() { constructor() {
super(); super();
this.register('members'); this.register('members');
} }
} }
module.exports = VoiceChannelDataStore; module.exports = VoiceChannelDataStore;

View File

@@ -1,14 +1,12 @@
'use strict';
const AbstractDataStore = require('./AbstractDataStore'); const AbstractDataStore = require('./AbstractDataStore');
class WebSocketManagerDataStore extends AbstractDataStore{ class WebSocketManagerDataStore extends AbstractDataStore {
constructor() { constructor() {
super(); super();
this.sessionID = null; this.sessionID = null;
this.sequence = -1; this.sequence = -1;
this.gateway = null; this.gateway = null;
} }
} }
module.exports = WebSocketManagerDataStore; module.exports = WebSocketManagerDataStore;

View File

@@ -1,15 +1,12 @@
'use strict'; function sendMessage(content, options = {}) {
return this.client.rest.methods.sendMessage(this, content, options.tts);
function sendMessage(content, options) {
options = options || {};
return this.client.rest.methods.SendMessage(this, content, options.tts);
} }
function sendTTSMessage(content, options) { function sendTTSMessage(content) {
options = options || {}; return this.client.rest.methods.sendMessage(this, content, true);
return this.client.rest.methods.SendMessage(this, content, true);
} }
exports.applyToClass = structure => { exports.applyToClass = structure => {
structure.prototype.sendMessage = sendMessage; structure.prototype.sendMessage = sendMessage;
structure.prototype.sendTTSMessage = sendTTSMessage;
}; };

View File

@@ -1,7 +1,6 @@
'use strict'; module.exports = function cloneObject(obj) {
module.exports = function CloneObject(obj) { const cloned = Object.create(obj);
var cloned = Object.create(obj); Object.assign(cloned, obj);
Object.assign(cloned, obj);
return cloned; return cloned;
}; };

View File

@@ -1,184 +1,182 @@
'use strict'; exports.DefaultOptions = {
ws: {
const DefaultOptions = exports.DefaultOptions = { large_threshold: 250,
ws: { compress: true,
large_threshold: 250, properties: {
compress: true, $os: process ? process.platform : 'discord.js',
properties: { $browser: 'discord.js',
$os: process ? process.platform : 'discord.js', $device: 'discord.js',
$browser: 'discord.js', $referrer: '',
$device: 'discord.js', $referring_domain: '',
$referrer: '', },
$referring_domain: '', },
}, protocol_version: 4,
}, max_message_cache: 200,
protocol_version: 4, rest_ws_bridge_timeout: 5000,
max_message_cache: 200,
rest_ws_bridge_timeout: 5000,
}; };
const Status = exports.Status = { exports.Status = {
READY: 0, READY: 0,
CONNECTING: 1, CONNECTING: 1,
RECONNECTING: 2, RECONNECTING: 2,
IDLE: 3, IDLE: 3,
}; };
const Package = exports.Package = require('../../package.json'); exports.Package = require('../../package.json');
const Errors = exports.Errors = { exports.Errors = {
NO_TOKEN: new Error('request to use token, but token was unavailable to the client'), NO_TOKEN: new Error('request to use token, but token was unavailable to the client'),
NO_BOT_ACCOUNT: new Error('you should ideally be using a bot account!'), NO_BOT_ACCOUNT: new Error('you should ideally be using a bot account!'),
BAD_WS_MESSAGE: new Error('a bad message was received from the websocket - bad compression or not json'), BAD_WS_MESSAGE: new Error('a bad message was received from the websocket - bad compression or not json'),
TOOK_TOO_LONG: new Error('something took too long to do'), TOOK_TOO_LONG: new Error('something took too long to do'),
NOT_A_PERMISSION: new Error('that is not a valid permission number'), NOT_A_PERMISSION: new Error('that is not a valid permission number'),
}; };
const API = 'https://discordapp.com/api'; const API = 'https://discordapp.com/api';
const Endpoints = exports.Endpoints = { const Endpoints = exports.Endpoints = {
// general endpoints // general endpoints
LOGIN: `${API}/auth/login`, login: `${API}/auth/login`,
LOGOUT: `${API}/auth/logout`, logout: `${API}/auth/logout`,
ME: `${API}/users/@me`, me: `${API}/users/@me`,
ME_GUILD: (guildID) => `${Endpoints.ME}/guilds/${guildID}`, meGuild: (guildID) => `${Endpoints.me}/guilds/${guildID}`,
GATEWAY: `${API}/gateway`, gateway: `${API}/gateway`,
USER_CHANNELS: (userID) => `${API}/users/${userID}/channels`, userChannels: (userID) => `${API}/users/${userID}/channels`,
AVATAR: (userID, avatar) => `${API}/users/${userID}/avatars/${avatar}.jpg`, avatar: (userID, avatar) => `${API}/users/${userID}/avatars/${avatar}.jpg`,
INVITE: (id) => `${API}/invite/${id}`, invite: (id) => `${API}/invite/${id}`,
// guilds // guilds
GUILDS: `${API}/guilds`, guilds: `${API}/guilds`,
GUILD: (guildID) => `${Endpoints.GUILDS}/${guildID}`, guild: (guildID) => `${Endpoints.guilds}/${guildID}`,
GUILD_ICON: (guildID, hash) => `${Endpoints.GUILD(guildID)}/icons/${hash}.jpg`, guildIcon: (guildID, hash) => `${Endpoints.guild(guildID)}/icons/${hash}.jpg`,
GUILD_PRUNE: (guildID) => `${Endpoints.GUILD(guildID)}/prune`, guildPrune: (guildID) => `${Endpoints.guild(guildID)}/prune`,
GUILD_EMBED: (guildID) => `${Endpoints.GUILD(guildID)}/embed`, guildEmbed: (guildID) => `${Endpoints.guild(guildID)}/embed`,
GUILD_INVITES: (guildID) => `${Endpoints.GUILD(guildID)}/invites`, guildInvites: (guildID) => `${Endpoints.guild(guildID)}/invites`,
GUILD_ROLES: (guildID) => `${Endpoints.GUILD(guildID)}/roles`, guildRoles: (guildID) => `${Endpoints.guild(guildID)}/roles`,
GUILD_ROLE: (guildID, roleID) => `${Endpoints.GUILD_ROLES(guildID)}/${roleID}`, guildRole: (guildID, roleID) => `${Endpoints.guildRoles(guildID)}/${roleID}`,
GUILD_BANS: (guildID) => `${Endpoints.GUILD(guildID)}/bans`, guildBans: (guildID) => `${Endpoints.guild(guildID)}/bans`,
GUILD_INTEGRATIONS: (guildID) => `${Endpoints.GUILD(guildID)}/integrations`, guildIntegrations: (guildID) => `${Endpoints.guild(guildID)}/integrations`,
GUILD_MEMBERS: (guildID) => `${Endpoints.GUILD(guildID)}/members`, guildMembers: (guildID) => `${Endpoints.guild(guildID)}/members`,
GUILD_MEMBER: (guildID, memberID) => `${Endpoints.GUILD_MEMBERS(guildID)}/${memberID}`, guildMember: (guildID, memberID) => `${Endpoints.guildMembers(guildID)}/${memberID}`,
GUILD_CHANNELS: (guildID) => `${Endpoints.GUILD(guildID)}/channels`, guildChannels: (guildID) => `${Endpoints.guild(guildID)}/channels`,
// channels // channels
CHANNELS: `${API}/channels`, channels: `${API}/channels`,
CHANNEL: (channelID) => `${Endpoints.CHANNELS}/${channelID}`, channel: (channelID) => `${Endpoints.channels}/${channelID}`,
CHANNEL_MESSAGES: (channelID) => `${Endpoints.CHANNEL(channelID)}/messages`, channelMessages: (channelID) => `${Endpoints.channel(channelID)}/messages`,
CHANNEL_INVITES: (channelID) => `${Endpoints.CHANNEL(channelID)}/invites`, channelInvites: (channelID) => `${Endpoints.channel(channelID)}/invites`,
CHANNEL_TYPING: (channelID) => `${Endpoints.CHANNEL(channelID)}/typing`, channelTyping: (channelID) => `${Endpoints.channel(channelID)}/typing`,
CHANNEL_PERMISSIONS: (channelID) => `${Endpoints.CHANNEL(channelID)}/permissions`, channelPermissions: (channelID) => `${Endpoints.channel(channelID)}/permissions`,
CHANNEL_MESSAGE: (channelID, messageID) => `${Endpoints.CHANNEL_MESSAGES(channelID)}/${messageID}`, channelMessage: (channelID, messageID) => `${Endpoints.channelMessage(channelID)}/${messageID}`,
}; };
const OPCodes = exports.OPCodes = { exports.OPCodes = {
DISPATCH: 0, DISPATCH: 0,
HEARTBEAT: 1, HEARTBEAT: 1,
IDENTIFY: 2, IDENTIFY: 2,
STATUS_UPDATE: 3, STATUS_UPDATE: 3,
VOICE_STATE_UPDATE: 4, VOICE_STATE_UPDATE: 4,
VOICE_GUILD_PING: 5, VOICE_GUILD_PING: 5,
RESUME: 6, RESUME: 6,
RECONNECT: 7, RECONNECT: 7,
REQUEST_GUILD_MEMBERS: 8, REQUEST_GUILD_MEMBERS: 8,
INVALID_SESSION: 9, INVALID_SESSION: 9,
}; };
const Events = exports.Events = { exports.Events = {
READY: 'ready', READY: 'ready',
GUILD_CREATE: 'guildCreate', GUILD_CREATE: 'guildCreate',
GUILD_DELETE: 'guildDelete', GUILD_DELETE: 'guildDelete',
GUILD_UNAVAILABLE: 'guildUnavailable', GUILD_UNAVAILABLE: 'guildUnavailable',
GUILD_AVAILABLE: 'guildAvailable', GUILD_AVAILABLE: 'guildAvailable',
GUILD_UPDATE: 'guildUpdate', GUILD_UPDATE: 'guildUpdate',
GUILD_BAN_ADD: 'guildBanAdd', GUILD_BAN_ADD: 'guildBanAdd',
GUILD_BAN_REMOVE: 'guildBanRemove', GUILD_BAN_REMOVE: 'guildBanRemove',
GUILD_MEMBER_ADD: 'guildMemberAdd', GUILD_MEMBER_ADD: 'guildMemberAdd',
GUILD_MEMBER_REMOVE: 'guildMemberRemove', GUILD_MEMBER_REMOVE: 'guildMemberRemove',
GUILD_MEMBER_ROLES_UPDATE: 'guildMemberRolesUpdate', GUILD_MEMBER_ROLES_UPDATE: 'guildMemberRolesUpdate',
GUILD_ROLE_CREATE: 'guildRoleCreate', GUILD_ROLE_CREATE: 'guildRoleCreate',
GUILD_ROLE_DELETE: 'guildRoleDelete', GUILD_ROLE_DELETE: 'guildRoleDelete',
GUILD_ROLE_UPDATE: 'guildRoleUpdate', GUILD_ROLE_UPDATE: 'guildRoleUpdate',
GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable', GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable',
CHANNEL_CREATE: 'channelCreate', CHANNEL_CREATE: 'channelCreate',
CHANNEL_DELETE: 'channelDelete', CHANNEL_DELETE: 'channelDelete',
CHANNEL_UPDATE: 'channelUpdate', CHANNEL_UPDATE: 'channelUpdate',
PRESENCE_UPDATE: 'presenceUpdate', PRESENCE_UPDATE: 'presenceUpdate',
USER_UPDATE: 'userUpdate', USER_UPDATE: 'userUpdate',
VOICE_STATE_UPDATE: 'voiceStateUpdate', VOICE_STATE_UPDATE: 'voiceStateUpdate',
TYPING_START: 'typingStart', TYPING_START: 'typingStart',
TYPING_STOP: 'typingStop', TYPING_STOP: 'typingStop',
WARN: 'warn', WARN: 'warn',
GUILD_MEMBERS_CHUNK: 'guildMembersChunk', GUILD_MEMBERS_CHUNK: 'guildMembersChunk',
MESSAGE_CREATE: 'message', MESSAGE_CREATE: 'message',
MESSAGE_DELETE: 'messageDelete', MESSAGE_DELETE: 'messageDelete',
MESSAGE_UPDATE: 'messageUpdate', MESSAGE_UPDATE: 'messageUpdate',
}; };
const WSEvents = exports.WSEvents = { exports.WSEvents = {
CHANNEL_CREATE: 'CHANNEL_CREATE', CHANNEL_CREATE: 'CHANNEL_CREATE',
CHANNEL_DELETE: 'CHANNEL_DELETE', CHANNEL_DELETE: 'CHANNEL_DELETE',
CHANNEL_UPDATE: 'CHANNEL_UPDATE', CHANNEL_UPDATE: 'CHANNEL_UPDATE',
MESSAGE_CREATE: 'MESSAGE_CREATE', MESSAGE_CREATE: 'MESSAGE_CREATE',
MESSAGE_DELETE: 'MESSAGE_DELETE', MESSAGE_DELETE: 'MESSAGE_DELETE',
MESSAGE_UPDATE: 'MESSAGE_UPDATE', MESSAGE_UPDATE: 'MESSAGE_UPDATE',
PRESENCE_UPDATE: 'PRESENCE_UPDATE', PRESENCE_UPDATE: 'PRESENCE_UPDATE',
READY: 'READY', READY: 'READY',
GUILD_BAN_ADD: 'GUILD_BAN_ADD', GUILD_BAN_ADD: 'GUILD_BAN_ADD',
GUILD_BAN_REMOVE: 'GUILD_BAN_REMOVE', GUILD_BAN_REMOVE: 'GUILD_BAN_REMOVE',
GUILD_CREATE: 'GUILD_CREATE', GUILD_CREATE: 'GUILD_CREATE',
GUILD_DELETE: 'GUILD_DELETE', GUILD_DELETE: 'GUILD_DELETE',
GUILD_MEMBER_ADD: 'GUILD_MEMBER_ADD', GUILD_MEMBER_ADD: 'GUILD_MEMBER_ADD',
GUILD_MEMBER_REMOVE: 'GUILD_MEMBER_REMOVE', GUILD_MEMBER_REMOVE: 'GUILD_MEMBER_REMOVE',
GUILD_MEMBER_UPDATE: 'GUILD_MEMBER_UPDATE', GUILD_MEMBER_UPDATE: 'GUILD_MEMBER_UPDATE',
GUILD_MEMBERS_CHUNK: 'GUILD_MEMBERS_CHUNK', GUILD_MEMBERS_CHUNK: 'GUILD_MEMBERS_CHUNK',
GUILD_ROLE_CREATE: 'GUILD_ROLE_CREATE', GUILD_ROLE_CREATE: 'GUILD_ROLE_CREATE',
GUILD_ROLE_DELETE: 'GUILD_ROLE_DELETE', GUILD_ROLE_DELETE: 'GUILD_ROLE_DELETE',
GUILD_ROLE_UPDATE: 'GUILD_ROLE_UPDATE', GUILD_ROLE_UPDATE: 'GUILD_ROLE_UPDATE',
GUILD_UPDATE: 'GUILD_UPDATE', GUILD_UPDATE: 'GUILD_UPDATE',
TYPING_START: 'TYPING_START', TYPING_START: 'TYPING_START',
USER_UPDATE: 'USER_UPDATE', USER_UPDATE: 'USER_UPDATE',
VOICE_STATE_UPDATE: 'VOICE_STATE_UPDATE', VOICE_STATE_UPDATE: 'VOICE_STATE_UPDATE',
FRIEND_ADD: 'RELATIONSHIP_ADD', FRIEND_ADD: 'RELATIONSHIP_ADD',
FRIEND_REMOVE: 'RELATIONSHIP_REMOVE', FRIEND_REMOVE: 'RELATIONSHIP_REMOVE',
}; };
const PermissionFlags = exports.PermissionFlags = { const PermissionFlags = exports.PermissionFlags = {
CREATE_INSTANT_INVITE: 1 << 0, CREATE_INSTANT_INVITE: 1 << 0,
KICK_MEMBERS: 1 << 1, KICK_MEMBERS: 1 << 1,
BAN_MEMBERS: 1 << 2, BAN_MEMBERS: 1 << 2,
ADMINISTRATOR: 1 << 3, ADMINISTRATOR: 1 << 3,
MANAGE_CHANNELS: 1 << 4, MANAGE_CHANNELS: 1 << 4,
MANAGE_GUILD: 1 << 5, MANAGE_GUILD: 1 << 5,
READ_MESSAGES: 1 << 10, READ_MESSAGES: 1 << 10,
SEND_MESSAGES: 1 << 11, SEND_MESSAGES: 1 << 11,
SEND_TTS_MESSAGES: 1 << 12, SEND_TTS_MESSAGES: 1 << 12,
MANAGE_MESSAGES: 1 << 13, MANAGE_MESSAGES: 1 << 13,
EMBED_LINKS: 1 << 14, EMBED_LINKS: 1 << 14,
ATTACH_FILES: 1 << 15, ATTACH_FILES: 1 << 15,
READ_MESSAGE_HISTORY: 1 << 16, READ_MESSAGE_HISTORY: 1 << 16,
MENTION_EVERYONE: 1 << 17, MENTION_EVERYONE: 1 << 17,
CONNECT: 1 << 20, CONNECT: 1 << 20,
SPEAK: 1 << 21, SPEAK: 1 << 21,
MUTE_MEMBERS: 1 << 22, MUTE_MEMBERS: 1 << 22,
DEAFEN_MEMBERS: 1 << 23, DEAFEN_MEMBERS: 1 << 23,
MOVE_MEMBERS: 1 << 24, MOVE_MEMBERS: 1 << 24,
USE_VAD: 1 << 25, USE_VAD: 1 << 25,
CHANGE_NICKNAME: 1 << 26, CHANGE_NICKNAME: 1 << 26,
MANAGE_NICKNAMES: 1 << 27, MANAGE_NICKNAMES: 1 << 27,
MANAGE_ROLES_OR_PERMISSIONS: 1 << 28, MANAGE_ROLES_OR_PERMISSIONS: 1 << 28,
}; };
let _ALL_PERMISSIONS = 0; let _ALL_PERMISSIONS = 0;
for (let key in PermissionFlags) { for (const key in PermissionFlags) {
_ALL_PERMISSIONS |= PermissionFlags[key]; _ALL_PERMISSIONS |= PermissionFlags[key];
} }
const ALL_PERMISSIONS = exports.ALL_PERMISSIONS = _ALL_PERMISSIONS; exports.ALL_PERMISSIONS = _ALL_PERMISSIONS;
const DEFAULT_PERMISSIONS = exports.DEFAULT_PERMISSIONS = 36953089; exports.DEFAULT_PERMISSIONS = 36953089;

View File

@@ -1,19 +1,17 @@
'use strict';
module.exports = function merge(def, given) { module.exports = function merge(def, given) {
if (!given) { if (!given) {
return def; return def;
} }
given = given || {}; given = given || {};
for (var key in def) { for (const key in def) {
if (!given.hasOwnProperty(key)) { if (!{}.hasOwnProperty.call(given, key)) {
given[key] = def[key]; given[key] = def[key];
} else if (given[key] === Object(given[key])) { } else if (given[key] === Object(given[key])) {
given[key] = merge(def[key], given[key]); given[key] = merge(def[key], given[key]);
} }
} }
return given; return given;
}; };

View File

@@ -3,172 +3,172 @@
const Discord = require('../'); const Discord = require('../');
const request = require('superagent'); const request = require('superagent');
let client = new Discord.Client(); const client = new Discord.Client();
client.login(require('./auth.json').token).then(token => console.log('logged in with token ' + token)).catch(console.log); client.login(require('./auth.json').token).then(token => console.log('logged in with token ' + token)).catch(console.log);
client.on('ready', () => { client.on('ready', () => {
console.log('ready!'); console.log('ready!');
}); });
client.on('guildCreate', (guild) => { client.on('guildCreate', (guild) => {
console.log(guild); console.log(guild);
}); });
client.on('guildDelete', (guild) => { client.on('guildDelete', (guild) => {
console.log('guilddel', guild.name); console.log('guilddel', guild.name);
}); });
client.on('guildUpdate', (old, guild) => { client.on('guildUpdate', (old, guild) => {
console.log('guildupdate', old.name, guild.name); console.log('guildupdate', old.name, guild.name);
}); });
client.on('channelCreate', channel => { client.on('channelCreate', channel => {
// console.log(channel); // console.log(channel);
}); });
client.on('channelDelete', channel => { client.on('channelDelete', channel => {
console.log('channDel', channel.name); console.log('channDel', channel.name);
}); });
client.on('channelUpdate', (old, chan) => { client.on('channelUpdate', (old, chan) => {
console.log('chan update', old.name, chan.name); console.log('chan update', old.name, chan.name);
}); });
client.on('guildMemberAdd', (guild, user) => { client.on('guildMemberAdd', (guild, user) => {
console.log('new guild member', user.user.username, 'in', guild.name); console.log('new guild member', user.user.username, 'in', guild.name);
}); });
client.on('guildMemberRemove', (guild, user) => { client.on('guildMemberRemove', (guild, user) => {
console.log('dead guild member', user.user.username, 'in', guild.name); console.log('dead guild member', user.user.username, 'in', guild.name);
}); });
client.on('guildRoleCreate', (guild, role) => { client.on('guildRoleCreate', (guild, role) => {
console.log('new role', role.name, 'in', guild.name); console.log('new role', role.name, 'in', guild.name);
role.edit({ role.edit({
permissions: ['DEAFEN_MEMBERS'], permissions: ['DEAFEN_MEMBERS'],
name: 'deafen' name: 'deafen',
}).then(role2 => { }).then(role2 => {
console.log('role replace from ' + role.name + ' to ' + role2.name); console.log('role replace from ' + role.name + ' to ' + role2.name);
}).catch(console.log) }).catch(console.log);
}); });
client.on('guildRoleDelete', (guild, role) => { client.on('guildRoleDelete', (guild, role) => {
console.log('dead role', role.name, 'in', guild.name); console.log('dead role', role.name, 'in', guild.name);
}); });
client.on('guildRoleUpdate', (guild, old, newRole) => { client.on('guildRoleUpdate', (guild, old, newRole) => {
console.log('updated role', old.name, 'to', newRole.name, 'in', guild.name); console.log('updated role', old.name, 'to', newRole.name, 'in', guild.name);
}); });
client.on('presenceUpdate', (oldUser, newUser) => { client.on('presenceUpdate', (oldUser, newUser) => {
// console.log('presence from', oldUser.username, 'to', newUser.username); // console.log('presence from', oldUser.username, 'to', newUser.username);
}); });
client.on('voiceStateUpdate', (oldMember, newMember) => { client.on('voiceStateUpdate', (oldMember, newMember) => {
console.log('voiceState', oldMember.user.username, oldMember.voiceChannel + '', newMember.voiceChannel + ''); console.log('voiceState', oldMember.user.username, oldMember.voiceChannel + '', newMember.voiceChannel + '');
}); });
client.on('typingStart.', (channel, user) => { client.on('typingStart.', (channel, user) => {
if (user.username === 'hydrabolt') if (user.username === 'hydrabolt')
console.log(user.username, 'started typing in', channel.name); console.log(user.username, 'started typing in', channel.name);
}); });
client.on('typingStop.', (channel, user, data) => { client.on('typingStop.', (channel, user, data) => {
if (user.username === 'hydrabolt') if (user.username === 'hydrabolt')
console.log(user.username, 'stopped typing in', channel.name, 'after', data.elapsedTime + 'ms'); console.log(user.username, 'stopped typing in', channel.name, 'after', data.elapsedTime + 'ms');
}); });
client.on('message', message => { client.on('message', message => {
if (true) { if (true) {
if (message.content === 'makechann') { if (message.content === 'makechann') {
if (message.channel.guild) { if (message.channel.guild) {
message.channel.guild.createChannel('hi', 'text').then(console.log); message.channel.guild.createChannel('hi', 'text').then(console.log);
} }
} }
if (message.content === 'myperms?') { if (message.content === 'myperms?') {
message.channel.sendMessage('Your permissions are:\n' + message.channel.sendMessage('Your permissions are:\n' +
JSON.stringify(message.channel.permissionsFor(message.author).serialize(), null, 4)); JSON.stringify(message.channel.permissionsFor(message.author).serialize(), null, 4));
} }
if (message.content === 'delchann') { if (message.content === 'delchann') {
message.channel.delete().then(chan => console.log('selfDelChann', chan.name)); message.channel.delete().then(chan => console.log('selfDelChann', chan.name));
} }
if (message.content.startsWith('setname')) { if (message.content.startsWith('setname')) {
message.channel.setName(message.content.substr(8)); message.channel.setName(message.content.substr(8));
} }
if (message.content.startsWith('botname')) { if (message.content.startsWith('botname')) {
client.user.setUsername(message.content.substr(8)); client.user.setUsername(message.content.substr(8));
} }
if (message.content.startsWith('botavatar')) { if (message.content.startsWith('botavatar')) {
request request
.get('url') .get('url')
.end((err, res) => { .end((err, res) => {
client.user.setAvatar(res.body).catch(console.log) client.user.setAvatar(res.body).catch(console.log)
.then(user => message.channel.sendMessage('Done!')); .then(user => message.channel.sendMessage('Done!'));
}); });
} }
if (message.content.startsWith('gn')) { if (message.content.startsWith('gn')) {
message.guild.setName(message.content.substr(3)) message.guild.setName(message.content.substr(3))
.then(guild => console.log('guild updated to', guild.name)) .then(guild => console.log('guild updated to', guild.name))
.catch(console.log); .catch(console.log);
} }
if (message.content === 'leave') { if (message.content === 'leave') {
message.guild.leave().then(guild => console.log('left guild', guild.name)).catch(console.log); message.guild.leave().then(guild => console.log('left guild', guild.name)).catch(console.log);
} }
if (message.content === 'stats') { if (message.content === 'stats') {
let m = ''; let m = '';
m += `I am aware of ${message.guild.channels.length} channels\n`; m += `I am aware of ${message.guild.channels.length} channels\n`;
m += `I am aware of ${message.guild.members.length} members`; m += `I am aware of ${message.guild.members.length} members`;
message.channel.sendMessage(m); message.channel.sendMessage(m);
} }
if (message.content === 'messageme!') { if (message.content === 'messageme!') {
message.author.sendMessage('oh, hi there!').catch(e => console.log(e.stack)); message.author.sendMessage('oh, hi there!').catch(e => console.log(e.stack));
} }
if (message.content === 'don\'t dm me') { if (message.content === 'don\'t dm me') {
message.author.deleteDM(); message.author.deleteDM();
} }
if (message.content.startsWith('kick')) { if (message.content.startsWith('kick')) {
message.guild.member(message.mentions[0]).kick().then(member => { message.guild.member(message.mentions[0]).kick().then(member => {
console.log(member); console.log(member);
message.channel.sendMessage('Kicked!' + member.user.username); message.channel.sendMessage('Kicked!' + member.user.username);
}).catch(console.log); }).catch(console.log);
} }
if (message.content === 'makerole') { if (message.content === 'makerole') {
message.guild.createRole().then(role => { message.guild.createRole().then(role => {
message.channel.sendMessage(`Made role ${role.name}`); message.channel.sendMessage(`Made role ${role.name}`);
}).catch(console.log); }).catch(console.log);
} }
} }
}); });
function nameLoop(user) { function nameLoop(user) {
// user.setUsername(user.username + 'a').then(nameLoop).catch(console.log); // user.setUsername(user.username + 'a').then(nameLoop).catch(console.log);
} }
function chanLoop(channel) { function chanLoop(channel) {
channel.setName(channel.name + 'a').then(chanLoop).catch(console.log); channel.setName(channel.name + 'a').then(chanLoop).catch(console.log);
} }
client.on('messageDelete', message => { client.on('messageDelete', message => {
console.log('Message deleted by', message.author.username); console.log('Message deleted by', message.author.username);
}); });
client.on('messageUpdate', (old, message) => { client.on('messageUpdate', (old, message) => {
if (message.author.username === 'hydrabolt') if (message.author.username === 'hydrabolt')
console.log('Message updated from', old.content, 'to', message.content); console.log('Message updated from', old.content, 'to', message.content);
}); });
client.on('message', message => { client.on('message', message => {
if (message.content === '?perms?') { if (message.content === '?perms?') {
console.log(message.author.username, 'asked for perms in', message.channel.name, ':'); console.log(message.author.username, 'asked for perms in', message.channel.name, ':');
console.log(message.channel.permissionsFor(message.author).serialize()); console.log(message.channel.permissionsFor(message.author).serialize());
} }
}); });