sonic-ws 1.2.0 → 1.2.1-wtf

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.
package/README.md CHANGED
@@ -23,7 +23,8 @@ Security:
23
23
  - Built-in ability for handshake packets, preventing repetitive initiation checks in listeners (for example, removes if(!init) everywhere)
24
24
  - Built-in rate limiting for packets; ability for global send & receive, alongside per-packet rate limiting
25
25
  - Built-in disabling & enabling of packets to prevent abuse
26
- - Prevents any race conditions; your callbacks will not be called until they finish.
26
+ - Prevents any race conditions; your callbacks will not be called until the last one finishes. (Alongside async options!)
27
+ - Prevents niche bugs found in other websocket libraries, such as functions calling after the socket already closed.
27
28
 
28
29
  Performance & Scaling:
29
30
  - Can handle very large packets in microseconds
@@ -119,4 +120,6 @@ Some weird error messages when invalid inputs are in like CreatePacket() and stu
119
120
 
120
121
  Better error handling
121
122
 
122
- Some middleware support
123
+ Some middleware support
124
+
125
+ Debug menus for client/server
package/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 16;
2
+ export declare const VERSION = 17;
3
3
  /** Server data suffix */
4
4
  export declare const SERVER_SUFFIX = "SWS";
5
5
  /** Server data suffix in array */
package/dist/version.js CHANGED
@@ -18,7 +18,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.SERVER_SUFFIX_NUMS = exports.SERVER_SUFFIX = exports.VERSION = void 0;
19
19
  const StringUtil_1 = require("./ws/util/StringUtil");
20
20
  /** Current protocol version */
21
- exports.VERSION = 16;
21
+ exports.VERSION = 17;
22
22
  /** Server data suffix */
23
23
  exports.SERVER_SUFFIX = "SWS";
24
24
  /** Server data suffix in array */
@@ -166,8 +166,15 @@ class SonicWSCore {
166
166
  const key = data[0];
167
167
  const value = data.slice(1);
168
168
  const packet = this.serverPackets.getPacket(this.serverPackets.getTag(key));
169
+ if (packet.rereference && value.length == 0) {
170
+ if (packet.lastReceived[0] === undefined)
171
+ return this.invalidPacket("No previous value to rereference");
172
+ this.listenPacket(packet.lastReceived[0], key);
173
+ return;
174
+ }
169
175
  if (packet.dataBatching == 0) {
170
- this.listenPacket(await packet.listen(value, null), key);
176
+ const res = packet.lastReceived[0] = await packet.listen(value, null);
177
+ this.listenPacket(res, key);
171
178
  return;
172
179
  }
173
180
  const batchData = await BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
@@ -205,7 +212,7 @@ class SonicWSCore {
205
212
  * @param values The values to send
206
213
  */
207
214
  async send(tag, ...values) {
208
- const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values);
215
+ const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values, 0);
209
216
  if (packet.dataBatching == 0)
210
217
  this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
211
218
  else
@@ -4,10 +4,10 @@ import { PacketType } from "./PacketType";
4
4
  export type PacketTypeValidator = (data: Uint8Array, index: number) => Promise<[Uint8Array, false | any]>;
5
5
  export type PacketReceiveProcessor = (data: Uint8Array, validationResult: any, index: number) => any;
6
6
  export type PacketSendProcessor = (ident: string, ...data: any[]) => Promise<Uint8Array>;
7
- export declare function createValidator<T extends PacketType>(type: T, dataCap: number, dataMin: number, packet: Packet<T | T[]>, gzipCompression: boolean, rereference: boolean): PacketTypeValidator;
7
+ export declare function createValidator<T extends PacketType>(type: T, dataCap: number, dataMin: number, packet: Packet<T | T[]>, gzipCompression: boolean): PacketTypeValidator;
8
8
  export declare function createReceiveProcessor(type: PacketType, enumData: EnumPackage[], cap: number): PacketReceiveProcessor;
9
9
  /** Creates a function that processes a packet type */
10
- export declare function createSendProcessor(type: PacketType, gzipCompression: boolean, rereference: boolean): PacketSendProcessor;
10
+ export declare function createSendProcessor(type: PacketType, gzipCompression: boolean): PacketSendProcessor;
11
11
  export declare function createObjSendProcessor(packet: Packet<PacketType[]>): PacketSendProcessor;
12
12
  export declare function createObjReceiveProcessor(packet: Packet<PacketType[]>): PacketReceiveProcessor;
13
13
  export declare function createObjValidator(packet: Packet<PacketType[]>): PacketTypeValidator;
@@ -52,7 +52,7 @@ function VARINT_VERIF(cap, min) {
52
52
  };
53
53
  }
54
54
  ;
