diff --git a/lib/Client/InternalClient.js b/lib/Client/InternalClient.js index 3c082df9c..d50e81a7a 100644 --- a/lib/Client/InternalClient.js +++ b/lib/Client/InternalClient.js @@ -240,6 +240,9 @@ var InternalClient = (function () { this.unavailableServers = new _UtilCache2["default"](); this.private_channels = new _UtilCache2["default"](); this.autoReconnectInterval = 1000; + this.unsyncedGuilds = 0; + this.guildSyncQueue = []; + this.guildSyncQueueLength = 1; this.intervals = { typing: [], @@ -489,8 +492,29 @@ var InternalClient = (function () { }); }; + InternalClient.prototype.syncGuild = function syncGuild(guildID) { + if (this.guildSyncQueueLength + 3 + guildID.length > 4081) { + // 4096 - "{\"op\":12,\"d\":[]}".length + 1 for lazy comma offset + this.sendWS({ op: 12, d: this.guildSyncQueue }); + this.guildSyncQueue = [guildID]; + this.guildSyncQueueLength = 1 + guildID.length + 3; + } else { + this.guildSyncQueue.push(guildID); + this.guildSyncQueueLength += guildID.length + 3; + } + }; + InternalClient.prototype.checkReady = function checkReady() { if (!this.readyTime) { + if (this.guildSyncQueue.length > 0) { + this.sendWS({ op: 12, d: this.guildSyncQueue }); + this.guildSyncQueue = []; + this.guildSyncQueueLength = 1; + return; + } + if (this.unsyncedGuilds > 0) { + return; + } if (this.forceFetchQueue.length > 0) { this.requestGuildMembers(this.forceFetchQueue); this.forceFetchQueue = []; @@ -1932,6 +1956,10 @@ var InternalClient = (function () { data.guilds.forEach(function (server) { if (!server.unavailable) { server = _this37.servers.add(new _StructuresServer2["default"](server, client)); + if (client.options.bot === false) { + _this37.unsyncedGuilds++; + _this37.syncGuild(server.id); + } if (_this37.client.options.forceFetchUsers && server.members && server.members.length < server.memberCount) { _this37.getGuildMembers(server.id, Math.ceil(server.memberCount / 1000)); } @@ -2079,6 +2107,10 @@ var InternalClient = (function () { if (!server) { if (!data.unavailable) { server = this.servers.add(new _StructuresServer2["default"](data, client)); + if (client.options.bot === false) { + this.unsyncedGuilds++; + this.syncGuild(server.id); + } if (client.readyTime) { client.emit("serverCreated", server); } @@ -2556,7 +2588,7 @@ var InternalClient = (function () { if (this.forceFetchCount.hasOwnProperty(server.id)) { if (this.forceFetchCount[server.id] <= 1) { delete this.forceFetchCount[server.id]; - this.checkReady(); + this.restartServerCreateTimeout(); } else { this.forceFetchCount[server.id]--; } @@ -2647,6 +2679,78 @@ var InternalClient = (function () { return; } break; + case _Constants.PacketType.SERVER_SYNC: + // (╯°□°)╯︵ ┻━┻ thx Discord devs + var guild = this.servers.get(data.id); + data.members.forEach(function (dataUser) { + guild.memberMap[dataUser.user.id] = { + roles: dataUser.roles, + mute: dataUser.mute, + selfMute: dataUser.self_mute, + deaf: dataUser.deaf, + selfDeaf: dataUser.self_deaf, + joinedAt: Date.parse(dataUser.joined_at), + nick: dataUser.nick || null + }; + guild.members.add(client.internal.users.add(new _StructuresUser2["default"](dataUser.user, client))); + }); + for (var _iterator11 = data.presences, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref11; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref11 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref11 = _i11.value; + } + + var presence = _ref11; + + var user = client.internal.users.get("id", presence.user.id); + if (user) { + user.status = presence.status; + user.game = presence.game; + } + } + if (guild.pendingVoiceStates && guild.pendingVoiceStates.length > 0) { + for (var _iterator12 = guild.pendingVoiceStates, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref12; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref12 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref12 = _i12.value; + } + + var voiceState = _ref12; + + var _user = guild.members.get("id", voiceState.user_id); + if (_user) { + guild.memberMap[_user.id] = guild.memberMap[_user.id] || {}; + guild.memberMap[_user.id].mute = voiceState.mute || guild.memberMap[_user.id].mute; + guild.memberMap[_user.id].selfMute = voiceState.self_mute === undefined ? guild.memberMap[_user.id].selfMute : voiceState.self_mute; + guild.memberMap[_user.id].deaf = voiceState.deaf || guild.memberMap[_user.id].deaf; + guild.memberMap[_user.id].selfDeaf = voiceState.self_deaf === undefined ? guild.memberMap[_user.id].selfDeaf : voiceState.self_deaf; + var _channel2 = guild.channels.get("id", voiceState.channel_id); + if (_channel2) { + guild.eventVoiceJoin(_user, _channel2); + } else { + guild.client.emit("warn", "channel doesn't exist even though GUILD_SYNC expects them to"); + } + } else { + guild.client.emit("warn", "user doesn't exist even though GUILD_SYNC expects them to"); + } + } + } + guild.pendingVoiceStates = null; + this.unsyncedGuilds--; + this.restartServerCreateTimeout(); + break; default: client.emit("unknown", packet); break; diff --git a/lib/Constants.js b/lib/Constants.js index b6807521d..bd6b2cb7a 100644 --- a/lib/Constants.js +++ b/lib/Constants.js @@ -150,6 +150,7 @@ Constants.PacketType = { SERVER_ROLE_CREATE: "GUILD_ROLE_CREATE", SERVER_ROLE_DELETE: "GUILD_ROLE_DELETE", SERVER_ROLE_UPDATE: "GUILD_ROLE_UPDATE", + SERVER_SYNC: "GUILD_SYNC", SERVER_UPDATE: "GUILD_UPDATE", TYPING: "TYPING_START", USER_UPDATE: "USER_UPDATE", diff --git a/lib/Structures/Server.js b/lib/Structures/Server.js index 389b90ac7..e2eb12f57 100644 --- a/lib/Structures/Server.js +++ b/lib/Structures/Server.js @@ -166,36 +166,40 @@ var Server = (function (_Equality) { } if (data.voice_states) { - for (var _iterator2 = data.voice_states, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { - var _ref2; + if (this.client.options.bot) { + for (var _iterator2 = data.voice_states, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; - if (_isArray2) { - if (_i2 >= _iterator2.length) break; - _ref2 = _iterator2[_i2++]; - } else { - _i2 = _iterator2.next(); - if (_i2.done) break; - _ref2 = _i2.value; - } - - var voiceState = _ref2; - - var _user = this.members.get("id", voiceState.user_id); - if (_user) { - this.memberMap[_user.id] = this.memberMap[_user.id] || {}; - this.memberMap[_user.id].mute = voiceState.mute || this.memberMap[_user.id].mute; - this.memberMap[_user.id].selfMute = voiceState.self_mute === undefined ? this.memberMap[_user.id].selfMute : voiceState.self_mute; - this.memberMap[_user.id].deaf = voiceState.deaf || this.memberMap[_user.id].deaf; - this.memberMap[_user.id].selfDeaf = voiceState.self_deaf === undefined ? this.memberMap[_user.id].selfDeaf : voiceState.self_deaf; - var channel = this.channels.get("id", voiceState.channel_id); - if (channel) { - this.eventVoiceJoin(_user, channel); + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; } else { - this.client.emit("warn", "channel doesn't exist even though READY expects them to"); + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + + var voiceState = _ref2; + + var _user = this.members.get("id", voiceState.user_id); + if (_user) { + this.memberMap[_user.id] = this.memberMap[_user.id] || {}; + this.memberMap[_user.id].mute = voiceState.mute || this.memberMap[_user.id].mute; + this.memberMap[_user.id].selfMute = voiceState.self_mute === undefined ? this.memberMap[_user.id].selfMute : voiceState.self_mute; + this.memberMap[_user.id].deaf = voiceState.deaf || this.memberMap[_user.id].deaf; + this.memberMap[_user.id].selfDeaf = voiceState.self_deaf === undefined ? this.memberMap[_user.id].selfDeaf : voiceState.self_deaf; + var channel = this.channels.get("id", voiceState.channel_id); + if (channel) { + this.eventVoiceJoin(_user, channel); + } else { + this.client.emit("warn", "channel doesn't exist even though READY expects them to"); + } + } else { + this.client.emit("warn", "user doesn't exist even though READY expects them to"); } - } else { - this.client.emit("warn", "user doesn't exist even though READY expects them to"); } + } else { + this.pendingVoiceStates = data.voice_states; } } } diff --git a/src/Client/InternalClient.js b/src/Client/InternalClient.js index 903b1acc4..5427acc80 100755 --- a/src/Client/InternalClient.js +++ b/src/Client/InternalClient.js @@ -157,6 +157,9 @@ export default class InternalClient { this.unavailableServers = new Cache(); this.private_channels = new Cache(); this.autoReconnectInterval = 1000; + this.unsyncedGuilds = 0; + this.guildSyncQueue = []; + this.guildSyncQueueLength = 1; this.intervals = { typing : [], @@ -390,8 +393,28 @@ export default class InternalClient { }); } + syncGuild(guildID) { + if(this.guildSyncQueueLength + 3 + guildID.length > 4081) { // 4096 - "{\"op\":12,\"d\":[]}".length + 1 for lazy comma offset + this.sendWS({op: 12, d: this.guildSyncQueue}); + this.guildSyncQueue = [guildID]; + this.guildSyncQueueLength = 1 + guildID.length + 3; + } else { + this.guildSyncQueue.push(guildID); + this.guildSyncQueueLength += guildID.length + 3; + } + } + checkReady() { if (!this.readyTime) { + if(this.guildSyncQueue.length > 0) { + this.sendWS({op: 12, d: this.guildSyncQueue}); + this.guildSyncQueue = []; + this.guildSyncQueueLength = 1; + return; + } + if(this.unsyncedGuilds > 0) { + return; + } if (this.forceFetchQueue.length > 0) { this.requestGuildMembers(this.forceFetchQueue); this.forceFetchQueue = []; @@ -1700,6 +1723,10 @@ export default class InternalClient { data.guilds.forEach(server => { if (!server.unavailable) { server = this.servers.add(new Server(server, client)); + if(client.options.bot === false) { + this.unsyncedGuilds++; + this.syncGuild(server.id); + } if (this.client.options.forceFetchUsers && server.members && server.members.length < server.memberCount) { this.getGuildMembers(server.id, Math.ceil(server.memberCount / 1000)); } @@ -1840,6 +1867,10 @@ export default class InternalClient { if (!server) { if (!data.unavailable) { server = this.servers.add(new Server(data, client)); + if(client.options.bot === false) { + this.unsyncedGuilds++; + this.syncGuild(server.id); + } if (client.readyTime) { client.emit("serverCreated", server); } @@ -2281,7 +2312,7 @@ export default class InternalClient { if (this.forceFetchCount.hasOwnProperty(server.id)) { if (this.forceFetchCount[server.id] <= 1) { delete this.forceFetchCount[server.id]; - this.checkReady(); + this.restartServerCreateTimeout(); } else { this.forceFetchCount[server.id]--; } @@ -2369,6 +2400,51 @@ export default class InternalClient { return; } break; + case PacketType.SERVER_SYNC:// (╯°□°)╯︵ ┻━┻ thx Discord devs + var guild = this.servers.get(data.id); + data.members.forEach((dataUser) => { + guild.memberMap[dataUser.user.id] = { + roles: dataUser.roles, + mute: dataUser.mute, + selfMute: dataUser.self_mute, + deaf: dataUser.deaf, + selfDeaf: dataUser.self_deaf, + joinedAt: Date.parse(dataUser.joined_at), + nick: dataUser.nick || null + }; + guild.members.add(client.internal.users.add(new User(dataUser.user, client))); + }); + for (var presence of data.presences) { + var user = client.internal.users.get("id", presence.user.id); + if(user) { + user.status = presence.status; + user.game = presence.game; + } + } + if(guild.pendingVoiceStates && guild.pendingVoiceStates.length > 0) { + for (var voiceState of guild.pendingVoiceStates) { + let user = guild.members.get("id", voiceState.user_id); + if (user) { + guild.memberMap[user.id] = guild.memberMap[user.id] || {}; + guild.memberMap[user.id].mute = voiceState.mute || guild.memberMap[user.id].mute; + guild.memberMap[user.id].selfMute = voiceState.self_mute === undefined ? guild.memberMap[user.id].selfMute : voiceState.self_mute; + guild.memberMap[user.id].deaf = voiceState.deaf || guild.memberMap[user.id].deaf; + guild.memberMap[user.id].selfDeaf = voiceState.self_deaf === undefined ? guild.memberMap[user.id].selfDeaf : voiceState.self_deaf; + let channel = guild.channels.get("id", voiceState.channel_id); + if (channel) { + guild.eventVoiceJoin(user, channel); + } else { + guild.client.emit("warn", "channel doesn't exist even though GUILD_SYNC expects them to"); + } + } else { + guild.client.emit("warn", "user doesn't exist even though GUILD_SYNC expects them to"); + } + } + } + guild.pendingVoiceStates = null; + this.unsyncedGuilds--; + this.restartServerCreateTimeout(); + break; default: client.emit("unknown", packet); break; diff --git a/src/Constants.js b/src/Constants.js index dffa52204..05e5fa8e7 100644 --- a/src/Constants.js +++ b/src/Constants.js @@ -103,6 +103,7 @@ Constants.PacketType = { SERVER_ROLE_CREATE : "GUILD_ROLE_CREATE", SERVER_ROLE_DELETE : "GUILD_ROLE_DELETE", SERVER_ROLE_UPDATE : "GUILD_ROLE_UPDATE", + SERVER_SYNC : "GUILD_SYNC", SERVER_UPDATE : "GUILD_UPDATE", TYPING : "TYPING_START", USER_UPDATE : "USER_UPDATE", diff --git a/src/Structures/Server.js b/src/Structures/Server.js index bc7abdedb..c4c0a4b8b 100644 --- a/src/Structures/Server.js +++ b/src/Structures/Server.js @@ -107,23 +107,27 @@ export default class Server extends Equality { } if (data.voice_states) { - for (var voiceState of data.voice_states) { - let user = this.members.get("id", voiceState.user_id); - if (user) { - this.memberMap[user.id] = this.memberMap[user.id] || {}; - this.memberMap[user.id].mute = voiceState.mute || this.memberMap[user.id].mute; - this.memberMap[user.id].selfMute = voiceState.self_mute === undefined ? this.memberMap[user.id].selfMute : voiceState.self_mute; - this.memberMap[user.id].deaf = voiceState.deaf || this.memberMap[user.id].deaf; - this.memberMap[user.id].selfDeaf = voiceState.self_deaf === undefined ? this.memberMap[user.id].selfDeaf : voiceState.self_deaf; - let channel = this.channels.get("id", voiceState.channel_id); - if (channel) { - this.eventVoiceJoin(user, channel); + if(this.client.options.bot) { + for (var voiceState of data.voice_states) { + let user = this.members.get("id", voiceState.user_id); + if (user) { + this.memberMap[user.id] = this.memberMap[user.id] || {}; + this.memberMap[user.id].mute = voiceState.mute || this.memberMap[user.id].mute; + this.memberMap[user.id].selfMute = voiceState.self_mute === undefined ? this.memberMap[user.id].selfMute : voiceState.self_mute; + this.memberMap[user.id].deaf = voiceState.deaf || this.memberMap[user.id].deaf; + this.memberMap[user.id].selfDeaf = voiceState.self_deaf === undefined ? this.memberMap[user.id].selfDeaf : voiceState.self_deaf; + let channel = this.channels.get("id", voiceState.channel_id); + if (channel) { + this.eventVoiceJoin(user, channel); + } else { + this.client.emit("warn", "channel doesn't exist even though READY expects them to"); + } } else { - this.client.emit("warn", "channel doesn't exist even though READY expects them to"); + this.client.emit("warn", "user doesn't exist even though READY expects them to"); } - } else { - this.client.emit("warn", "user doesn't exist even though READY expects them to"); } + } else { + this.pendingVoiceStates = data.voice_states; } } }