cloudstorm 0.5.8 → 0.6.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,545 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- // This ultra light weigth WS code is a slimmed down version originally found at https://github.com/timotejroiko/tiny-discord
6
- // Modifications and use of this code was granted for this project by the author, Timotej Roiko.
7
- // A major thank you to Tim for better performing software.
8
- const events_1 = require("events");
9
- const crypto_1 = require("crypto");
10
- const zlib_1 = require("zlib");
11
- const https_1 = __importDefault(require("https"));
12
- const http_1 = __importDefault(require("http"));
13
- const util_1 = __importDefault(require("util"));
14
- const Constants_1 = require("../Constants");
15
- const RatelimitBucket_1 = __importDefault(require("./RatelimitBucket"));
16
- /**
17
- * Helper Class for simplifying the websocket connection to Discord.
18
- */
19
- class BetterWs extends events_1.EventEmitter {
20
- constructor(address, options) {
21
- super();
22
- this.wsBucket = new RatelimitBucket_1.default(120, 60000);
23
- this.presenceBucket = new RatelimitBucket_1.default(5, 60000);
24
- this._connecting = false;
25
- this.encoding = options.encoding === "etf" ? "etf" : "json";
26
- this.compress = options.compress || false;
27
- this.address = address;
28
- this.options = options;
29
- this._socket = null;
30
- this._internal = {
31
- closePromise: null,
32
- zlib: null,
33
- };
34
- }
35
- get status() {
36
- const internal = this._internal;
37
- if (this._connecting)
38
- return 2;
39
- if (internal.closePromise)
40
- return 3; // closing
41
- if (!this._socket)
42
- return 4; // closed
43
- return 1; // connected
44
- }
45
- connect() {
46
- if (this._socket)
47
- return Promise.resolve(void 0);
48
- const key = (0, crypto_1.randomBytes)(16).toString("base64");
49
- const url = new URL(this.address);
50
- const useHTTPS = (url.protocol === "https:" || url.protocol === "wss:") || url.port === "443";
51
- const port = url.port || (useHTTPS ? "443" : "80");
52
- const req = (useHTTPS ? https_1.default : http_1.default).request({
53
- hostname: url.hostname,
54
- path: `${url.pathname}${url.search}`,
55
- port: port,
56
- headers: {
57
- "Connection": "Upgrade",
58
- "Upgrade": "websocket",
59
- "Sec-WebSocket-Key": key,
60
- "Sec-WebSocket-Version": "13",
61
- }
62
- });
63
- this._connecting = true;
64
- return new Promise((resolve, reject) => {
65
- req.on("upgrade", (res, socket) => {
66
- const hash = (0, crypto_1.createHash)("sha1").update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");
67
- const accept = res.headers["sec-websocket-accept"];
68
- if (hash !== accept) {
69
- socket.end(() => {
70
- this.emit("debug", "Failed websocket-key validation");
71
- this._connecting = false;
72
- reject(new Error(`Invalid Sec-Websocket-Accept | expected: ${hash} | received: ${accept}`));
73
- });
74
- return;
75
- }
76
- socket.on("error", this._onError.bind(this));
77
- socket.on("close", this._onClose.bind(this));
78
- socket.on("readable", this._onReadable.bind(this));
79
- this._socket = socket;
80
- this._connecting = false;
81
- if (this.compress) {
82
- const z = (0, zlib_1.createInflate)();
83
- // @ts-ignore
84
- z._c = z.close;
85
- z._h = z._handle;
86
- z._hc = z._handle.close;
87
- z._v = () => void 0;
88
- this._internal.zlib = z;
89
- }
90
- this.emit("ws_open");
91
- resolve(void 0);
92
- });
93
- req.on("error", e => {
94
- this._connecting = false;
95
- reject(e);
96
- });
97
- req.end();
98
- });
99
- }
100
- async close(code, reason) {
101
- const internal = this._internal;
102
- if (internal.closePromise)
103
- return internal.closePromise;
104
- if (!this._socket)
105
- return Promise.resolve(void 0);
106
- let resolver;
107
- const promise = new Promise(resolve => {
108
- resolver = resolve;
109
- const from = Buffer.from([code >> 8, code & 255]);
110
- this._write(reason ? Buffer.concat([from, Buffer.from(reason)]) : from, 8);
111
- }).then(() => {
112
- internal.closePromise = null;
113
- });
114
- // @ts-ignore
115
- promise.resolve = resolver;
116
- internal.closePromise = promise;
117
- return promise;
118
- }
119
- sendMessage(data) {
120
- if (!isValidRequest(data))
121
- return Promise.reject(new Error("Invalid request"));
122
- return new Promise(res => {
123
- const presence = data.op === Constants_1.GATEWAY_OP_CODES.PRESENCE_UPDATE;
124
- const sendMsg = () => {
125
- this.wsBucket.queue(() => {
126
- this.emit("debug_send", data);
127
- if (this.encoding === "json")
128
- this._write(Buffer.from(JSON.stringify(data)), 1);
129
- else {
130
- const etf = writeETF(data);
131
- this._write(etf, 2);
132
- }
133
- res(void 0);
134
- });
135
- };
136
- if (presence)
137
- this.presenceBucket.queue(sendMsg);
138
- else
139
- sendMsg();
140
- });
141
- }
142
- _write(packet, opcode) {
143
- const socket = this._socket;
144
- if (!socket || !socket.writable)
145
- return;
146
- const length = packet.length;
147
- let frame;
148
- if (length < 126) {
149
- frame = Buffer.allocUnsafe(6 + length);
150
- frame[1] = 128 + length;
151
- }
152
- else if (length < (1 << 16)) {
153
- frame = Buffer.allocUnsafe(8 + length);
154
- frame[1] = 254;
155
- frame[2] = length >> 8;
156
- frame[3] = length & 255;
157
- }
158
- else {
159
- frame = Buffer.allocUnsafe(14 + length);
160
- frame[1] = 255;
161
- frame.writeBigUInt64BE(BigInt(length), 2);
162
- }
163
- frame[0] = 128 + opcode;
164
- frame.writeUInt32BE(0, frame.length - length - 4);
165
- frame.set(packet, frame.length - length);
166
- socket.write(frame);
167
- }
168
- _onError(error) {
169
- if (!this._socket)
170
- return;
171
- this.emit("debug", util_1.default.inspect(error, true, 1, false));
172
- this._write(Buffer.allocUnsafe(0), 8);
173
- }
174
- _onClose() {
175
- const socket = this._socket;
176
- const internal = this._internal;
177
- if (!socket)
178
- return;
179
- this.emit("debug", "Connection closed");
180
- socket.removeListener("data", this._onReadable);
181
- socket.removeListener("error", this._onError);
182
- socket.removeListener("close", this._onClose);
183
- this.wsBucket.dropQueue();
184
- this.presenceBucket.dropQueue();
185
- this._socket = null;
186
- if (internal.zlib) {
187
- internal.zlib.close();
188
- internal.zlib = null;
189
- }
190
- // @ts-ignore
191
- if (internal.closePromise)
192
- internal.closePromise.resolve(void 0);
193
- }
194
- _onReadable() {
195
- const socket = this._socket;
196
- while (((socket === null || socket === void 0 ? void 0 : socket.readableLength) || 0) > 1) {
197
- let length = readRange(socket, 1, 1) & 127;
198
- let bytes = 0;
199
- if (length > 125) {
200
- bytes = length === 126 ? 2 : 8;
201
- if (socket.readableLength < 2 + bytes)
202
- return;
203
- length = readRange(socket, 2, bytes);
204
- }
205
- const frame = socket.read(2 + bytes + length);
206
- if (!frame)
207
- return;
208
- const fin = frame[0] >> 7;
209
- const opcode = frame[0] & 15;
210
- if (fin !== 1 || opcode === 0)
211
- this.emit("debug", "discord actually does send messages with fin=0. if you see this error let me know");
212
- const payload = frame.subarray(2 + bytes);
213
- this._processFrame(opcode, payload);
214
- }
215
- }
216
- _processFrame(opcode, message) {
217
- const internal = this._internal;
218
- switch (opcode) {
219
- case 1: {
220
- const packet = JSON.parse(message.toString());
221
- this.emit("ws_message", packet);
222
- break;
223
- }
224
- case 2: {
225
- let packet;
226
- if (this.compress) {
227
- const z = internal.zlib;
228
- let error = null;
229
- let data = null;
230
- // @ts-ignore
231
- z.close = z._handle.close = z._v;
232
- try {
233
- // @ts-ignore
234
- data = z._processChunk(message, zlib_1.constants.Z_SYNC_FLUSH);
235
- }
236
- catch (e) {
237
- error = e;
238
- }
239
- const l = message.length;
240
- if (message[l - 4] !== 0 || message[l - 3] !== 0 || message[l - 2] !== 255 || message[l - 1] !== 255)
241
- this.emit("debug", "discord actually does send fragmented zlib messages. If you see this error let me know");
242
- // @ts-ignore
243
- z.close = z._c;
244
- // @ts-ignore
245
- z._handle = z._h;
246
- // @ts-ignore
247
- z._handle.close = z._hc;
248
- // @ts-ignore
249
- z._events.error = void 0;
250
- // @ts-ignore
251
- z._eventCount--;
252
- z.removeAllListeners("error");
253
- if (error) {
254
- this.emit("debug", "Zlib error");
255
- this._write(Buffer.allocUnsafe(0), 8);
256
- return;
257
- }
258
- if (!data) {
259
- this.emit("debug", "Data from zlib processing was null. If you see this error let me know"); // This should never run, but TS is lame
260
- return;
261
- }
262
- packet = this.encoding === "json" ? JSON.parse(String(data)) : readETF(data, 1);
263
- }
264
- else if (this.encoding === "json") {
265
- const data = (0, zlib_1.inflateSync)(message);
266
- packet = JSON.parse(data.toString());
267
- }
268
- else
269
- packet = readETF(message, 1);
270
- this.emit("ws_message", packet);
271
- break;
272
- }
273
- case 8: {
274
- const code = message.length > 1 ? (message[0] << 8) + message[1] : 0;
275
- const reason = message.length > 2 ? message.subarray(2).toString() : "";
276
- this.emit("ws_close", code, reason);
277
- this._write(Buffer.from([code >> 8, code & 255]), 8);
278
- break;
279
- }
280
- case 9: {
281
- this._write(message, 10);
282
- break;
283
- }
284
- }
285
- }
286
- }
287
- function isValidRequest(value) {
288
- return value && typeof value === "object" && Number.isInteger(value.op) && typeof value.d !== "undefined";
289
- }
290
- function readRange(socket, index, bytes) {
291
- // @ts-ignore
292
- let head = socket._readableState.buffer.head;
293
- let cursor = 0;
294
- let read = 0;
295
- let num = 0;
296
- do {
297
- for (const element of head.data) {
298
- if (++cursor > index) {
299
- num *= 256;
300
- num += element;
301
- if (++read === bytes)
302
- return num;
303
- }
304
- }
305
- } while ((head = head.next));
306
- throw new Error("readRange failed?");
307
- }
308
- function readETF(data, start) {
309
- let view;
310
- let x = start;
311
- const loop = () => {
312
- const type = data[x++];
313
- switch (type) {
314
- case 97: {
315
- return data[x++];
316
- }
317
- case 98: {
318
- const int = data.readInt32BE(x);
319
- x += 4;
320
- return int;
321
- }
322
- case 100: {
323
- const length = data.readUInt16BE(x);
324
- let atom = "";
325
- if (length > 30) {
326
- // @ts-ignore
327
- atom = data.latin1Slice(x += 2, x + length);
328
- }
329
- else {
330
- for (let i = x += 2; i < x + length; i++) {
331
- atom += String.fromCharCode(data[i]);
332
- }
333
- }
334
- x += length;
335
- if (!atom)
336
- return undefined;
337
- if (atom === "nil" || atom === "null")
338
- return null;
339
- if (atom === "true")
340
- return true;
341
- if (atom === "false")
342
- return false;
343
- return atom;
344
- }
345
- case 108:
346
- case 106: {
347
- const array = [];
348
- if (type === 108) {
349
- const length = data.readUInt32BE(x);
350
- x += 4;
351
- for (let i = 0; i < length; i++) {
352
- array.push(loop());
353
- }
354
- x++;
355
- }
356
- return array;
357
- }
358
- case 107: {
359
- const array = [];
360
- const length = data.readUInt16BE(x);
361
- x += 2;
362
- for (let i = 0; i < length; i++) {
363
- array.push(data[x++]);
364
- }
365
- return array;
366
- }
367
- case 109: {
368
- const length = data.readUInt32BE(x);
369
- let str = "";
370
- if (length > 30) {
371
- // @ts-ignore
372
- str = data.utf8Slice(x += 4, x + length);
373
- }
374
- else {
375
- let i = x += 4;
376
- const l = x + length;
377
- while (i < l) {
378
- const byte = data[i++];
379
- if (byte < 128)
380
- str += String.fromCharCode(byte);
381
- else if (byte < 224)
382
- str += String.fromCharCode(((byte & 31) << 6) + (data[i++] & 63));
383
- else if (byte < 240)
384
- str += String.fromCharCode(((byte & 15) << 12) + ((data[i++] & 63) << 6) + (data[i++] & 63));
385
- else
386
- str += String.fromCodePoint(((byte & 7) << 18) + ((data[i++] & 63) << 12) + ((data[i++] & 63) << 6) + (data[i++] & 63));
387
- }
388
- }
389
- x += length;
390
- return str;
391
- }
392
- case 110: {
393
- // @ts-ignore
394
- if (!view)
395
- view = new DataView(data.buffer, data.offset, data.byteLength);
396
- const length = data[x++];
397
- const sign = data[x++];
398
- let left = length;
399
- let num = BigInt(0);
400
- while (left > 0) {
401
- if (left >= 8) {
402
- num <<= BigInt(64);
403
- num += view.getBigUint64(x + (left -= 8), true);
404
- }
405
- else if (left >= 4) {
406
- num <<= BigInt(32);
407
- // @ts-ignore
408
- num += BigInt(view.getUint32(x + (left -= 4)), true);
409
- }
410
- else if (left >= 2) {
411
- num <<= BigInt(16);
412
- // @ts-ignore
413
- num += BigInt(view.getUint16(x + (left -= 2)), true);
414
- }
415
- else {
416
- num <<= BigInt(8);
417
- num += BigInt(data[x]);
418
- left--;
419
- }
420
- }
421
- x += length;
422
- return (sign ? -num : num).toString();
423
- }
424
- case 116: {
425
- const obj = {};
426
- const length = data.readUInt32BE(x);
427
- x += 4;
428
- for (let i = 0; i < length; i++) {
429
- const key = loop();
430
- // @ts-ignore
431
- obj[key] = loop();
432
- }
433
- return obj;
434
- }
435
- }
436
- throw new Error(`Missing etf type: ${type}`);
437
- };
438
- return loop();
439
- }
440
- function writeETF(data) {
441
- const b = Buffer.allocUnsafe(1 << 12);
442
- b[0] = 131;
443
- let i = 1;
444
- const loop = (obj) => {
445
- const type = typeof obj;
446
- switch (type) {
447
- case "boolean": {
448
- b[i++] = 100;
449
- if (obj) {
450
- b.writeUInt16BE(4, i);
451
- // @ts-ignore
452
- b.latin1Write("true", i += 2);
453
- i += 4;
454
- }
455
- else {
456
- b.writeUInt16BE(5, i);
457
- // @ts-ignore
458
- b.latin1Write("false", i += 2);
459
- i += 5;
460
- }
461
- break;
462
- }
463
- case "string": {
464
- const length = Buffer.byteLength(obj);
465
- b[i++] = 109;
466
- b.writeUInt32BE(length, i);
467
- // @ts-ignore
468
- b.utf8Write(obj, i += 4);
469
- i += length;
470
- break;
471
- }
472
- case "number": {
473
- if (Number.isInteger(obj)) {
474
- const abs = Math.abs(obj);
475
- if (abs < 2147483648) {
476
- b[i++] = 98;
477
- b.writeInt32BE(obj, i);
478
- i += 4;
479
- }
480
- else if (abs < Number.MAX_SAFE_INTEGER) {
481
- b[i++] = 110;
482
- b[i++] = 8;
483
- b[i++] = Number(obj < 0);
484
- b.writeBigUInt64LE(BigInt(abs), i);
485
- i += 8;
486
- break;
487
- }
488
- else {
489
- b[i++] = 70;
490
- b.writeDoubleBE(obj, i);
491
- i += 8;
492
- }
493
- }
494
- else {
495
- b[i++] = 70;
496
- b.writeDoubleBE(obj, i);
497
- i += 8;
498
- }
499
- break;
500
- }
501
- case "bigint": {
502
- b[i++] = 110;
503
- b[i++] = 8;
504
- b[i++] = Number(obj < 0);
505
- b.writeBigUInt64LE(obj, i);
506
- i += 8;
507
- break;
508
- }
509
- case "object": {
510
- if (obj === null) {
511
- b[i++] = 100;
512
- b.writeUInt16BE(3, i);
513
- // @ts-ignore
514
- b.latin1Write("nil", i += 2);
515
- i += 3;
516
- }
517
- else if (Array.isArray(obj)) {
518
- if (obj.length) {
519
- b[i++] = 108;
520
- b.writeUInt32BE(obj.length, i);
521
- i += 4;
522
- for (const item of obj) {
523
- loop(item);
524
- }
525
- }
526
- b[i++] = 106;
527
- }
528
- else {
529
- const entries = Object.entries(obj).filter(x => typeof x[1] !== "undefined");
530
- b[i++] = 116;
531
- b.writeUInt32BE(entries.length, i);
532
- i += 4;
533
- for (const [key, value] of entries) {
534
- loop(key);
535
- loop(value);
536
- }
537
- }
538
- break;
539
- }
540
- }
541
- };
542
- loop(data);
543
- return Buffer.from(b.subarray(0, i));
544
- }
545
- module.exports = BetterWs;
@@ -1,44 +0,0 @@
1
- /// <reference types="node" />
2
- /**
3
- * RatelimitBucket, used for ratelimiting the execution of functions.
4
- */
5
- declare class RatelimitBucket {
6
- fnQueue: Array<{
7
- fn: () => unknown;
8
- callback: () => unknown;
9
- error: Error;
10
- }>;
11
- limit: number;
12
- remaining: number;
13
- limitReset: number;
14
- defaultReset: number | undefined;
15
- resetTimeout: NodeJS.Timeout | null;
16
- static readonly default: typeof RatelimitBucket;
17
- /**
18
- * Create a new Bucket.
19
- * @param limit Number of functions that may be executed during the timeframe set in limitReset.
20
- * @param limitReset Timeframe in milliseconds until the ratelimit resets.
21
- * @param defaultLimit If the bucket info does not provide default values, but provides remaining, this is the limit to use after the initial reset.
22
- * @param defaultReset If the bucket info does not provide default values, but provides remaining, this is the reset to use after the initial reset.
23
- */
24
- constructor(limit?: number, limitReset?: number, defaultReset?: number);
25
- /**
26
- * Queue a function to be executed.
27
- * @param fn Function to be executed.
28
- * @returns Result of the function if any.
29
- */
30
- queue<T>(fn: () => T): Promise<T>;
31
- /**
32
- * Check if there are any functions in the queue that haven't been executed yet.
33
- */
34
- private checkQueue;
35
- /**
36
- * Reset the remaining tokens to the base limit.
37
- */
38
- private resetRemaining;
39
- /**
40
- * Clear the current queue of events to be sent.
41
- */
42
- dropQueue(): void;
43
- }
44
- export = RatelimitBucket;
@@ -1,104 +0,0 @@
1
- "use strict";
2
- /**
3
- * RatelimitBucket, used for ratelimiting the execution of functions.
4
- */
5
- class RatelimitBucket {
6
- /**
7
- * Create a new Bucket.
8
- * @param limit Number of functions that may be executed during the timeframe set in limitReset.
9
- * @param limitReset Timeframe in milliseconds until the ratelimit resets.
10
- * @param defaultLimit If the bucket info does not provide default values, but provides remaining, this is the limit to use after the initial reset.
11
- * @param defaultReset If the bucket info does not provide default values, but provides remaining, this is the reset to use after the initial reset.
12
- */
13
- constructor(limit = 5, limitReset = 5000, defaultReset) {
14
- this.fnQueue = [];
15
- this.limit = limit;
16
- this.remaining = limit;
17
- this.limitReset = limitReset;
18
- this.resetTimeout = null;
19
- this.defaultReset = defaultReset;
20
- }
21
- /**
22
- * Queue a function to be executed.
23
- * @param fn Function to be executed.
24
- * @returns Result of the function if any.
25
- */
26
- queue(fn) {
27
- // More debug-ability
28
- const error = new Error("An Error occurred in the bucket queue");
29
- return new Promise((res, rej) => {
30
- const wrapFn = () => {
31
- this.remaining--;
32
- if (!this.resetTimeout) {
33
- this.resetTimeout = setTimeout(() => {
34
- try {
35
- this.resetRemaining();
36
- }
37
- catch (e) {
38
- rej(e);
39
- }
40
- }, this.limitReset).unref();
41
- }
42
- if (this.remaining !== 0)
43
- this.checkQueue().catch(rej);
44
- if (fn instanceof Promise) {
45
- return fn.then(res).catch((e) => {
46
- if (e) {
47
- e.stack = error.stack;
48
- return rej(e);
49
- }
50
- else
51
- return rej(error);
52
- });
53
- }
54
- return res(fn());
55
- };
56
- if (this.remaining === 0) {
57
- this.fnQueue.push({ fn, callback: wrapFn, error });
58
- this.checkQueue().catch(rej);
59
- }
60
- else
61
- wrapFn();
62
- });
63
- }
64
- /**
65
- * Check if there are any functions in the queue that haven't been executed yet.
66
- */
67
- async checkQueue() {
68
- if (this.fnQueue.length > 0 && this.remaining !== 0) {
69
- const queuedFunc = this.fnQueue.splice(0, 1)[0];
70
- try {
71
- queuedFunc.callback();
72
- }
73
- catch (e) {
74
- if (e) {
75
- e.stack = queuedFunc.error.stack;
76
- throw e;
77
- }
78
- else
79
- throw queuedFunc.error;
80
- }
81
- }
82
- }
83
- /**
84
- * Reset the remaining tokens to the base limit.
85
- */
86
- resetRemaining() {
87
- this.remaining = this.limit;
88
- if (this.defaultReset)
89
- this.limitReset = this.defaultReset;
90
- if (this.resetTimeout) {
91
- clearTimeout(this.resetTimeout);
92
- this.resetTimeout = null;
93
- }
94
- this.checkQueue();
95
- }
96
- /**
97
- * Clear the current queue of events to be sent.
98
- */
99
- dropQueue() {
100
- this.fnQueue = [];
101
- }
102
- }
103
- RatelimitBucket.default = RatelimitBucket;
104
- module.exports = RatelimitBucket;