55
- function createValidator(type, dataCap, dataMin, packet, gzipCompression, rereference) {
55
+ function createValidator(type, dataCap, dataMin, packet, gzipCompression) {
56
56
  function genFunc() {
57
57
  switch (type) {
58
58
  case PacketType_1.PacketType.NONE: return (data) => data.length == 0;
@@ -149,29 +149,18 @@ function createValidator(type, dataCap, dataMin, packet, gzipCompression, rerefe
149
149
  }
150
150
  }
151
151
  const fn = genFunc();
152
- let parsed = null;
153
152
  return gzipCompression
154
153
  ? async (data, index) => {
155
- if (rereference && data.length == 0) {
156
- if (parsed == null)
157
- return [data, false];
158
- return parsed;
159
- }
160
154
  try {
161
155
  const dec = await (0, CompressionUtil_1.decompressGzip)(data);
162
- return parsed = [dec, fn(dec, index)];
156
+ return [dec, fn(dec, index)];
163
157
  }
164
158
  catch {
165
159
  return [data, false];
166
160
  }
167
161
  }
168
162
  : async (data, index) => {
169
- if (rereference && data.length == 0) {
170
- if (parsed == null)
171
- return [data, false];
172
- return parsed;
173
- }
174
- return parsed = [data, fn(data, index)];
163
+ return [data, fn(data, index)];
175
164
  };
176
165
  }
177
166
  function createReceiveProcessor(type, enumData, cap) {
@@ -215,7 +204,7 @@ function createReceiveProcessor(type, enumData, cap) {
215
204
  }
216
205
  }
217
206
  /** Creates a function that processes a packet type */
218
- function createSendProcessor(type, gzipCompression, rereference) {
207
+ function createSendProcessor(type, gzipCompression) {
219
208
  function genFunc() {
220
209
  switch (type) {
221
210
  case PacketType_1.PacketType.NONE: return () => [];
@@ -263,34 +252,19 @@ function createSendProcessor(type, gzipCompression, rereference) {
263
252
  }
264
253
  }
265
254
  const fn = genFunc();
266
- let lastSent;
267
255
  if (!gzipCompression) {
268
256
  return async (_, data) => {
269
- if (rereference) {
270
- const jstr = JSON.stringify(data);
271
- if (jstr == lastSent) {
272
- return CompressionUtil_1.EMPTY_UINT8;
273
- }
274
- lastSent = jstr;
275
- }
276
257
  return new Uint8Array(fn(data));
277
258
  };
278
259
  }
279
260
  return async (ident, data) => {
280
- if (rereference) {
281
- const jstr = JSON.stringify(data);
282
- if (jstr == lastSent) {
283
- return CompressionUtil_1.EMPTY_UINT8;
284
- }
285
- lastSent = jstr;
286
- }
287
261
  return (0, CompressionUtil_1.compressGzip)(new Uint8Array(fn(data)), ident);
288
262
  };
289
263
  }
290
264
  function createObjSendProcessor(packet) {
291
265
  const size = packet.type.length;
292
266
  // TODO: Add compression and add rereferences[]
293
- const processors = packet.type.map(t => createSendProcessor(t, false, false));
267
+ const processors = packet.type.map(t => createSendProcessor(t, false));
294
268
  return async (ident, data) => {
295
269
  let result = [];
296
270
  for (let i = 0; i < size; i++) {
@@ -321,7 +295,7 @@ function createObjReceiveProcessor(packet) {
321
295
  };
322
296
  }
323
297
  function createObjValidator(packet) {
324
- const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet, false, false));
298
+ const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet, false));
325
299
  return async (data) => {
326
300
  let index = 0, enums = 0, computedData = [];
327
301
  while (index < data.length) {
@@ -30,6 +30,8 @@ export declare class Packet<T extends (PacketType | readonly PacketType[])> {
30
30
  processSend: (data: any[]) => Promise<Uint8Array>;
31
31
  validate: (data: Uint8Array) => Promise<[Uint8Array, boolean]>;
32
32
  customValidator: ((socket: SonicWSConnection, ...values: any[]) => boolean) | null;
33
+ lastReceived: Record<number, any>;
34
+ lastSent: Record<number, any>;
33
35
  constructor(tag: string, schema: PacketSchema<T>, customValidator: ValidatorFunction, enabled: boolean, client: boolean);
34
36
  listen(value: Uint8Array, socket: SonicWSConnection | null): Promise<[processed: any, flatten: boolean] | string>;
35
37
  serialize(): number[];
@@ -50,6 +50,8 @@ class Packet {
50
50
  processSend;
51
51
  validate;
52
52
  customValidator;
53
+ lastReceived = {};
54
+ lastSent = {};
53
55
  constructor(tag, schema, customValidator, enabled, client) {
54
56
  this.tag = tag;
55
57
  this.defaultEnabled = enabled;
@@ -92,6 +92,7 @@ class SonicWSConnection {
92
92
  for (const tag of host.clientPackets.getTags()) {
93
93
  this.listeners[tag] = [];
94
94
  const pack = host.clientPackets.getPacket(tag);
95
+ pack.lastReceived[this.id] = undefined;
95
96
  this.enabledPackets[tag] = pack.defaultEnabled;
96
97
  this.asyncMap[tag] = pack.async;
97
98
  if (pack.async)
@@ -121,6 +122,9 @@ class SonicWSConnection {
121
122
  if (shouldCall)
122
123
  callback(true);
123
124
  }
125
+ for (const packet of host.clientPackets.getPackets()) {
126
+ delete packet.lastReceived[this.id];
127
+ }
124
128
  });
125
129
  }
126
130
  parseData(event) {
@@ -214,8 +218,14 @@ class SonicWSConnection {
214
218
  return;
215
219
  const [tag, value] = data;
216
220
  const packet = this.host.clientPackets.getPacket(tag);
221
+ if (packet.rereference && value.length == 0) {
222
+ if (packet.lastReceived[this.id] === undefined)
223
+ return this.invalidPacket("No previous value to rereference");
224
+ this.listenPacket(packet.lastReceived[this.id], tag);
225
+ return;
226
+ }
217
227
  if (packet.dataBatching == 0) {
218
- const res = await packet.listen(value, this);
228
+ const res = packet.lastReceived[this.id] = await packet.listen(value, this);
219
229
  this.listenPacket(res, tag);
220
230
  return;
221
231
  }
@@ -282,7 +292,7 @@ class SonicWSConnection {
282
292
  * @param values The values to send
283
293
  */
284
294
  async send(tag, ...values) {
285
- this.send_processed(...await (0, PacketUtils_1.processPacket)(this.host.serverPackets, tag, values));
295
+ this.send_processed(...await (0, PacketUtils_1.processPacket)(this.host.serverPackets, tag, values, this.id));
286
296
  }
287
297
  /**
288
298
  * Broadcasts a packet to all other users connected
@@ -219,7 +219,7 @@ class SonicWSServer {
219
219
  async broadcastTagged(tag, packetTag, ...values) {
220
220
  if (!this.tagsInv.has(tag))
221
221
  return;
222
- const data = await (0, PacketUtils_1.processPacket)(this.serverPackets, packetTag, values);
222
+ const data = await (0, PacketUtils_1.processPacket)(this.serverPackets, packetTag, values, -1);
223
223
  this.tagsInv.get(tag).forEach(conn => conn.send_processed(...data));
224
224
  }
225
225
  /**
@@ -229,7 +229,7 @@ class SonicWSServer {
229
229
  * @param values The values to send
230
230
  */
231
231
  async broadcastFiltered(tag, filter, ...values) {
232
- const data = await (0, PacketUtils_1.processPacket)(this.serverPackets, tag, values);
232
+ const data = await (0, PacketUtils_1.processPacket)(this.serverPackets, tag, values, -1);
233
233
  this.connections.filter(filter).forEach(conn => conn.send_processed(...data));
234
234
  }
235
235
  /**
@@ -9,7 +9,7 @@ import { EnumPackage } from "../enums/EnumType";
9
9
  * @param values The values
10
10
  * @returns The indexed code, the data, and the packet schema
11
11
  */
12
- export declare function processPacket(packets: PacketHolder, tag: string, values: any[]): Promise<[code: number, data: Uint8Array, packet: Packet<any>]>;
12
+ export declare function processPacket(packets: PacketHolder, tag: string, values: any[], id: number): Promise<[code: number, data: Uint8Array, packet: Packet<any>]>;
13
13
  /**
14
14
  * Calls the listener for a packet with error callback
15
15
  * @param listened The listened data
@@ -26,6 +26,7 @@ exports.UnFlattenData = UnFlattenData;
26
26
  const Packets_1 = require("../../packets/Packets");
27
27
  const PacketType_1 = require("../../packets/PacketType");
28
28
  const EnumType_1 = require("../enums/EnumType");
29
+ const CompressionUtil_1 = require("./CompressionUtil");
29
30
  /**
30
31
  * Processes and verifies values into a sendable format
31
32
  * @param packets Packet holder
@@ -33,7 +34,7 @@ const EnumType_1 = require("../enums/EnumType");
33
34
  * @param values The values
34
35
  * @returns The indexed code, the data, and the packet schema
35
36
  */
36
- async function processPacket(packets, tag, values) {
37
+ async function processPacket(packets, tag, values, id) {
37
38
  const code = packets.getKey(tag);
38
39
  const packet = packets.getPacket(tag);
39
40
  if (packet.autoFlatten) {
@@ -68,7 +69,15 @@ async function processPacket(packets, tag, values) {
68
69
  }
69
70
  }
70
71
  }
71
- return [code, values.length > 0 ? await packet.processSend(values) : new Uint8Array([]), packet];
72
+ const sendData = values.length > 0 ? await packet.processSend(values) : CompressionUtil_1.EMPTY_UINT8;
73
+ if (packet.rereference) {
74
+ if (id == -1)
75
+ throw new Error("Cannot broadcast a packet that is rereference-enabled");
76
+ if (packet.lastSent[id] == sendData)
77
+ return [code, CompressionUtil_1.EMPTY_UINT8, packet];
78
+ packet.lastSent[id] = sendData;
79
+ }
80
+ return [code, sendData, packet];
72
81
  }
73
82
  /**
74
83
  * Calls the listener for a packet with error callback
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonic-ws",
3
- "version": "1.2.0",
3
+ "version": "1.2.1-wtf",
4
4
  "description": "Ultra-lightweight, high-performance, and bandwidth efficient websocket library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",