sonic-ws 1.2.1 → 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 +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/ws/Connection.d.ts +12 -0
- package/dist/ws/Connection.js +1 -0
- package/dist/ws/client/core/ClientCore.d.ts +6 -2
- package/dist/ws/client/core/ClientCore.js +42 -2
- package/dist/ws/server/SonicWSConnection.d.ts +5 -1
- package/dist/ws/server/SonicWSConnection.js +42 -1
- package/package.json +1 -1
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
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 =
|
|
21
|
+
exports.VERSION = 18;
|
|
22
22
|
/** Server data suffix */
|
|
23
23
|
exports.SERVER_SUFFIX = "SWS";
|
|
24
24
|
/** Server data suffix in array */
|
package/dist/ws/Connection.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/ws/Connection.js
CHANGED
|
@@ -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('
|
|
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
|
-
|
|
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
|