cloudstorm 0.1.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,234 +0,0 @@
1
- 'use strict';
2
- let EventEmitter;
3
- try {
4
- EventEmitter = require('eventemitter3');
5
- } catch (e) {
6
- EventEmitter = require('events').EventEmitter;
7
- }
8
- const zlib = require('zlib-sync');
9
- let Erlpack;
10
- try {
11
- Erlpack = require('erlpack');
12
- } catch (e) {// eslint-disable-next-line no-empty
13
- }
14
- const GATEWAY_OP_CODES = require('../Constants').GATEWAY_OP_CODES;
15
- let WebSocket = require('ws');
16
- let RatelimitBucket = require('./RatelimitBucket');
17
-
18
- /**
19
- * @typedef BetterWs
20
- * @description Helper Class for simplifying the websocket connection to discord
21
- * @property {WebSocket} ws - the raw websocket connection
22
- * @property {RatelimitBucket} wsBucket - ratelimit bucket for the general websocket connection
23
- * @property {RatelimitBucket} statusBucket - ratelimit bucket for the 5/60s status update ratelimit
24
- * @property {zlib} zlibInflate - shared zlibInflate context for inflating zlib compressed messages received from discord
25
- * @private
26
- */
27
- class BetterWs extends EventEmitter {
28
- /**
29
- * Create a new BetterWs instance
30
- * @param {String} address
31
- * @param {Object} options
32
- * @private
33
- */
34
- constructor(address, options = {}) {
35
- super();
36
- this.ws = new WebSocket(address, options);
37
- this.bindWs(this.ws);
38
- this.wsBucket = new RatelimitBucket(120, 60000);
39
- this.statusBucket = new RatelimitBucket(5, 60000);
40
- this.zlibInflate = new zlib.Inflate({
41
- chunkSize: 65535,
42
- flush: zlib.Z_SYNC_FLUSH,
43
- });
44
- }
45
-
46
- /**
47
- * Get the raw websocket connection currently used
48
- * @returns {WebSocket}
49
- * @protected
50
- */
51
- get rawWs() {
52
- return this.ws;
53
- }
54
-
55
- /**
56
- * Add eventlisteners to a passed websocket connection
57
- * @param {WebSocket} ws - websocket
58
- * @protected
59
- */
60
- bindWs(ws) {
61
- ws.on('message', (msg) => {
62
- this.onMessage(msg);
63
- });
64
- ws.on('close', (code, reason) => this.onClose(code, reason));
65
- ws.on('error', (err) => {
66
- /**
67
- * @event BetterWs#error
68
- * @type {Error}
69
- * @description Emitted upon errors from the underlying websocket
70
- * @private
71
- */
72
- this.emit('error', err);
73
- });
74
- ws.on('open', () => this.onOpen());
75
- }
76
-
77
- /**
78
- * Create a new Websocket Connection if the old one was closed/destroyed
79
- * @param {String} address - address to connect to
80
- * @param {Object} options - options used by the websocket connection
81
- * @protected
82
- */
83
- recreateWs(address, options = {}) {
84
- this.ws.removeAllListeners();
85
- this.zlibInflate = new zlib.Inflate({
86
- chunkSize: 65535,
87
- flush: zlib.Z_SYNC_FLUSH,
88
- });
89
- this.ws = new WebSocket(address, options);
90
- this.options = options;
91
- this.wsBucket.dropQueue();
92
- this.wsBucket = new RatelimitBucket(120, 60000);
93
- this.statusBucket = new RatelimitBucket(5, 60000);
94
- this.bindWs(this.ws);
95
- }
96
-
97
- /**
98
- * Called upon opening of the websocket connection
99
- * @protected
100
- */
101
- onOpen() {
102
- /**
103
- * @event BetterWs#ws_open
104
- * @type {void}
105
- * @description Emitted once the underlying websocket connection has opened
106
- * @private
107
- */
108
- this.emit('ws_open');
109
- }
110
-
111
- /**
112
- * Called once a websocket message is received,
113
- * uncompresses the message using zlib and parses it via Erlpack or JSON.parse
114
- * @param {Object|Buffer|String} message - message received by websocket
115
- * @protected
116
- */
117
- onMessage(message) {
118
- try {
119
- const length = message.length;
120
- const flush = length >= 4 &&
121
- message[length - 4] === 0x00 &&
122
- message[length - 3] === 0x00 &&
123
- message[length - 2] === 0xFF &&
124
- message[length - 1] === 0xFF;
125
- this.zlibInflate.push(message, flush && zlib.Z_SYNC_FLUSH);
126
- if (!flush) return;
127
- if (Erlpack) {
128
- message = Erlpack.unpack(this.zlibInflate.result);
129
- } else {
130
- message = JSON.parse(this.zlibInflate.result);
131
- }
132
- } catch (e) {
133
- /**
134
- * @event BetterWs#error
135
- * @type {String}
136
- * @description Emitted upon parse errors of messages
137
- * @private
138
- */
139
- this.emit('error', `Message: ${message} was not parseable`);
140
- return;
141
- }
142
- /**
143
- * @event BetterWs#ws_message
144
- * @type {Object}
145
- * @description Emitted upon successful parsing of a message with the parsed Message
146
- * @private
147
- */
148
- this.emit('ws_message', message);
149
- }
150
-
151
- /**
152
- * Called when the websocket connection closes for some reason
153
- * @param {Number} code - websocket close code
154
- * @param {String} reason - reason of the close if any
155
- * @protected
156
- */
157
- onClose(code, reason) {
158
- /**
159
- * @event BetterWs#ws_close
160
- * @type {void}
161
- * @param {Number} code - websocket close code
162
- * @param {String} reason - websocket close reason
163
- * @private
164
- */
165
- this.emit('ws_close', code, reason);
166
- }
167
-
168
- /**
169
- * Send a message to the discord gateway
170
- * @param {Object} data - data to send
171
- * @returns {Promise.<void>}
172
- * @protected
173
- */
174
- sendMessage(data) {
175
- /**
176
- * @event BetterWs#debug_send
177
- * @type {object}
178
- * @description Used for debugging the messages sent to discord's gateway
179
- * @private
180
- */
181
- this.emit('debug_send', data);
182
- return new Promise((res, rej) => {
183
- let status = data.op === GATEWAY_OP_CODES.STATUS_UPDATE;
184
- try {
185
- if (Erlpack) {
186
- data = Erlpack.pack(data);
187
- } else {
188
- data = JSON.stringify(data);
189
- }
190
- } catch (e) {
191
- return rej(e);
192
- }
193
- let sendMsg = () => {
194
- // The promise from wsBucket is ignored, since the method passed to it does not return a promise
195
- this.wsBucket.queue(() => {
196
- this.ws.send(data, {}, (e) => {
197
- if (e) {
198
- return rej(e);
199
- }
200
- res();
201
- });
202
- });
203
- };
204
- if (status) {
205
- // same here
206
- this.statusBucket.queue(sendMsg);
207
- } else {
208
- sendMsg();
209
- }
210
- });
211
- }
212
-
213
- /**
214
- * Close the current connection
215
- * @param {Number} code=1000 - websocket close code to use
216
- * @param {String} reason - reason of the disconnect
217
- * @returns {Promise.<void>}
218
- * @protected
219
- */
220
- close(code = 1000, reason = '') {
221
- return new Promise((res, rej) => {
222
- this.ws.close(code, reason);
223
- this.ws.once('close', () => {
224
- return res();
225
- });
226
- setTimeout(() => {
227
- return rej('Websocket not closed within 5 seconds');
228
- }, 5 * 1000);
229
- });
230
-
231
- }
232
- }
233
-
234
- module.exports = BetterWs;
@@ -1,89 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * RatelimitBucket, used for ratelimiting the execution of functions
5
- * @property {Array} fnQueue - array of functions waiting to be executed
6
- * @property {Number} limit - Number of functions that may be executed during the timeframe set in limitReset
7
- * @property {Number} remaining - Remaining amount of executions during the current timeframe
8
- * @property {Number} limitReset - Timeframe in milliseconds until the ratelimit resets
9
- * @property {Object} resetTimeout - Timeout that calls the reset function once the timeframe passed
10
- * @private
11
- */
12
- class RatelimitBucket {
13
- /**
14
- * Create a new Bucket
15
- * @param {Number} [limit=5] - Number of functions that may be executed during the timeframe set in limitReset
16
- * @param {Number} [limitReset=5000] - Timeframe in milliseconds until the ratelimit resets
17
- * @private
18
- */
19
- constructor(limit = 5, limitReset = 5000) {
20
- this.fnQueue = [];
21
- this.limit = limit;
22
- this.remaining = limit;
23
- this.limitReset = limitReset;
24
- this.resetTimeout = null;
25
- }
26
-
27
- /**
28
- * Queue a function to be executed
29
- * @param {Function} fn - function to be executed
30
- * @returns {Promise.<void>} - Result of the function if any
31
- * @protected
32
- */
33
- queue(fn) {
34
- return new Promise((res, rej) => {
35
- let wrapFn = () => {
36
- this.remaining--;
37
- if (!this.resetTimeout) {
38
- this.resetTimeout = setTimeout(() => this.resetRemaining(), this.limitReset);
39
- }
40
- if (this.remaining !== 0) {
41
- this.checkQueue();
42
- }
43
- if (typeof fn.then === 'function') {
44
- return fn().then(res).catch(rej);
45
- }
46
- return res(fn());
47
- };
48
- if (this.remaining === 0) {
49
- this.fnQueue.push({
50
- fn, callback: wrapFn
51
- });
52
- this.checkQueue();
53
- } else {
54
- wrapFn();
55
- }
56
- });
57
- }
58
-
59
- /**
60
- * Check if there are any functions in the queue that haven't been executed yet
61
- * @protected
62
- */
63
- checkQueue() {
64
- if (this.fnQueue.length > 0 && this.remaining !== 0) {
65
- let queuedFunc = this.fnQueue.splice(0, 1)[0];
66
- queuedFunc.callback();
67
- }
68
- }
69
-
70
- /**
71
- * Reset the remaining tokens to the base limit
72
- * @protected
73
- */
74
- resetRemaining() {
75
- this.remaining = this.limit;
76
- clearTimeout(this.resetTimeout);
77
- this.checkQueue();
78
- }
79
-
80
- /**
81
- * Clear the current queue of events to be sent
82
- * @protected
83
- */
84
- dropQueue() {
85
- this.fnQueue = [];
86
- }
87
- }
88
-
89
- module.exports = RatelimitBucket;