sonic-ws 1.2.1-wtf → 1.2.2-why

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
@@ -16,6 +16,7 @@ Developer Friendly:
16
16
  - Keys are automatically indexed before transfer, improving readability and efficiency (for example, send("pixel") and send("p") use the same bandwidth)
17
17
  - Data is validated and supports custom validation, ensuring only valid, safe, and untampered packets ever call your listeners
18
18
  - Edge cases are heavily tested with heavy data ranges; supports code points fully up to the max of 0x10FFFF
19
+ - Debug tools to view all packets
19
20
 
20
21
  Security:
21
22
  - Tamper-proof; any invalid packet instantly causes closure, and tampering becomes incredibly difficult
package/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Current protocol version */
2
- export declare const VERSION = 17;
2
+ export declare const VERSION = 18;
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 = 17;
21
+ exports.VERSION = 18;
22
22
  /** Server data suffix */
23
23
  exports.SERVER_SUFFIX = "SWS";
24
24
  /** Server data suffix in array */
@@ -1,3 +1,11 @@
1
+ export interface BasicMiddleware {
2
+ init?(conn: Connection): void;
3
+ onReceive_pre(tag: string, data: Uint8Array): boolean | void;
4
+ onSend_pre(tag: string, values: any[]): boolean | void;
5
+ onReceive_post(tag: string, values: any[]): boolean | void;
6
+ onSend_post(tag: string, data: Uint8Array): boolean | void;
7
+ onStatusChange(status: number): void;
8
+ }
1
9
  /**
2
10
  * Holds shared connection values. Lets helper functions work on client and server.
3
11
  */
@@ -42,4 +50,8 @@ export interface Connection {
42
50
  * Closes the connection
43
51
  */
44
52
  close(code?: number, reason?: string): void;
53
+ /**
54
+ * Adds a basic middleware which can interact with packets
55
+ */
56
+ addBasicMiddleware(middleware: BasicMiddleware): void;
45
57
  }
@@ -15,3 +15,4 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
+ ;
@@ -1,5 +1,5 @@
1
1
  import { PacketHolder } from '../../util/packets/PacketHolder';
