feat: Internal sharding (#2902)

* internal sharding

* ready event

* the square deal

* the new deal

* the second new deal

* add actual documentation

* the new freedom

* the great society

* federal intervention

* some of requested changes

* i ran out of things to call these

* destroy this

* fix: Client#uptime went missing

* fix(Client): destroy the client on login failure

This may happen duo invalid sharding config / invalid token / user requested destroy

* fix(Client): reject login promise when the client is destroyed before ready

* fix(WebSocketManager): remove redundancy in destroy method (#2491)

* typo(ErrorMessages): duo -> duo to

* typo(ErrorMessages): duo -> due

* fix: docs and options

* docs(WebSocketManager): WebSockethard -> WebSocketShard (#2502)

* fix(ClientUser): lazily load to account for extended user structure (#2501)

* docs(WebSocketShard): document class to make it visible in documentation (#2504)

* fix: WebSocketShard#reconnect

* fix: presenceUpdate & userUpdate
* presenceUpdate wasn't really being handled at all
* userUpdate handled incorrectly because as of v7 in the Discord API, it comes inside presenceUpdate

* re-add raw event

* member is now part of message create payload

* feat: Add functionality to support multiple servers with different shards (#2395)

* Added functionallity to spawn multiple sharding managers due to adding start and end shards

* Small fixes and limiting shard amount to max recommended

* Forgot a check in spawn()

* Fixed indentation

* Removed optiosn object documentation for totalShards

* More fixes and a check that the startShard + amount doesnt go over the recommended shard amount

* fix getting max recommended

* Removed async from constructor (my fault)

* Changed start and end shard to a shardList or "auto" + fixed some brainfarts with isNaN

* Changed the loop and totalShard count calculation

* shards are actually 0 based

* Fixed a problem with the gateway and handled some range errors and type errors

* Changed Number.isNan to isNaN and changed a few Integer checks to use Number.isInteger

* Added check if shardList contains smth greater than totalShards; made spawn use totalShards again; shardList will be ignored and rebuild if totalShards is 'auto'; fixed docs

* ShardingManager#spawn now uses a for..of loop; fixed the if statement inside the new for..of loop to still work as intended; made the totalShards be set to a new amount if smth manual is put into ShardingManager#spawn just like before; Fixed some spelling

* internal sharding

* ready event

* the square deal

* the new deal

* the second new deal

* add actual documentation

* the new freedom

* the great society

* federal intervention

* some of requested changes

* i ran out of things to call these

* destroy this

* fix: Client#uptime went missing

* fix(Client): destroy the client on login failure

This may happen duo invalid sharding config / invalid token / user requested destroy

* fix(Client): reject login promise when the client is destroyed before ready

* fix(WebSocketManager): remove redundancy in destroy method (#2491)

* typo(ErrorMessages): duo -> duo to

* typo(ErrorMessages): duo -> due

* fix: docs and options

* docs(WebSocketManager): WebSockethard -> WebSocketShard (#2502)

* fix(ClientUser): lazily load to account for extended user structure (#2501)

* docs(WebSocketShard): document class to make it visible in documentation (#2504)

* fix: WebSocketShard#reconnect

* fix: presenceUpdate & userUpdate
* presenceUpdate wasn't really being handled at all
* userUpdate handled incorrectly because as of v7 in the Discord API, it comes inside presenceUpdate

* Internal Sharding adaptation

Adapted to internal sharding
Fixed a bug where non ready invalidated sessions wouldnt respawn

* Fixed shardCount not retrieving

* Fixing style

removed unnecessary parenthesis

* Fixing and rebasing

lets hope i didnt dun hecklered it

* Fixing my own retardation

* Thanks git rebase

* fix: assigning member in message create payload

* fix: resumes

* fix: IS wont give up reconnecting now

* docs: add missing docs mostly

* fix: found lost methods

* fix: WebSocketManager#broadcast check if shard exists

* fix: ShardClientUtil#id returning undefined

* feat: handle new session rate limits (#2796)

* feat: handle new session rate limits

* i have no idea what i was doing last night

* fix if statement weirdness

* fix: re-add presence parsing from ClientOptions (#2893)

* resolve conflicts

* typings: missing typings

* re-add missing linter rule

* fix: replacing ClientUser wrongly

* address unecessary performance waste

* docs: missing disconnect event

* fix(typings): Fix 2 issues with typings (#2909)

* (Typings) Update typings to reflect current ClientOptions

* fix(Typings) fixes a bug with Websockets and DOM Types

* fix travis

* feat: allow setting presence per shard

* add WebSocketManager#shardX events

* adjust typings, docs and performance issues

* readjust shard events, now provide shardId parameter instead

* fix: ready event should check shardCount, not actualShardCount

* fix: re-add replayed parameter of Client#resume

* fix(Sharding): fixes several things in Internal Sharding (#2914)

* fix(Sharding) fixes several things in Internal Sharding

* add default value for shards property

* better implement checking for shards array

* fix travis & some casing

* split shard count into 2 words

* update to latest Internal Sharding, fix requested changes

* make sure totalShardCount is a number

* fix comment

* fix small typo

* dynamically set totalShardCount if either shards or shardCount is provided

* consistency: rename shardID to shardId

* remove Client#shardIds

* fix: typo in GuildIntegrationsUpdate handler

* fix: incorrect packet data being passed in some events (#2919)

* fix: edgecase of ShardingManager and totalShardCount (#2918)

* fix: Client#userUpdate being passed wrong parameter
and fix a potential edgecase of returning null in ClientUser#edit from this event

* fix consistency and typings issues

* consistency: shardId instances renamed to shardID

* typings: fix typings regarding WebSocket

* style(.eslintrc): remove additional whitespace

* fix(Client): remove ondisconnect handler on timeout

* docs(BaseClient): fix typo of Immediate

* nitpick: typings, private fields and methods

* typo: improve grammar a bit

* fix: error assigning client in WebSocketManager

* typo: actually spell milliseconds properly
This commit is contained in:
Isabella
2018-11-03 13:21:23 -05:00
committed by GitHub
parent 18f065867c
commit f3cad81f53
95 changed files with 1145 additions and 1393 deletions

View File

@@ -19,13 +19,17 @@ class ActionsManager {
this.register(require('./GuildRoleCreate'));
this.register(require('./GuildRoleDelete'));
this.register(require('./GuildRoleUpdate'));
this.register(require('./PresenceUpdate'));
this.register(require('./UserUpdate'));
this.register(require('./VoiceStateUpdate'));
this.register(require('./GuildEmojiCreate'));
this.register(require('./GuildEmojiDelete'));
this.register(require('./GuildEmojiUpdate'));
this.register(require('./GuildEmojisUpdate'));
this.register(require('./GuildRolesPositionUpdate'));
this.register(require('./GuildChannelsPositionUpdate'));
this.register(require('./GuildIntegrationsUpdate'));
this.register(require('./WebhooksUpdate'));
}
register(Action) {

View File

@@ -0,0 +1,18 @@
const Action = require('./Action');
const { Events } = require('../../util/Constants');
class GuildIntegrationsUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
if (guild) client.emit(Events.GUILD_INTEGRATIONS_UPDATE, guild);
}
}
module.exports = GuildIntegrationsUpdate;
/**
* Emitted whenever a guild integration is updated
* @event Client#guildIntegrationsUpdate
* @param {Guild} guild The guild whose integrations were updated
*/

View File

@@ -2,7 +2,7 @@ const Action = require('./Action');
const { Events, Status } = require('../../util/Constants');
class GuildMemberRemoveAction extends Action {
handle(data) {
handle(data, shard) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
let member = null;
@@ -13,7 +13,7 @@ class GuildMemberRemoveAction extends Action {
guild.voiceStates.delete(member.id);
member.deleted = true;
guild.members.remove(member.id);
if (client.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
if (shard.status === Status.READY) client.emit(Events.GUILD_MEMBER_REMOVE, member);
}
}
return { guild, member };

View File

@@ -10,7 +10,9 @@ class MessageCreateAction extends Action {
if (existing) return { message: existing };
const message = channel.messages.add(data);
const user = message.author;
const member = channel.guild ? channel.guild.member(user) : null;
let member = null;
if (message.member && channel.guild) member = channel.guild.members.add(message.member);
else if (channel.guild) member = channel.guild.member(user);
channel.lastMessageID = data.id;
if (user) {
user.lastMessageID = data.id;

View File

@@ -0,0 +1,38 @@
const Action = require('./Action');
const { Events } = require('../../util/Constants');
class PresenceUpdateAction extends Action {
handle(data) {
let cached = this.client.users.get(data.user.id);
if (!cached && data.user.username) cached = this.client.users.add(data.user);
if (!cached) return;
if (data.user && data.user.username) {
if (!cached.equals(data.user)) this.client.actions.UserUpdate.handle(data);
}
const guild = this.client.guilds.get(data.guild_id);
if (!guild) return;
let member = guild.members.get(cached.id);
if (!member && data.status !== 'offline') {
member = guild.members.add({ user: cached, roles: data.roles, deaf: false, mute: false });
this.client.emit(Events.GUILD_MEMBER_AVAILABLE, member);
}
if (member) {
if (this.client.listenerCount(Events.PRESENCE_UPDATE) === 0) {
guild.presences.add(data);
return;
}
const old = member._clone();
if (member.presence) old.frozenPresence = member.presence._clone();
guild.presences.add(data);
this.client.emit(Events.PRESENCE_UPDATE, old, member);
} else {
guild.presences.add(data);
}
}
}
module.exports = PresenceUpdateAction;

View File

@@ -5,19 +5,14 @@ class UserUpdateAction extends Action {
handle(data) {
const client = this.client;
if (client.user) {
if (client.user.equals(data)) {
return {
old: client.user,
updated: client.user,
};
}
const newUser = client.users.get(data.user.id);
const oldUser = newUser._update(data.user);
const oldUser = client.user._update(data);
client.emit(Events.USER_UPDATE, oldUser, client.user);
if (!oldUser.equals(newUser)) {
client.emit(Events.USER_UPDATE, oldUser, newUser);
return {
old: oldUser,
updated: client.user,
updated: newUser,
};
}

View File

@@ -0,0 +1,42 @@
const Action = require('./Action');
const { Events } = require('../../util/Constants');
const VoiceState = require('../../structures/VoiceState');
class VoiceStateUpdate extends Action {
handle(data) {
const client = this.client;
const guild = client.guilds.get(data.guild_id);
if (guild) {
// Update the state
const oldState = guild.voiceStates.has(data.user_id) ?
guild.voiceStates.get(data.user_id)._clone() :
new VoiceState(guild, { user_id: data.user_id });
const newState = guild.voiceStates.add(data);
// Get the member
let member = guild.members.get(data.user_id);
if (member && data.member) {
member._patch(data.member);
} else if (data.member && data.member.user && data.member.joined_at) {
member = guild.members.add(data.member);
}
// Emit event
if (member && member.user.id === client.user.id && data.channel_id) {
client.emit('self.voiceStateUpdate', data);
}
client.emit(Events.VOICE_STATE_UPDATE, oldState, newState);
}
}
}
/**
* Emitted whenever a member changes voice state - e.g. joins/leaves a channel, mutes/unmutes.
* @event Client#voiceStateUpdate
* @param {?VoiceState} oldState The voice state before the update
* @param {VoiceState} newState The voice state after the update
*/
module.exports = VoiceStateUpdate;

View File

@@ -0,0 +1,18 @@
const Action = require('./Action');
const { Events } = require('../../util/Constants');
class WebhooksUpdate extends Action {
handle(data) {
const client = this.client;
const channel = client.channels.get(data.channel_id);
if (channel) client.emit(Events.WEBHOOKS_UPDATE, channel);
}
}
/**
* Emitted whenever a guild text channel has its webhooks changed.
* @event Client#webhookUpdate
* @param {TextChannel} channel The channel that had a webhook update
*/
module.exports = WebhooksUpdate;