discord.js-selfv13 13.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of discord.js-selfv13 might be problematic. Click here for more details.

Files changed (188) hide show
  1. package/.dccache +1 -0
  2. package/LICENSE +190 -0
  3. package/README.md +87 -0
  4. package/browser.js +9 -0
  5. package/deploy/deploy-key.enc +0 -0
  6. package/deploy/deploy.sh +90 -0
  7. package/deploy/test.sh +34 -0
  8. package/docs/README.md +1 -0
  9. package/docs/examples/attachments.md +163 -0
  10. package/docs/examples/avatars.js +29 -0
  11. package/docs/examples/embed.js +38 -0
  12. package/docs/examples/greeting.js +30 -0
  13. package/docs/examples/moderation.md +145 -0
  14. package/docs/examples/ping.js +29 -0
  15. package/docs/examples/webhook.js +12 -0
  16. package/docs/general/faq.md +23 -0
  17. package/docs/general/updating.md +181 -0
  18. package/docs/general/welcome.md +95 -0
  19. package/docs/index.yml +30 -0
  20. package/docs/logo.svg +19 -0
  21. package/docs/topics/voice.md +113 -0
  22. package/docs/topics/web.md +38 -0
  23. package/package.json +147 -0
  24. package/src/client/Client.js +564 -0
  25. package/src/client/ClientDataManager.js +150 -0
  26. package/src/client/ClientDataResolver.js +376 -0
  27. package/src/client/ClientManager.js +74 -0
  28. package/src/client/WebhookClient.js +118 -0
  29. package/src/client/actions/Action.js +23 -0
  30. package/src/client/actions/ActionsManager.js +40 -0
  31. package/src/client/actions/ChannelCreate.js +11 -0
  32. package/src/client/actions/ChannelDelete.js +30 -0
  33. package/src/client/actions/ChannelUpdate.js +74 -0
  34. package/src/client/actions/GuildBanRemove.js +13 -0
  35. package/src/client/actions/GuildChannelsPositionUpdate.js +19 -0
  36. package/src/client/actions/GuildDelete.js +57 -0
  37. package/src/client/actions/GuildEmojiCreate.js +17 -0
  38. package/src/client/actions/GuildEmojiDelete.js +18 -0
  39. package/src/client/actions/GuildEmojiUpdate.js +17 -0
  40. package/src/client/actions/GuildEmojisUpdate.js +38 -0
  41. package/src/client/actions/GuildMemberGet.js +10 -0
  42. package/src/client/actions/GuildMemberRemove.js +41 -0
  43. package/src/client/actions/GuildRoleCreate.js +26 -0
  44. package/src/client/actions/GuildRoleDelete.js +42 -0
  45. package/src/client/actions/GuildRoleUpdate.js +41 -0
  46. package/src/client/actions/GuildRolesPositionUpdate.js +19 -0
  47. package/src/client/actions/GuildSync.js +29 -0
  48. package/src/client/actions/GuildUpdate.js +34 -0
  49. package/src/client/actions/MessageCreate.js +53 -0
  50. package/src/client/actions/MessageDelete.js +35 -0
  51. package/src/client/actions/MessageDeleteBulk.js +26 -0
  52. package/src/client/actions/MessageReactionAdd.js +37 -0
  53. package/src/client/actions/MessageReactionRemove.js +37 -0
  54. package/src/client/actions/MessageReactionRemoveAll.js +25 -0
  55. package/src/client/actions/MessageUpdate.js +40 -0
  56. package/src/client/actions/Ready.js +1 -0
  57. package/src/client/actions/Ready.js.bak +65 -0
  58. package/src/client/actions/UserGet.js +11 -0
  59. package/src/client/actions/UserNoteUpdate.js +30 -0
  60. package/src/client/actions/UserUpdate.js +33 -0
  61. package/src/client/rest/APIRequest.js +56 -0
  62. package/src/client/rest/DiscordAPIError.js +60 -0
  63. package/src/client/rest/RESTManager.js +58 -0
  64. package/src/client/rest/RESTMethods.js +1006 -0
  65. package/src/client/rest/RequestHandlers/Burst.js +90 -0
  66. package/src/client/rest/RequestHandlers/RequestHandler.js +54 -0
  67. package/src/client/rest/RequestHandlers/Sequential.js +132 -0
  68. package/src/client/rest/UserAgentManager.js +25 -0
  69. package/src/client/voice/ClientVoiceManager.js +81 -0
  70. package/src/client/voice/VoiceBroadcast.js +366 -0
  71. package/src/client/voice/VoiceConnection.js +530 -0
  72. package/src/client/voice/VoiceUDPClient.js +127 -0
  73. package/src/client/voice/VoiceWebSocket.js +246 -0
  74. package/src/client/voice/dispatcher/StreamDispatcher.js +331 -0
  75. package/src/client/voice/opus/BaseOpusEngine.js +60 -0
  76. package/src/client/voice/opus/NodeOpusEngine.js +40 -0
  77. package/src/client/voice/opus/OpusEngineList.js +28 -0
  78. package/src/client/voice/opus/OpusScriptEngine.js +45 -0
  79. package/src/client/voice/player/AudioPlayer.js +170 -0
  80. package/src/client/voice/receiver/VoiceReadable.js +17 -0
  81. package/src/client/voice/receiver/VoiceReceiver.js +219 -0
  82. package/src/client/voice/util/SecretKey.js +16 -0
  83. package/src/client/voice/util/Secretbox.js +33 -0
  84. package/src/client/voice/util/VolumeInterface.js +86 -0
  85. package/src/client/websocket/WebSocketConnection.js +506 -0
  86. package/src/client/websocket/WebSocketManager.js +90 -0
  87. package/src/client/websocket/packets/WebSocketPacketManager.js +110 -0
  88. package/src/client/websocket/packets/handlers/AbstractHandler.js +11 -0
  89. package/src/client/websocket/packets/handlers/ChannelCreate.js +17 -0
  90. package/src/client/websocket/packets/handlers/ChannelDelete.js +20 -0
  91. package/src/client/websocket/packets/handlers/ChannelPinsUpdate.js +37 -0
  92. package/src/client/websocket/packets/handlers/ChannelUpdate.js +11 -0
  93. package/src/client/websocket/packets/handlers/GuildBanAdd.js +23 -0
  94. package/src/client/websocket/packets/handlers/GuildBanRemove.js +20 -0
  95. package/src/client/websocket/packets/handlers/GuildCreate.js +22 -0
  96. package/src/client/websocket/packets/handlers/GuildDelete.js +19 -0
  97. package/src/client/websocket/packets/handlers/GuildEmojisUpdate.js +11 -0
  98. package/src/client/websocket/packets/handlers/GuildIntegrationsUpdate.js +19 -0
  99. package/src/client/websocket/packets/handlers/GuildMemberAdd.js +17 -0
  100. package/src/client/websocket/packets/handlers/GuildMemberRemove.js +13 -0
  101. package/src/client/websocket/packets/handlers/GuildMemberUpdate.js +18 -0
  102. package/src/client/websocket/packets/handlers/GuildMembersChunk.js +33 -0
  103. package/src/client/websocket/packets/handlers/GuildRoleCreate.js +11 -0
  104. package/src/client/websocket/packets/handlers/GuildRoleDelete.js +11 -0
  105. package/src/client/websocket/packets/handlers/GuildRoleUpdate.js +11 -0
  106. package/src/client/websocket/packets/handlers/GuildSync.js +11 -0
  107. package/src/client/websocket/packets/handlers/GuildUpdate.js +11 -0
  108. package/src/client/websocket/packets/handlers/MessageCreate.js +19 -0
  109. package/src/client/websocket/packets/handlers/MessageDelete.js +19 -0
  110. package/src/client/websocket/packets/handlers/MessageDeleteBulk.js +17 -0
  111. package/src/client/websocket/packets/handlers/MessageReactionAdd.js +11 -0
  112. package/src/client/websocket/packets/handlers/MessageReactionRemove.js +11 -0
  113. package/src/client/websocket/packets/handlers/MessageReactionRemoveAll.js +11 -0
  114. package/src/client/websocket/packets/handlers/MessageUpdate.js +11 -0
  115. package/src/client/websocket/packets/handlers/PresenceUpdate.js +76 -0
  116. package/src/client/websocket/packets/handlers/Ready.js +83 -0
  117. package/src/client/websocket/packets/handlers/RelationshipAdd.js +19 -0
  118. package/src/client/websocket/packets/handlers/RelationshipRemove.js +19 -0
  119. package/src/client/websocket/packets/handlers/Resumed.js +28 -0
  120. package/src/client/websocket/packets/handlers/TypingStart.js +68 -0
  121. package/src/client/websocket/packets/handlers/UserGuildSettingsUpdate.js +21 -0
  122. package/src/client/websocket/packets/handlers/UserNoteUpdate.js +12 -0
  123. package/src/client/websocket/packets/handlers/UserSettingsUpdate.js +18 -0
  124. package/src/client/websocket/packets/handlers/UserUpdate.js +11 -0
  125. package/src/client/websocket/packets/handlers/VoiceServerUpdate.js +19 -0
  126. package/src/client/websocket/packets/handlers/VoiceStateUpdate.js +52 -0
  127. package/src/client/websocket/packets/handlers/WebhooksUpdate.js +19 -0
  128. package/src/index.js +66 -0
  129. package/src/sharding/Shard.js +282 -0
  130. package/src/sharding/ShardClientUtil.js +146 -0
  131. package/src/sharding/ShardingManager.js +220 -0
  132. package/src/structures/Attachment.js +75 -0
  133. package/src/structures/CategoryChannel.js +22 -0
  134. package/src/structures/Channel.js +78 -0
  135. package/src/structures/ClientUser.js +447 -0
  136. package/src/structures/ClientUserChannelOverride.js +30 -0
  137. package/src/structures/ClientUserGuildSettings.js +60 -0
  138. package/src/structures/ClientUserSettings.js +80 -0
  139. package/src/structures/DMChannel.js +76 -0
  140. package/src/structures/Emoji.js +256 -0
  141. package/src/structures/GroupDMChannel.js +246 -0
  142. package/src/structures/Guild.js +1461 -0
  143. package/src/structures/GuildAuditLogs.js +371 -0
  144. package/src/structures/GuildChannel.js +537 -0
  145. package/src/structures/GuildMember.js +613 -0
  146. package/src/structures/Invite.js +164 -0
  147. package/src/structures/Message.js +605 -0
  148. package/src/structures/MessageAttachment.js +68 -0
  149. package/src/structures/MessageCollector.js +100 -0
  150. package/src/structures/MessageEmbed.js +386 -0
  151. package/src/structures/MessageMentions.js +144 -0
  152. package/src/structures/MessageReaction.js +96 -0
  153. package/src/structures/NewsChannel.js +24 -0
  154. package/src/structures/OAuth2Application.js +148 -0
  155. package/src/structures/PartialGuild.js +51 -0
  156. package/src/structures/PartialGuildChannel.js +44 -0
  157. package/src/structures/PermissionOverwrites.js +69 -0
  158. package/src/structures/Presence.js +241 -0
  159. package/src/structures/ReactionCollector.js +85 -0
  160. package/src/structures/ReactionEmoji.js +49 -0
  161. package/src/structures/RichEmbed.js +295 -0
  162. package/src/structures/Role.js +376 -0
  163. package/src/structures/StoreChannel.js +25 -0
  164. package/src/structures/TextChannel.js +154 -0
  165. package/src/structures/User.js +329 -0
  166. package/src/structures/UserConnection.js +48 -0
  167. package/src/structures/UserProfile.js +62 -0
  168. package/src/structures/VoiceChannel.js +146 -0
  169. package/src/structures/VoiceRegion.js +50 -0
  170. package/src/structures/Webhook.js +304 -0
  171. package/src/structures/interfaces/Collector.js +179 -0
  172. package/src/structures/interfaces/TextBasedChannel.js +635 -0
  173. package/src/structures/shared/resolvePermissions.js +26 -0
  174. package/src/util/Collection.js +532 -0
  175. package/src/util/Constants.js +845 -0
  176. package/src/util/Permissions.js +306 -0
  177. package/src/util/Snowflake.js +82 -0
  178. package/src/util/Util.js +221 -0
  179. package/test/random.js +207 -0
  180. package/test/shard.js +31 -0
  181. package/test/sharder.js +7 -0
  182. package/test/voice.js +78 -0
  183. package/test/webpack.html +31 -0
  184. package/tsconfig.json +13 -0
  185. package/tslint.json +62 -0
  186. package/typings/discord.js-test.ts +69 -0
  187. package/typings/index.d.ts +2190 -0
  188. package/webpack.config.js +62 -0