2
- import { Connection } from '../../Connection';
2
+ import { BasicMiddleware, Connection } from '../../Connection';
3
3
  export declare abstract class SonicWSCore implements Connection {
4
4
  /** Raw 'ws' library connection / webjs WebSocket class */
5
5
  socket: WebSocket;
@@ -24,6 +24,7 @@ export declare abstract class SonicWSCore implements Connection {
24
24
  _timers: Record<number, [number, (closed: boolean) => void, boolean]>;
25
25
  private asyncData;
26
26
  private asyncMap;
27
+ private _state;
27
28
  constructor(ws: WebSocket, bufferHandler: (val: MessageEvent) => Promise<Uint8Array>);
28
29
  private reading;
29
30
  private readQueue;
@@ -31,9 +32,12 @@ export declare abstract class SonicWSCore implements Connection {
31
32
  private invalidPacket;
32
33
  private listenLock;
33
34
  private packetQueue;
34
- listenPacket(data: string | [any[], boolean], code: number): void;
35
+ listenPacket(data: string | [any[], boolean], code: number): Promise<void>;
35
36
  private isAsync;
36
37
  private enqueuePacket;
38
+ private basicMiddlewares;
39
+ addBasicMiddleware(middleware: BasicMiddleware): void;
40
+ private callMiddleware;
37
41
  private messageHandler;
38
42
  protected listen(key: string, listener: (data: any[]) => void): void;
39
43
  /**
@@ -38,6 +38,7 @@ class SonicWSCore {
38
38
  _timers = {};
39
39
  asyncData = {};
40
40
  asyncMap = {};
41
+ _state = WebSocket.OPEN;
41
42
  constructor(ws, bufferHandler) {
42
43
  this.socket = ws;
43
44
  this.listeners = {
@@ -52,7 +53,9 @@ class SonicWSCore {
52
53
  this.serverKeyHandler = this.serverKeyHandler.bind(this);
53
54
  this.messageHandler = this.messageHandler.bind(this);
54
55
  this.socket.addEventListener('message', this.serverKeyHandler);
55
- this.socket.addEventListener('close', (event) => {
56
+ this.socket.addEventListener('open', () => this.callMiddleware('onStatusChange', WebSocket.OPEN));
57
+ this.socket.addEventListener('close', event => {
58
+ this.callMiddleware('onStatusChange', WebSocket.CLOSED);
56
59
  this.listeners.close.forEach(listener => listener(event));
57
60
  for (const [id, callback, shouldCall] of Object.values(this._timers)) {
58
61
  this.clearTimeout(id);
@@ -115,7 +118,9 @@ class SonicWSCore {
115
118
  }
116
119
  listenLock = false;
117
120
  packetQueue = [];
118
- listenPacket(data, code) {
121
+ async listenPacket(data, code) {
122
+ if (await this.callMiddleware('onReceive_post', this.serverPackets.getTag(code), typeof data == 'string' ? [data] : data[0]))
123
+ return;
119
124
  const listeners = this.listeners.event[code];
120
125
  if (!listeners)
121
126
  return console.warn("Warn: No listener for packet " + code);
@@ -158,6 +163,35 @@ class SonicWSCore {
158
163
  else
159
164
  this.listenLock = false;
160
165
  }
166
+ basicMiddlewares = [];
167
+ addBasicMiddleware(middleware) {
168
+ this.basicMiddlewares.push(middleware);
169
+ const m = middleware;
170
+ try {
171
+ if (typeof m.init === 'function')
172
+ m.init(this);
173
+ }
174
+ catch (e) {
175
+ console.warn('Middleware init threw an error:', e);
176
+ }
177
+ }
178
+ async callMiddleware(method, ...values) {
179
+ let cancelled = false;
180
+ for (const middleware of this.basicMiddlewares) {
181
+ const fn = middleware[method];
182
+ if (!fn)
183
+ continue;
184
+ try {
185
+ if (await fn(...values)) {
186
+ cancelled = true;
187
+ }
188
+ }
189
+ catch (e) {
190
+ console.warn(`Middleware ${String(method)} threw an error:`, e);
191
+ }
192
+ }
193
+ return cancelled;
194
+ }
161
195
  async messageHandler(event) {
162
196
  const data = await this.bufferHandler(event);
163
197
  this.listeners.message.forEach(listener => listener(data));
@@ -166,6 +200,8 @@ class SonicWSCore {
166
200
  const key = data[0];
167
201
  const value = data.slice(1);
168
202
  const packet = this.serverPackets.getPacket(this.serverPackets.getTag(key));
203
+ if (await this.callMiddleware('onReceive_pre', packet.tag, data))
204
+ return;
169
205
  if (packet.rereference && value.length == 0) {
170
206
  if (packet.lastReceived[0] === undefined)
171
207
  return this.invalidPacket("No previous value to rereference");
@@ -212,7 +248,11 @@ class SonicWSCore {
212
248
  * @param values The values to send
213
249
  */
214
250
  async send(tag, ...values) {
251
+ if (await this.callMiddleware('onSend_pre', tag, values))
252
+ return;
215
253
  const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values, 0);
254
+ if (await this.callMiddleware('onSend_post', tag, data))
255
+ return;
216
256
  if (packet.dataBatching == 0)
217
257
  this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
218
258
  else
@@ -1,7 +1,7 @@
1
1
  import * as WS from 'ws';
2
2
  import { SonicWSServer } from './SonicWSServer';
3
3
  import { Packet } from '../packets/Packets';
4
- import { Connection } from '../Connection';
4
+ import { BasicMiddleware, Connection } from '../Connection';
5
5
  export declare class SonicWSConnection implements Connection {
6
6
  /** Raw 'ws' library socket */
7
7
  socket: WS.WebSocket;
@@ -23,6 +23,7 @@ export declare class SonicWSConnection implements Connection {
23
23
  private asyncMap;
24
24
  private asyncData;
25
25
  private closed;
26
+ private _state;
26
27
  constructor(socket: WS.WebSocket, host: SonicWSServer, id: number, handshakePacket: string | null, clientRateLimit: number, serverRateLimit: number);
27
28
  private parseData;
28
29
  private handshakeHandler;
@@ -32,6 +33,9 @@ export declare class SonicWSConnection implements Connection {
32
33
  private packetQueue;
33
34
  private listenPacket;
34
35
  private messageHandler;
36
+ private basicMiddlewares;
37
+ addBasicMiddleware(middleware: BasicMiddleware): void;
38
+ private callMiddleware;
35
39
  /**
36
40
  * Enables a packet for the client.
37
41
  * @param tag The tag of the packet
@@ -83,6 +83,7 @@ class SonicWSConnection {
83
83
  asyncMap = {};
84
84
  asyncData = {};
85
85
  closed = false;
86
+ _state = WebSocket.OPEN;
86
87
  constructor(socket, host, id, handshakePacket, clientRateLimit, serverRateLimit) {
87
88
  this.socket = socket;
88
89
  this.host = host;
@@ -115,7 +116,9 @@ class SonicWSConnection {
115
116
  this.handshakeLambda = (data) => this.handshakeHandler(data);
116
117
  this.socket.addEventListener('message', this.handshakeLambda);
117
118
  }
119
+ this.socket.on('open', () => this.callMiddleware('onStatusChange', WebSocket.OPEN));
118
120
  this.socket.on('close', () => {
121
+ this.callMiddleware('onStatusChange', WebSocket.CLOSED);
119
122
  this.closed = true;
120
123
  for (const [id, callback, shouldCall] of Object.values(this._timers)) {
121
124
  this.clearTimeout(id);
@@ -181,6 +184,8 @@ class SonicWSConnection {
181
184
  async listenPacket(data, tag) {
182
185
  if (this.closed)
183
186
  return;
187
+ if (await this.callMiddleware('onReceive_post', tag, typeof data == 'string' ? [data] : data[0]))
188
+ return;
184
189
  const isAsync = this.isAsync(tag);
185
190
  let locked, packetQueue, asyncData;
186
191
  if (isAsync) {
@@ -218,6 +223,8 @@ class SonicWSConnection {
218
223
  return;
219
224
  const [tag, value] = data;
220
225
  const packet = this.host.clientPackets.getPacket(tag);
226
+ if (await this.callMiddleware('onReceive_pre', packet.tag, value))
227
+ return;
221
228
  if (packet.rereference && value.length == 0) {
222
229
  if (packet.lastReceived[this.id] === undefined)
223
230
  return this.invalidPacket("No previous value to rereference");
@@ -236,6 +243,35 @@ class SonicWSConnection {
236
243
  this.listenPacket(data, tag);
237
244
  }
238
245
  }
246
+ basicMiddlewares = [];
247
+ addBasicMiddleware(middleware) {
248
+ this.basicMiddlewares.push(middleware);
249
+ const m = middleware;
250
+ try {
251
+ if (typeof m.init === 'function')
252
+ m.init(this);
253
+ }
254
+ catch (e) {
255
+ console.warn('Middleware init threw an error:', e);
256
+ }
257
+ }
258
+ async callMiddleware(method, ...values) {
259
+ let cancelled = false;
260
+ for (const middleware of this.basicMiddlewares) {
261
+ const fn = middleware[method];
262
+ if (!fn)
263
+ continue;
264
+ try {
265
+ if (!await fn(...values)) {
266
+ cancelled = true;
267
+ }
268
+ }
269
+ catch (e) {
270
+ console.warn(`Middleware ${String(method)} threw an error:`, e);
271
+ }
272
+ }
273
+ return cancelled;
274
+ }
239
275
  /**
240
276
  * Enables a packet for the client.
241
277
  * @param tag The tag of the packet
@@ -292,7 +328,12 @@ class SonicWSConnection {
292
328
  * @param values The values to send
293
329
  */
294
330
  async send(tag, ...values) {
295
- this.send_processed(...await (0, PacketUtils_1.processPacket)(this.host.serverPackets, tag, values, this.id));
331
+ if (await this.callMiddleware('onSend_pre', tag, values))
332
+ return;
333
+ const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.host.serverPackets, tag, values, this.id);
334
+ if (await this.callMiddleware('onSend_post', tag, data))
335
+ return;
336
+ this.send_processed(code, data, packet);
296
337
  }
297
338
  /**
298
339
  * Broadcasts a packet to all other users connected
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonic-ws",
3
- "version": "1.2.1-wtf",
3
+ "version": "1.2.2-why",
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",