@@ -0,0 +1,506 @@
1
+ const browser = typeof window !== 'undefined';
2
+ const EventEmitter = require('events');
3
+ const Constants = require('../../util/Constants');
4
+ const zlib = require('zlib');
5
+ const PacketManager = require('./packets/WebSocketPacketManager');
6
+ const erlpack = (function findErlpack() {
7
+ try {
8
+ const e = require('erlpack');
9
+ if (!e.pack) return null;
10
+ return e;
11
+ } catch (e) {
12
+ return null;
13
+ }
14
+ }());
15
+
16
+ const WebSocket = (function findWebSocket() {
17
+ if (browser) return window.WebSocket; // eslint-disable-line no-undef
18
+ try {
19
+ return require('@discordjs/uws');
20
+ } catch (e) {
21
+ return require('ws');
22
+ }
23
+ }());
24
+
25
+ /**
26
+ * Abstracts a WebSocket connection with decoding/encoding for the Discord gateway.
27
+ * @private
28
+ */
29
+ class WebSocketConnection extends EventEmitter {
30
+ /**
31
+ * @param {WebSocketManager} manager The WebSocket manager
32
+ * @param {string} gateway The WebSocket gateway to connect to
33
+ */
34
+ constructor(manager, gateway) {
35
+ super();
36
+ /**
37
+ * The WebSocket Manager of this connection
38
+ * @type {WebSocketManager}
39
+ */
40
+ this.manager = manager;
41
+
42
+ /**
43
+ * The client this belongs to
44
+ * @type {Client}
45
+ */
46
+ this.client = manager.client;
47
+
48
+ /**
49
+ * The WebSocket connection itself
50
+ * @type {WebSocket}
51
+ */
52
+ this.ws = null;
53
+
54
+ /**
55
+ * The current sequence of the WebSocket
56
+ * @type {number}
57
+ */
58
+ this.sequence = -1;
59
+
60
+ /**
61
+ * The current status of the client
62
+ * @type {Status}
63
+ */
64
+ this.status = Constants.Status.IDLE;
65
+
66
+ /**
67
+ * The Packet Manager of the connection
68
+ * @type {WebSocketPacketManager}
69
+ */
70
+ this.packetManager = new PacketManager(this);
71
+
72
+ /**
73
+ * The last time a ping was sent (a timestamp)
74
+ * @type {number}
75
+ */
76
+ this.lastPingTimestamp = 0;
77
+
78
+ /**
79
+ * Contains the rate limit queue and metadata
80
+ * @type {Object}
81
+ */
82
+ this.ratelimit = {
83
+ queue: [],
84
+ remaining: 120,
85
+ total: 120,
86
+ time: 60e3,
87
+ resetTimer: null,
88
+ };
89
+ this.connect(gateway);
90
+
91
+ /**
92
+ * Events that are disabled (will not be processed)
93
+ * @type {Object}
94
+ */
95
+ this.disabledEvents = {};
96
+
97
+ /**
98
+ * The sequence on WebSocket close
99
+ * @type {number}
100
+ */
101
+ this.closeSequence = 0;
102
+
103
+ /**
104
+ * Whether or not the WebSocket is expecting to be closed
105
+ * @type {boolean}
106
+ */
107
+ this.expectingClose = false;
108
+ for (const event of this.client.options.disabledEvents) this.disabledEvents[event] = true;
109
+ }
110
+
111
+ /**
112
+ * Causes the client to be marked as ready and emits the ready event.
113
+ * @returns {void}
114
+ */
115
+ triggerReady() {
116
+ if (this.status === Constants.Status.READY) {
117
+ this.debug('Tried to mark self as ready, but already ready');
118
+ return;
119
+ }
120
+ /**
121
+ * Emitted when the client becomes ready to start working.
122
+ * @event Client#ready
123
+ */
124
+ this.status = Constants.Status.READY;
125
+ this.client.emit(Constants.Events.READY);
126
+ this.packetManager.handleQueue();
127
+ }
128
+
129
+ /**
130
+ * Checks whether the client is ready to be marked as ready.
131
+ * @returns {void}
132
+ */
133
+ checkIfReady() {
134
+ if (this.status === Constants.Status.READY || this.status === Constants.Status.NEARLY) return false;
135
+ let unavailableGuilds = 0;
136
+ for (const guild of this.client.guilds.values()) {
137
+ if (!guild.available) unavailableGuilds++;
138
+ }
139
+ if (unavailableGuilds === 0) {
140
+ this.status = Constants.Status.NEARLY;
141
+ if (!this.client.options.fetchAllMembers) return this.triggerReady();
142
+ // Fetch all members before marking self as ready
143
+ const promises = this.client.guilds.map(g => g.fetchMembers());
144
+ Promise.all(promises)
145
+ .then(() => this.triggerReady())
146
+ .catch(e => {
147
+ this.debug(`Failed to fetch all members before ready! ${e}`);
148
+ this.triggerReady();
149
+ });
150
+ }
151
+ return true;
152
+ }
153
+
154
+ // Util
155
+ /**
156
+ * Emits a debug message.
157
+ * @param {string} message Debug message
158
+ * @returns {void}
159
+ */
160
+ debug(message) {
161
+ if (message instanceof Error) message = message.stack;
162
+ return this.manager.debug(`[connection] ${message}`);
163
+ }
164
+
165
+ /**
166
+ * Attempts to serialise data from the WebSocket.
167
+ * @param {string|Object} data Data to unpack
168
+ * @returns {Object}
169
+ */
170
+ unpack(data) {
171
+ if (data instanceof ArrayBuffer) data = Buffer.from(new Uint8Array(data));
172
+
173
+ if (erlpack && typeof data !== 'string') return erlpack.unpack(data);
174
+ else if (data instanceof Buffer) data = zlib.inflateSync(data).toString();
175
+
176
+ return JSON.parse(data);
177
+ }
178
+
179
+ /**
180
+ * Packs an object ready to be sent.
181
+ * @param {Object} data Data to pack
182
+ * @returns {string|Buffer}
183
+ */
184
+ pack(data) {
185
+ return erlpack ? erlpack.pack(data) : JSON.stringify(data);
186
+ }
187
+
188
+ /**
189
+ * Processes the current WebSocket queue.
190
+ */
191
+ processQueue() {
192
+ if (this.ratelimit.remaining === 0) return;
193
+ if (this.ratelimit.queue.length === 0) return;
194
+ if (this.ratelimit.remaining === this.ratelimit.total) {
195
+ this.ratelimit.resetTimer = this.client.setTimeout(() => {
196
+ this.ratelimit.remaining = this.ratelimit.total;
197
+ this.processQueue();
198
+ }, this.ratelimit.time);
199
+ }
200
+ while (this.ratelimit.remaining > 0) {
201
+ const item = this.ratelimit.queue.shift();
202
+ if (!item) return;
203
+ this._send(item);
204
+ this.ratelimit.remaining--;
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Sends data, bypassing the queue.
210
+ * @param {Object} data Packet to send
211
+ * @returns {void}
212
+ */
213
+ _send(data) {
214
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
215
+ this.debug(`Tried to send packet ${JSON.stringify(data)} but no WebSocket is available!`);
216
+ return;
217
+ }
218
+ this.ws.send(this.pack(data));
219
+ }
220
+
221
+ /**
222
+ * Adds data to the queue to be sent.
223
+ * @param {Object} data Packet to send
224
+ * @returns {void}
225
+ */
226
+ send(data) {
227
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
228
+ this.debug(`Tried to send packet ${JSON.stringify(data)} but no WebSocket is available!`);
229
+ return;
230
+ }
231
+ this.ratelimit.queue.push(data);
232
+ this.processQueue();
233
+ }
234
+
235
+ /**
236
+ * Creates a connection to a gateway.
237
+ * @param {string} gateway The gateway to connect to
238
+ * @param {number} [after=0] How long to wait before connecting
239
+ * @param {boolean} [force=false] Whether or not to force a new connection even if one already exists
240
+ * @returns {boolean}
241
+ */
242
+ connect(gateway = this.gateway, after = 0, force = false) {
243
+ if (after) return this.client.setTimeout(() => this.connect(gateway, 0, force), after); // eslint-disable-line
244
+ if (this.ws && !force) {
245
+ this.debug('WebSocket connection already exists');
246
+ return false;
247
+ } else if (typeof gateway !== 'string') {
248
+ this.debug(`Tried to connect to an invalid gateway: ${gateway}`);
249
+ return false;
250
+ }
251
+ this.expectingClose = false;
252
+ this.gateway = gateway;
253
+ this.debug(`Connecting to ${gateway}`);
254
+ const ws = this.ws = new WebSocket(gateway);
255
+ if (browser) ws.binaryType = 'arraybuffer';
256
+ ws.onmessage = this.onMessage.bind(this);
257
+ ws.onopen = this.onOpen.bind(this);
258
+ ws.onerror = this.onError.bind(this);
259
+ ws.onclose = this.onClose.bind(this);
260
+ this.status = Constants.Status.CONNECTING;
261
+ return true;
262
+ }
263
+
264
+ /**
265
+ * Destroys the connection.
266
+ * @returns {boolean}
267
+ */
268
+ destroy() {
269
+ const ws = this.ws;
270
+ if (!ws) {
271
+ this.debug('Attempted to destroy WebSocket but no connection exists!');
272
+ return false;
273
+ }
274
+ this.heartbeat(-1);
275
+ this.expectingClose = true;
276
+ ws.close(1000);
277
+ this.packetManager.handleQueue();
278
+ this.ws = null;
279
+ this.status = Constants.Status.DISCONNECTED;
280
+ this.ratelimit.remaining = this.ratelimit.total;
281
+ return true;
282
+ }
283
+
284
+ /**
285
+ * Called whenever a message is received.
286
+ * @param {Event} event Event received
287
+ * @returns {boolean}
288
+ */
289
+ onMessage(event) {
290
+ let data;
291
+ try {
292
+ data = this.unpack(event.data);
293
+ } catch (err) {
294
+ this.emit('debug', err);
295
+ }
296
+ return this.onPacket(data);
297
+ }
298
+
299
+ /**
300
+ * Sets the current sequence of the connection.
301
+ * @param {number} s New sequence
302
+ */
303
+ setSequence(s) {
304
+ this.sequence = s > this.sequence ? s : this.sequence;
305
+ }
306
+
307
+ /**
308
+ * Called whenever a packet is received.
309
+ * @param {Object} packet Received packet
310
+ * @returns {boolean}
311
+ */
312
+ onPacket(packet) {
313
+ if (!packet) {
314
+ this.debug('Received null packet');
315
+ return false;
316
+ }
317
+ this.client.emit('raw', packet);
318
+ switch (packet.op) {
319
+ case Constants.OPCodes.HELLO:
320
+ return this.heartbeat(packet.d.heartbeat_interval);
321
+ case Constants.OPCodes.RECONNECT:
322
+ return this.reconnect();
323
+ case Constants.OPCodes.INVALID_SESSION:
324
+ if (!packet.d) this.sessionID = null;
325
+ this.sequence = -1;
326
+ this.debug('Session invalidated -- will identify with a new session');
327
+ return this.identify(packet.d ? 2500 : 0);
328
+ case Constants.OPCodes.HEARTBEAT_ACK:
329
+ return this.ackHeartbeat();
330
+ case Constants.OPCodes.HEARTBEAT:
331
+ return this.heartbeat();
332
+ default:
333
+ return this.packetManager.handle(packet);
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Called whenever a connection is opened to the gateway.
339
+ * @param {Event} event Received open event
340
+ */
341
+ onOpen(event) {
342
+ if (event && event.target && event.target.url) this.gateway = event.target.url;
343
+ this.debug(`Connected to gateway ${this.gateway}`);
344
+ this.identify();
345
+ }
346
+
347
+ /**
348
+ * Causes a reconnection to the gateway.
349
+ */
350
+ reconnect() {
351
+ this.debug('Attemping to reconnect in 5500ms...');
352
+ /**
353
+ * Emitted whenever the client tries to reconnect to the WebSocket.
354
+ * @event Client#reconnecting
355
+ */
356
+ this.client.emit(Constants.Events.RECONNECTING);
357
+ this.connect(this.gateway, 5500, true);
358
+ }
359
+
360
+ /**
361
+ * Called whenever an error occurs with the WebSocket.
362
+ * @param {Error} error The error that occurred
363
+ */
364
+ onError(error) {
365
+ if (error && error.message === 'uWs client connection error') {
366
+ this.reconnect();
367
+ return;
368
+ }
369
+ /**
370
+ * Emitted whenever the client's WebSocket encounters a connection error.
371
+ * @event Client#error
372
+ * @param {Error} error The encountered error
373
+ */
374
+ this.client.emit(Constants.Events.ERROR, error);
375
+ }
376
+
377
+ /**
378
+ * @external CloseEvent
379
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
380
+ */
381
+
382
+ /**
383
+ * Called whenever a connection to the gateway is closed.
384
+ * @param {CloseEvent} event Close event that was received
385
+ */
386
+ onClose(event) {
387
+ this.debug(`${this.expectingClose ? 'Client' : 'Server'} closed the WebSocket connection: ${event.code}`);
388
+ this.closeSequence = this.sequence;
389
+ // Reset the state before trying to fix anything
390
+ this.emit('close', event);
391
+ this.heartbeat(-1);
392
+ // Should we reconnect?
393
+ if (event.code === 1000 ? this.expectingClose : Constants.WSCodes[event.code]) {
394
+ this.expectingClose = false;
395
+ /**
396
+ * Emitted when the client's WebSocket disconnects and will no longer attempt to reconnect.
397
+ * @event Client#disconnect
398
+ * @param {CloseEvent} event The WebSocket close event
399
+ */
400
+ this.client.emit(Constants.Events.DISCONNECT, event);
401
+ this.debug(Constants.WSCodes[event.code]);
402
+ this.destroy();
403
+ return;
404
+ }
405
+ this.expectingClose = false;
406
+ this.reconnect();
407
+ }
408
+
409
+ // Heartbeat
410
+ /**
411
+ * Acknowledges a heartbeat.
412
+ */
413
+ ackHeartbeat() {
414
+ this.debug(`Heartbeat acknowledged, latency of ${Date.now() - this.lastPingTimestamp}ms`);
415
+ this.client._pong(this.lastPingTimestamp);
416
+ }
417
+
418
+ /**
419
+ * Sends a heartbeat or sets an interval for sending heartbeats.
420
+ * @param {number} [time] If -1, clears the interval, any other number sets an interval
421
+ * If no value is given, a heartbeat will be sent instantly
422
+ */
423
+ heartbeat(time) {
424
+ if (!isNaN(time)) {
425
+ if (time === -1) {
426
+ this.debug('Clearing heartbeat interval');
427
+ this.client.clearInterval(this.heartbeatInterval);
428
+ this.heartbeatInterval = null;
429
+ } else {
430
+ this.debug(`Setting a heartbeat interval for ${time}ms`);
431
+ this.heartbeatInterval = this.client.setInterval(() => this.heartbeat(), time);
432
+ }
433
+ return;
434
+ }
435
+ this.debug('Sending a heartbeat');
436
+ this.lastPingTimestamp = Date.now();
437
+ this.send({
438
+ op: Constants.OPCodes.HEARTBEAT,
439
+ d: this.sequence,
440
+ });
441
+ }
442
+
443
+ // Identification
444
+ /**
445
+ * Identifies the client on a connection.
446
+ * @param {number} [after] How long to wait before identifying
447
+ * @returns {void}
448
+ */
449
+ identify(after) {
450
+ if (after) return this.client.setTimeout(this.identify.bind(this), after);
451
+ return this.sessionID ? this.identifyResume() : this.identifyNew();
452
+ }
453
+
454
+ /**
455
+ * Identifies as a new connection on the gateway.
456
+ * @returns {void}
457
+ */
458
+ identifyNew() {
459
+ if (!this.client.token) {
460
+ this.debug('No token available to identify a new session with');
461
+ return;
462
+ }
463
+ // Clone the generic payload and assign the token
464
+ const d = Object.assign({ token: this.client.token }, this.client.options.ws);
465
+
466
+ // Sharding stuff
467
+ const { shardId, shardCount } = this.client.options;
468
+ if (shardCount > 0) d.shard = [Number(shardId), Number(shardCount)];
469
+
470
+ // Send the payload
471
+ this.debug('Identifying as a new session');
472
+ this.send({ op: Constants.OPCodes.IDENTIFY, d });
473
+ }
474
+
475
+ /**
476
+ * Resumes a session on the gateway.
477
+ * @returns {void}
478
+ */
479
+ identifyResume() {
480
+ if (!this.sessionID) {
481
+ this.debug('Warning: wanted to resume but session ID not available; identifying as a new session instead');
482
+ return this.identifyNew();
483
+ }
484
+ this.debug(`Attempting to resume session ${this.sessionID}`);
485
+
486
+ const d = {
487
+ token: this.client.token,
488
+ session_id: this.sessionID,
489
+ seq: this.sequence,
490
+ };
491
+
492
+ return this.send({
493
+ op: Constants.OPCodes.RESUME,
494
+ d,
495
+ });
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Encoding the WebSocket connections will use.
501
+ * @type {string}
502
+ */
503
+ WebSocketConnection.ENCODING = erlpack ? 'etf' : 'json';
504
+ WebSocketConnection.WebSocket = WebSocket;
505
+
506
+ module.exports = WebSocketConnection;
@@ -0,0 +1,90 @@
1
+ const EventEmitter = require('events').EventEmitter;
2
+ const Constants = require('../../util/Constants');
3
+ const WebSocketConnection = require('./WebSocketConnection');
4
+
5
+ /**
6
+ * WebSocket Manager of the client.
7
+ * @private
8
+ */
9
+ class WebSocketManager extends EventEmitter {
10
+ constructor(client) {
11
+ super();
12
+ /**
13
+ * The client that instantiated this WebSocketManager
14
+ * @type {Client}
15
+ */
16
+ this.client = client;
17
+
18
+ /**
19
+ * The WebSocket connection of this manager
20
+ * @type {?WebSocketConnection}
21
+ */
22
+ this.connection = null;
23
+ }
24
+
25
+ /**
26
+ * Sends a heartbeat on the available connection.
27
+ * @returns {void}
28
+ */
29
+ heartbeat() {
30
+ if (!this.connection) return this.debug('No connection to heartbeat');
31
+ return this.connection.heartbeat();
32
+ }
33
+
34
+ /**
35
+ * Emits a debug event.
36
+ * @param {string} message Debug message
37
+ * @returns {void}
38
+ */
39
+ debug(message) {
40
+ return this.client.emit('debug', `[ws] ${message}`);
41
+ }
42
+
43
+ /**
44
+ * Destroy the client.
45
+ * @returns {void} Whether or not destruction was successful
46
+ */
47
+ destroy() {
48
+ if (!this.connection) {
49
+ this.debug('Attempted to destroy WebSocket but no connection exists!');
50
+ return false;
51
+ }
52
+ return this.connection.destroy();
53
+ }
54
+
55
+ /**
56
+ * Send a packet on the available WebSocket.
57
+ * @param {Object} packet Packet to send
58
+ * @returns {void}
59
+ */
60
+ send(packet) {
61
+ if (!this.connection) {
62
+ this.debug('No connection to websocket');
63
+ return;
64
+ }
65
+ this.connection.send(packet);
66
+ }
67
+
68
+ /**
69
+ * Connects the client to a gateway.
70
+ * @param {string} gateway The gateway to connect to
71
+ * @returns {boolean}
72
+ */
73
+ connect(gateway) {
74
+ if (!this.connection) {
75
+ this.connection = new WebSocketConnection(this, gateway);
76
+ return true;
77
+ }
78
+ switch (this.connection.status) {
79
+ case Constants.Status.IDLE:
80
+ case Constants.Status.DISCONNECTED:
81
+ this.connection.connect(gateway, 5500);
82
+ return true;
83
+ default:
84
+ this.debug(`Couldn't connect to ${gateway} as the websocket is at state ${this.connection.status}`);
85
+ return false;
86
+ }
87
+ }
88
+ }
89
+
90
+ module.exports = WebSocketManager;
@@ -0,0 +1,110 @@
1
+ const Constants = require('../../../util/Constants');
2
+
3
+ const BeforeReadyWhitelist = [
4
+ Constants.WSEvents.READY,
5
+ Constants.WSEvents.RESUMED,
6
+ Constants.WSEvents.GUILD_CREATE,
7
+ Constants.WSEvents.GUILD_DELETE,
8
+ Constants.WSEvents.GUILD_MEMBERS_CHUNK,
9
+ Constants.WSEvents.GUILD_MEMBER_ADD,
10
+ Constants.WSEvents.GUILD_MEMBER_REMOVE,
11
+ ];
12
+
13
+ class WebSocketPacketManager {
14
+ constructor(connection) {
15
+ this.ws = connection;
16
+ this.handlers = {};
17
+ this.queue = [];
18
+
19
+ this.register(Constants.WSEvents.READY, require('./handlers/Ready'));
20
+ this.register(Constants.WSEvents.RESUMED, require('./handlers/Resumed'));
21
+ this.register(Constants.WSEvents.GUILD_CREATE, require('./handlers/GuildCreate'));
22
+ this.register(Constants.WSEvents.GUILD_DELETE, require('./handlers/GuildDelete'));
23
+ this.register(Constants.WSEvents.GUILD_UPDATE, require('./handlers/GuildUpdate'));
24
+ this.register(Constants.WSEvents.GUILD_BAN_ADD, require('./handlers/GuildBanAdd'));
25
+ this.register(Constants.WSEvents.GUILD_BAN_REMOVE, require('./handlers/GuildBanRemove'));
26
+ this.register(Constants.WSEvents.GUILD_MEMBER_ADD, require('./handlers/GuildMemberAdd'));
27
+ this.register(Constants.WSEvents.GUILD_MEMBER_REMOVE, require('./handlers/GuildMemberRemove'));
28
+ this.register(Constants.WSEvents.GUILD_MEMBER_UPDATE, require('./handlers/GuildMemberUpdate'));
29
+ this.register(Constants.WSEvents.GUILD_ROLE_CREATE, require('./handlers/GuildRoleCreate'));
30
+ this.register(Constants.WSEvents.GUILD_ROLE_DELETE, require('./handlers/GuildRoleDelete'));
31
+ this.register(Constants.WSEvents.GUILD_ROLE_UPDATE, require('./handlers/GuildRoleUpdate'));
32
+ this.register(Constants.WSEvents.GUILD_EMOJIS_UPDATE, require('./handlers/GuildEmojisUpdate'));
33
+ this.register(Constants.WSEvents.GUILD_MEMBERS_CHUNK, require('./handlers/GuildMembersChunk'));
34
+ this.register(Constants.WSEvents.GUILD_INTEGRATIONS_UPDATE, require('./handlers/GuildIntegrationsUpdate'));
35
+ this.register(Constants.WSEvents.CHANNEL_CREATE, require('./handlers/ChannelCreate'));
36
+ this.register(Constants.WSEvents.CHANNEL_DELETE, require('./handlers/ChannelDelete'));
37
+ this.register(Constants.WSEvents.CHANNEL_UPDATE, require('./handlers/ChannelUpdate'));
38
+ this.register(Constants.WSEvents.CHANNEL_PINS_UPDATE, require('./handlers/ChannelPinsUpdate'));
39
+ this.register(Constants.WSEvents.PRESENCE_UPDATE, require('./handlers/PresenceUpdate'));
40
+ this.register(Constants.WSEvents.USER_UPDATE, require('./handlers/UserUpdate'));
41
+ this.register(Constants.WSEvents.USER_NOTE_UPDATE, require('./handlers/UserNoteUpdate'));
42
+ this.register(Constants.WSEvents.USER_SETTINGS_UPDATE, require('./handlers/UserSettingsUpdate'));
43
+ this.register(Constants.WSEvents.USER_GUILD_SETTINGS_UPDATE, require('./handlers/UserGuildSettingsUpdate'));
44
+ this.register(Constants.WSEvents.VOICE_STATE_UPDATE, require('./handlers/VoiceStateUpdate'));
45
+ this.register(Constants.WSEvents.TYPING_START, require('./handlers/TypingStart'));
46
+ this.register(Constants.WSEvents.MESSAGE_CREATE, require('./handlers/MessageCreate'));
47
+ this.register(Constants.WSEvents.MESSAGE_DELETE, require('./handlers/MessageDelete'));
48
+ this.register(Constants.WSEvents.MESSAGE_UPDATE, require('./handlers/MessageUpdate'));
49
+ this.register(Constants.WSEvents.MESSAGE_DELETE_BULK, require('./handlers/MessageDeleteBulk'));
50
+ this.register(Constants.WSEvents.VOICE_SERVER_UPDATE, require('./handlers/VoiceServerUpdate'));
51
+ this.register(Constants.WSEvents.GUILD_SYNC, require('./handlers/GuildSync'));
52
+ this.register(Constants.WSEvents.RELATIONSHIP_ADD, require('./handlers/RelationshipAdd'));
53
+ this.register(Constants.WSEvents.RELATIONSHIP_REMOVE, require('./handlers/RelationshipRemove'));
54
+ this.register(Constants.WSEvents.MESSAGE_REACTION_ADD, require('./handlers/MessageReactionAdd'));
55
+ this.register(Constants.WSEvents.MESSAGE_REACTION_REMOVE, require('./handlers/MessageReactionRemove'));
56
+ this.register(Constants.WSEvents.MESSAGE_REACTION_REMOVE_ALL, require('./handlers/MessageReactionRemoveAll'));
57
+ this.register(Constants.WSEvents.WEBHOOKS_UPDATE, require('./handlers/WebhooksUpdate'));
58
+ }
59
+
60
+ get client() {
61
+ return this.ws.client;
62
+ }
63
+
64
+ register(event, Handler) {
65
+ this.handlers[event] = new Handler(this);
66
+ }
67
+
68
+ handleQueue() {
69
+ this.queue.forEach((element, index) => {
70
+ this.handle(this.queue[index], true);
71
+ this.queue.splice(index, 1);
72
+ });
73
+ }
74
+
75
+ handle(packet, queue = false) {
76
+ if (packet.op === Constants.OPCodes.HEARTBEAT_ACK) {
77
+ this.ws.client._pong(this.ws.client._pingTimestamp);
78
+ this.ws.lastHeartbeatAck = true;
79
+ this.ws.client.emit('debug', 'Heartbeat acknowledged');
80
+ } else if (packet.op === Constants.OPCodes.HEARTBEAT) {
81
+ this.client.ws.send({
82
+ op: Constants.OPCodes.HEARTBEAT,
83
+ d: this.client.ws.sequence,
84
+ });
85
+ this.ws.client.emit('debug', 'Received gateway heartbeat');
86
+ }
87
+
88
+ if (this.ws.status === Constants.Status.RECONNECTING) {
89
+ this.ws.reconnecting = false;
90
+ this.ws.checkIfReady();
91
+ }
92
+
93
+ this.ws.setSequence(packet.s);
94
+
95
+ if (this.ws.disabledEvents[packet.t] !== undefined) return false;
96
+
97
+ if (this.ws.status !== Constants.Status.READY) {
98
+ if (BeforeReadyWhitelist.indexOf(packet.t) === -1) {
99
+ this.queue.push(packet);
100
+ return false;
101
+ }
102
+ }
103
+
104
+ if (!queue && this.queue.length > 0) this.handleQueue();
105
+ if (this.handlers[packet.t]) return this.handlers[packet.t].handle(packet);
106
+ return false;
107
+ }
108
+ }
109
+
110
+ module.exports = WebSocketPacketManager;