sonic-ws 1.1.1 → 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 +9 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/ws/client/core/ClientCore.d.ts +2 -1
- package/dist/ws/client/core/ClientCore.js +24 -15
- package/dist/ws/packets/PacketProcessors.d.ts +4 -10
- package/dist/ws/packets/PacketProcessors.js +173 -125
- package/dist/ws/packets/PacketType.d.ts +7 -1
- package/dist/ws/packets/PacketType.js +6 -0
- package/dist/ws/packets/Packets.d.ts +12 -6
- package/dist/ws/packets/Packets.js +41 -40
- package/dist/ws/server/SonicWSConnection.d.ts +1 -1
- package/dist/ws/server/SonicWSConnection.js +15 -5
- package/dist/ws/server/SonicWSServer.d.ts +4 -2
- package/dist/ws/server/SonicWSServer.js +20 -17
- package/dist/ws/util/packets/BatchHelper.d.ts +1 -1
- package/dist/ws/util/packets/BatchHelper.js +2 -2
- package/dist/ws/util/packets/CompressionUtil.d.ts +7 -0
- package/dist/ws/util/packets/CompressionUtil.js +202 -1
- package/dist/ws/util/packets/PacketHolder.d.ts +1 -1
- package/dist/ws/util/packets/PacketHolder.js +1 -1
- package/dist/ws/util/packets/PacketUtils.d.ts +10 -1
- package/dist/ws/util/packets/PacketUtils.js +35 -12
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -7,8 +7,9 @@ SonicWS is an ultra-lightweight, high-performance WebSocket library focused on m
|
|
|
7
7
|
Compression:
|
|
8
8
|
- Lossless compression up to 70% or more (for example, 38kb -> 14kb)
|
|
9
9
|
- Optimized bandwidth for many different types to fit special constraints
|
|
10
|
-
- Automatic helpers to flatten typed nested arrays for maximum wire efficiency (for example, [[1,
|
|
10
|
+
- Automatic helpers to flatten typed nested arrays for maximum wire efficiency (for example, [[1,false,"text"],[4,true,"other"]] to [[1,4],[false,true],["text,"other"]])
|
|
11
11
|
- Uses raw binary bytes to transmit data as efficiently as possible while still using high level readable code
|
|
12
|
+
- Built-in ability to use compression libraries
|
|
12
13
|
|
|
13
14
|
Developer Friendly:
|
|
14
15
|
- Predefined data types of various sized integers, single and double precision floating point numbers, strings, enums, etc. and RAW to allow for developers to do anything they want
|
|
@@ -22,7 +23,8 @@ Security:
|
|
|
22
23
|
- Built-in ability for handshake packets, preventing repetitive initiation checks in listeners (for example, removes if(!init) everywhere)
|
|
23
24
|
- Built-in rate limiting for packets; ability for global send & receive, alongside per-packet rate limiting
|
|
24
25
|
- Built-in disabling & enabling of packets to prevent abuse
|
|
25
|
-
- Prevents any race conditions; your callbacks will not be called until
|
|
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.
|
|
26
28
|
|
|
27
29
|
Performance & Scaling:
|
|
28
30
|
- Can handle very large packets in microseconds
|
|
@@ -38,8 +40,9 @@ Developer Experience:
|
|
|
38
40
|
- Debug tools for socket ids, byte size, data logging, etc. for troubleshooting
|
|
39
41
|
- Very minimal learning curve, easy to work in
|
|
40
42
|
- JSDoc's for understanding; immensely intuitive (personally, I took a break for half a year and came back and snapped right back in)
|
|
43
|
+
- Almost every case has a pre-made wire optimization and boilerplate removal.
|
|
41
44
|
|
|
42
|
-
Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets
|
|
45
|
+
Whether you're making a real-time game, a dashboard, a distributed system, or anything else, SonicWS gets you safe, structured packets; fast.
|
|
43
46
|
|
|
44
47
|
## SAMPLES
|
|
45
48
|
|
|
@@ -117,4 +120,6 @@ Some weird error messages when invalid inputs are in like CreatePacket() and stu
|
|
|
117
120
|
|
|
118
121
|
Better error handling
|
|
119
122
|
|
|
120
|
-
|
|
123
|
+
Some middleware support
|
|
124
|
+
|
|
125
|
+
Debug menus for client/server
|
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 = 17;
|
|
22
22
|
/** Server data suffix */
|
|
23
23
|
exports.SERVER_SUFFIX = "SWS";
|
|
24
24
|
/** Server data suffix in array */
|
|
@@ -26,6 +26,7 @@ export declare abstract class SonicWSCore implements Connection {
|
|
|
26
26
|
private asyncMap;
|
|
27
27
|
constructor(ws: WebSocket, bufferHandler: (val: MessageEvent) => Promise<Uint8Array>);
|
|
28
28
|
private reading;
|
|
29
|
+
private readQueue;
|
|
29
30
|
private serverKeyHandler;
|
|
30
31
|
private invalidPacket;
|
|
31
32
|
private listenLock;
|
|
@@ -50,7 +51,7 @@ export declare abstract class SonicWSCore implements Connection {
|
|
|
50
51
|
* @param tag The tag of the packet
|
|
51
52
|
* @param values The values to send
|
|
52
53
|
*/
|
|
53
|
-
send(tag: string, ...values: any[]): void
|
|
54
|
+
send(tag: string, ...values: any[]): Promise<void>;
|
|
54
55
|
/**
|
|
55
56
|
* Listens for when the client connects
|
|
56
57
|
* @param listener Callback on connection
|
|
@@ -63,27 +63,28 @@ class SonicWSCore {
|
|
|
63
63
|
this.bufferHandler = bufferHandler;
|
|
64
64
|
}
|
|
65
65
|
reading = false;
|
|
66
|
+
readQueue = [];
|
|
66
67
|
async serverKeyHandler(event) {
|
|
67
|
-
// stupid asynchronous bullshit
|
|
68
68
|
if (this.reading)
|
|
69
|
-
return this.
|
|
69
|
+
return this.readQueue.push(event);
|
|
70
70
|
this.reading = true;
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
71
|
+
const cdata = await this.bufferHandler(event);
|
|
72
|
+
if (cdata.length < 3 || (0, BufferUtil_1.as8String)(cdata.slice(0, 3)) != version_1.SERVER_SUFFIX) {
|
|
73
73
|
this.socket.close(1000);
|
|
74
74
|
throw new Error("The server requested is not a Sonic WS server.");
|
|
75
75
|
}
|
|
76
|
-
const version =
|
|
76
|
+
const version = cdata[3];
|
|
77
77
|
if (version != version_1.VERSION) {
|
|
78
78
|
this.socket.close(1000);
|
|
79
79
|
throw new Error(`Version mismatch: ${version > version_1.VERSION ? "client" : "server"} is outdated (server: ${version}, client: ${version_1.VERSION})`);
|
|
80
80
|
}
|
|
81
|
-
const
|
|
81
|
+
const data = await (0, CompressionUtil_1.decompressGzip)(cdata.subarray(4, cdata.length));
|
|
82
|
+
const [ckOff, id] = (0, CompressionUtil_1.readVarInt)(data, 0);
|
|
82
83
|
this.id = id;
|
|
83
84
|
const [valuesOff, ckLength] = (0, CompressionUtil_1.readVarInt)(data, ckOff);
|
|
84
|
-
const ckData = data.
|
|
85
|
+
const ckData = data.subarray(valuesOff, valuesOff + ckLength);
|
|
85
86
|
this.clientPackets.holdPackets(Packets_1.Packet.deserializeAll(ckData, true));
|
|
86
|
-
const skData = data.
|
|
87
|
+
const skData = data.subarray(valuesOff + ckLength, data.length);
|
|
87
88
|
this.serverPackets.holdPackets(Packets_1.Packet.deserializeAll(skData, true));
|
|
88
89
|
this.batcher.registerSendPackets(this.clientPackets, this);
|
|
89
90
|
for (const p of this.serverPackets.getPackets()) {
|
|
@@ -105,6 +106,8 @@ class SonicWSCore {
|
|
|
105
106
|
this.readyListeners = null; // clear
|
|
106
107
|
this.socket.removeEventListener('message', this.serverKeyHandler);
|
|
107
108
|
this.socket.addEventListener('message', this.messageHandler);
|
|
109
|
+
this.readQueue.forEach(e => this.messageHandler(e));
|
|
110
|
+
this.readQueue = [];
|
|
108
111
|
}
|
|
109
112
|
invalidPacket(listened) {
|
|
110
113
|
console.error(listened);
|
|
@@ -136,7 +139,7 @@ class SonicWSCore {
|
|
|
136
139
|
packetQueue = this.packetQueue;
|
|
137
140
|
}
|
|
138
141
|
if (locked) {
|
|
139
|
-
packetQueue.push(
|
|
142
|
+
packetQueue.push(data);
|
|
140
143
|
return;
|
|
141
144
|
}
|
|
142
145
|
if (isAsync)
|
|
@@ -144,12 +147,11 @@ class SonicWSCore {
|
|
|
144
147
|
else
|
|
145
148
|
this.listenLock = true;
|
|
146
149
|
let currentData = data;
|
|
147
|
-
let currentCode = code;
|
|
148
150
|
while (true) {
|
|
149
151
|
await (0, PacketUtils_1.listenPacket)(currentData, listeners, this.invalidPacket);
|
|
150
152
|
if (packetQueue.length === 0)
|
|
151
153
|
break;
|
|
152
|
-
|
|
154
|
+
currentData = packetQueue.shift();
|
|
153
155
|
}
|
|
154
156
|
if (isAsync)
|
|
155
157
|
asyncData[0] = false;
|
|
@@ -164,11 +166,18 @@ class SonicWSCore {
|
|
|
164
166
|
const key = data[0];
|
|
165
167
|
const value = data.slice(1);
|
|
166
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
|
+
}
|
|
167
175
|
if (packet.dataBatching == 0) {
|
|
168
|
-
|
|
176
|
+
const res = packet.lastReceived[0] = await packet.listen(value, null);
|
|
177
|
+
this.listenPacket(res, key);
|
|
169
178
|
return;
|
|
170
179
|
}
|
|
171
|
-
const batchData = BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
|
|
180
|
+
const batchData = await BatchHelper_1.BatchHelper.unravelBatch(packet, value, null);
|
|
172
181
|
if (typeof batchData == 'string')
|
|
173
182
|
return this.invalidPacket(batchData);
|
|
174
183
|
batchData.forEach(data => this.listenPacket(data, key));
|
|
@@ -202,8 +211,8 @@ class SonicWSCore {
|
|
|
202
211
|
* @param tag The tag of the packet
|
|
203
212
|
* @param values The values to send
|
|
204
213
|
*/
|
|
205
|
-
send(tag, ...values) {
|
|
206
|
-
const [code, data, packet] = (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values);
|
|
214
|
+
async send(tag, ...values) {
|
|
215
|
+
const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.clientPackets, tag, values, 0);
|
|
207
216
|
if (packet.dataBatching == 0)
|
|
208
217
|
this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
|
|
209
218
|
else
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { EnumPackage } from "../util/enums/EnumType";
|
|
2
2
|
import { Packet } from "./Packets";
|
|
3
3
|
import { PacketType } from "./PacketType";
|
|
4
|
-
export type PacketTypeValidator = (data: Uint8Array, index: number) => false | any
|
|
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
|
-
export type PacketSendProcessor = (...data: any) =>
|
|
7
|
-
export declare function createValidator<T extends PacketType>(type: T, dataCap: number, dataMin: number, packet: Packet<T | T[]
|
|
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): 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): 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;
|
|
14
|
-
type BuildTuple<T, N extends number, R extends unknown[] = []> = R['length'] extends N ? R : BuildTuple<T, N, [T, ...R]>;
|
|
15
|
-
export type PacketResponse<T extends PacketType | readonly PacketType[], N extends number | readonly number[]> = T extends PacketType[] ? N extends number[] ? PacketResponseArray<T, N> : never : BuildTuple<T extends PacketType.NONE ? undefined : T extends PacketType.RAW ? Uint8Array : T extends PacketType.BYTES | PacketType.UBYTES ? number : T extends PacketType.SHORTS | PacketType.USHORTS ? number : T extends PacketType.VARINT | PacketType.UVARINT | PacketType.DELTAS ? number : T extends PacketType.FLOATS | PacketType.DOUBLES ? number : T extends PacketType.BOOLEANS ? boolean : T extends PacketType.STRINGS_ASCII | PacketType.STRINGS_UTF16 ? string : T extends PacketType.ENUMS ? any : never, N extends number ? N : never>;
|
|
16
|
-
type PacketResponseArray<T extends PacketType[], N extends number[]> = {
|
|
17
|
-
[K in keyof T]: K extends number ? PacketResponse<T[K], N[K] & number> : never;
|
|
18
|
-
};
|
|
19
|
-
export {};
|
|
@@ -52,91 +52,116 @@ function VARINT_VERIF(cap, min) {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
;
|
|
55
|
-
function createValidator(type, dataCap, dataMin, packet) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const pkg = packet.enumData[index];
|
|
63
|
-
for (let i = 0; i < data.length; i++) {
|
|
64
|
-
if (pkg.values.length <= data[i])
|
|
55
|
+
function createValidator(type, dataCap, dataMin, packet, gzipCompression) {
|
|
56
|
+
function genFunc() {
|
|
57
|
+
switch (type) {
|
|
58
|
+
case PacketType_1.PacketType.NONE: return (data) => data.length == 0;
|
|
59
|
+
case PacketType_1.PacketType.RAW: return () => undefined;
|
|
60
|
+
case PacketType_1.PacketType.ENUMS: return (data, index) => {
|
|
61
|
+
if (data.length < dataMin || data.length > dataCap || index >= packet.enumData.length)
|
|
65
62
|
return false;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
lengths
|
|
110
|
-
totalLength
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
while (index < data.length) {
|
|
119
|
-
sectors++;
|
|
120
|
-
if (sectors > dataCap)
|
|
63
|
+
const pkg = packet.enumData[index];
|
|
64
|
+
for (let i = 0; i < data.length; i++) {
|
|
65
|
+
if (pkg.values.length <= data[i])
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
case PacketType_1.PacketType.BYTES: return BYTE_LEN(dataCap, dataMin);
|
|
70
|
+
case PacketType_1.PacketType.UBYTES: return BYTE_LEN(dataCap, dataMin);
|
|
71
|
+
case PacketType_1.PacketType.HEX: return BYTE_LEN(dataCap, dataMin);
|
|
72
|
+
case PacketType_1.PacketType.SHORTS: return SHORT_LEN(dataCap, dataMin);
|
|
73
|
+
case PacketType_1.PacketType.USHORTS: return SHORT_LEN(dataCap, dataMin);
|
|
74
|
+
case PacketType_1.PacketType.VARINT: return VARINT_VERIF(dataCap, dataMin);
|
|
75
|
+
case PacketType_1.PacketType.UVARINT: return VARINT_VERIF(dataCap, dataMin);
|
|
76
|
+
case PacketType_1.PacketType.DELTAS: return VARINT_VERIF(dataCap, dataMin);
|
|
77
|
+
case PacketType_1.PacketType.FLOATS: return (data) => {
|
|
78
|
+
if (data.length % 4 !== 0)
|
|
79
|
+
return false;
|
|
80
|
+
const sectors = data.length * CompressionUtil_1.ONE_FOURTH;
|
|
81
|
+
if (sectors > dataCap || sectors < dataMin)
|
|
82
|
+
return false;
|
|
83
|
+
return undefined;
|
|
84
|
+
};
|
|
85
|
+
case PacketType_1.PacketType.DOUBLES: return (data) => {
|
|
86
|
+
if (data.length % 8 !== 0)
|
|
87
|
+
return false;
|
|
88
|
+
const sectors = data.length * CompressionUtil_1.ONE_EIGHT;
|
|
89
|
+
if (sectors > dataCap || sectors < dataMin)
|
|
90
|
+
return false;
|
|
91
|
+
return undefined;
|
|
92
|
+
};
|
|
93
|
+
case PacketType_1.PacketType.BOOLEANS:
|
|
94
|
+
{
|
|
95
|
+
const min = Math.ceil(dataMin * CompressionUtil_1.ONE_EIGHT);
|
|
96
|
+
const cap = Math.ceil(dataCap * CompressionUtil_1.ONE_EIGHT);
|
|
97
|
+
return (data) => data.length >= min && data.length <= cap;
|
|
98
|
+
}
|
|
99
|
+
;
|
|
100
|
+
case PacketType_1.PacketType.STRINGS_ASCII: return (data) => {
|
|
101
|
+
let index = 0;
|
|
102
|
+
const [offCount, stringCount] = (0, CompressionUtil_1.readVarInt)(data, index);
|
|
103
|
+
index = offCount;
|
|
104
|
+
if (stringCount < dataMin || stringCount > dataCap)
|
|
105
|
+
return false;
|
|
106
|
+
const lengths = [];
|
|
107
|
+
let totalLength = 0;
|
|
108
|
+
for (let i = 0; i < stringCount; i++) {
|
|
109
|
+
const [offLen, strLen] = (0, CompressionUtil_1.readVarInt)(data, index);
|
|
110
|
+
index = offLen;
|
|
111
|
+
lengths.push(strLen);
|
|
112
|
+
totalLength += strLen;
|
|
113
|
+
}
|
|
114
|
+
if (index + Math.ceil(totalLength / 8) > data.length)
|
|
121
115
|
return false;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (
|
|
116
|
+
return [stringCount, lengths, index];
|
|
117
|
+
};
|
|
118
|
+
case PacketType_1.PacketType.STRINGS_UTF16: return (data) => {
|
|
119
|
+
let sectors = 0, index = 0, computed = [];
|
|
120
|
+
while (index < data.length) {
|
|
121
|
+
sectors++;
|
|
122
|
+
if (sectors > dataCap)
|
|
129
123
|
return false;
|
|
130
|
-
|
|
124
|
+
const [off, strLength] = (0, CompressionUtil_1.readVarInt)(data, index);
|
|
125
|
+
index = off;
|
|
126
|
+
let string = [];
|
|
127
|
+
for (let i = 0; i < strLength; i++) {
|
|
128
|
+
const [newOff, char] = (0, CompressionUtil_1.readVarInt)(data, index);
|
|
129
|
+
index = newOff;
|
|
130
|
+
if (index > data.length)
|
|
131
|
+
return false;
|
|
132
|
+
string.push(char);
|
|
133
|
+
}
|
|
134
|
+
computed.push(string);
|
|
131
135
|
}
|
|
132
|
-
|
|
136
|
+
if (sectors < dataMin)
|
|
137
|
+
return false;
|
|
138
|
+
return computed;
|
|
139
|
+
};
|
|
140
|
+
case PacketType_1.PacketType.JSON: return (data) => {
|
|
141
|
+
try {
|
|
142
|
+
return (0, CompressionUtil_1.decompressJSON)(data);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
default: throw new Error("Unknown type: " + type);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const fn = genFunc();
|
|
152
|
+
return gzipCompression
|
|
153
|
+
? async (data, index) => {
|
|
154
|
+
try {
|
|
155
|
+
const dec = await (0, CompressionUtil_1.decompressGzip)(data);
|
|
156
|
+
return [dec, fn(dec, index)];
|
|
133
157
|
}
|
|
134
|
-
|
|
135
|
-
return false;
|
|
136
|
-
|
|
158
|
+
catch {
|
|
159
|
+
return [data, false];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
: async (data, index) => {
|
|
163
|
+
return [data, fn(data, index)];
|
|
137
164
|
};
|
|
138
|
-
default: throw new Error("Unknown type: " + type);
|
|
139
|
-
}
|
|
140
165
|
}
|
|
141
166
|
function createReceiveProcessor(type, enumData, cap) {
|
|
142
167
|
switch (type) {
|
|
@@ -144,6 +169,7 @@ function createReceiveProcessor(type, enumData, cap) {
|
|
|
144
169
|
case PacketType_1.PacketType.RAW: return (data) => data;
|
|
145
170
|
case PacketType_1.PacketType.BYTES: return (data) => Array.from(data).map(CompressionUtil_1.demapZigZag);
|
|
146
171
|
case PacketType_1.PacketType.UBYTES: return (data) => Array.from(data);
|
|
172
|
+
case PacketType_1.PacketType.HEX: return (data) => (0, CompressionUtil_1.bytesToHex)(data);
|
|
147
173
|
case PacketType_1.PacketType.SHORTS: return (data) => (0, BufferUtil_1.splitBuffer)(data, 2).map(v => (0, CompressionUtil_1.demapShort_ZZ)(v));
|
|
148
174
|
case PacketType_1.PacketType.USHORTS: return (data) => (0, BufferUtil_1.splitBuffer)(data, 2).map(v => (0, CompressionUtil_1.fromShort)(v));
|
|
149
175
|
case PacketType_1.PacketType.VARINT: return (_, computed) => computed.map(CompressionUtil_1.demapZigZag);
|
|
@@ -170,64 +196,86 @@ function createReceiveProcessor(type, enumData, cap) {
|
|
|
170
196
|
}
|
|
171
197
|
return strings;
|
|
172
198
|
};
|
|
173
|
-
case PacketType_1.PacketType.STRINGS_UTF16: return (
|
|
199
|
+
case PacketType_1.PacketType.STRINGS_UTF16: return (_, computed) => {
|
|
174
200
|
return computed.map(codes => String.fromCodePoint(...codes));
|
|
175
201
|
};
|
|
202
|
+
case PacketType_1.PacketType.JSON: return (_, computed) => computed;
|
|
176
203
|
default: throw new Error("Unknown type: " + type);
|
|
177
204
|
}
|
|
178
205
|
}
|
|
179
206
|
/** Creates a function that processes a packet type */
|
|
180
|
-
function createSendProcessor(type) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
];
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
function createSendProcessor(type, gzipCompression) {
|
|
208
|
+
function genFunc() {
|
|
209
|
+
switch (type) {
|
|
210
|
+
case PacketType_1.PacketType.NONE: return () => [];
|
|
211
|
+
case PacketType_1.PacketType.RAW: return (data) => Array.from(data);
|
|
212
|
+
case PacketType_1.PacketType.ENUMS: return (enums) => enums;
|
|
213
|
+
case PacketType_1.PacketType.BYTES: return (numbers) => numbers.map(CompressionUtil_1.mapZigZag);
|
|
214
|
+
case PacketType_1.PacketType.UBYTES: return (numbers) => numbers.map(CompressionUtil_1.toByte);
|
|
215
|
+
case PacketType_1.PacketType.HEX: return (hex) => {
|
|
216
|
+
if (typeof hex != "string") {
|
|
217
|
+
if (hex instanceof Array && hex.length == 1)
|
|
218
|
+
return (0, CompressionUtil_1.hexToBytes)(hex[0]);
|
|
219
|
+
throw new Error("Cannot send more than 1 hex string; this packet is equivalent to UBYTES: " + JSON.stringify(hex));
|
|
220
|
+
}
|
|
221
|
+
return (0, CompressionUtil_1.hexToBytes)(hex);
|
|
222
|
+
};
|
|
223
|
+
case PacketType_1.PacketType.SHORTS: return (numbers) => numbers.map(CompressionUtil_1.mapShort_ZZ).flat();
|
|
224
|
+
case PacketType_1.PacketType.USHORTS: return (numbers) => numbers.map(CompressionUtil_1.toShort).flat();
|
|
225
|
+
case PacketType_1.PacketType.VARINT: return (numbers) => numbers.map(n => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n))).flat();
|
|
226
|
+
case PacketType_1.PacketType.UVARINT: return (numbers) => numbers.map(CompressionUtil_1.convertVarInt).flat();
|
|
227
|
+
case PacketType_1.PacketType.DELTAS: return (numbers) => numbers.map((n, i) => (0, CompressionUtil_1.convertVarInt)((0, CompressionUtil_1.mapZigZag)(n - (numbers[i - 1] || 0)))).flat();
|
|
228
|
+
case PacketType_1.PacketType.FLOATS: return (singles) => singles.map(CompressionUtil_1.convertFloat).flat();
|
|
229
|
+
case PacketType_1.PacketType.DOUBLES: return (doubles) => doubles.map(CompressionUtil_1.convertDouble).flat();
|
|
230
|
+
case PacketType_1.PacketType.BOOLEANS: return (bools) => (0, ArrayUtil_1.splitArray)(bools, 8).map((bools) => (0, CompressionUtil_1.compressBools)(bools)).flat();
|
|
231
|
+
case PacketType_1.PacketType.STRINGS_ASCII: return (strings) => {
|
|
232
|
+
return [
|
|
233
|
+
...(0, CompressionUtil_1.convertVarInt)(strings.length),
|
|
234
|
+
...strings.map(str => (0, CompressionUtil_1.convertVarInt)(str.length)).flat(),
|
|
235
|
+
...(0, CompressionUtil_1.encodeHuffman)(strings.reduce((a, b) => a + String(b), "")),
|
|
236
|
+
];
|
|
237
|
+
};
|
|
238
|
+
case PacketType_1.PacketType.STRINGS_UTF16: return (strings) => {
|
|
239
|
+
const res = [];
|
|
240
|
+
for (const v of strings) {
|
|
241
|
+
const string = String(v);
|
|
242
|
+
const charCodes = (0, StringUtil_1.processCharCodes)(string);
|
|
243
|
+
// hate js man
|
|
244
|
+
const length = charCodes.length;
|
|
245
|
+
res.push(...(0, CompressionUtil_1.convertVarInt)(length));
|
|
246
|
+
res.push(...charCodes.map(CompressionUtil_1.convertVarInt).flat());
|
|
247
|
+
}
|
|
248
|
+
return res;
|
|
249
|
+
};
|
|
250
|
+
case PacketType_1.PacketType.JSON: return (value) => Array.from((0, CompressionUtil_1.compressJSON)(value));
|
|
251
|
+
default: throw new Error("Unknown type: " + type);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const fn = genFunc();
|
|
255
|
+
if (!gzipCompression) {
|
|
256
|
+
return async (_, data) => {
|
|
257
|
+
return new Uint8Array(fn(data));
|
|
213
258
|
};
|
|
214
|
-
default: throw new Error("Unknown type: " + type);
|
|
215
259
|
}
|
|
260
|
+
return async (ident, data) => {
|
|
261
|
+
return (0, CompressionUtil_1.compressGzip)(new Uint8Array(fn(data)), ident);
|
|
262
|
+
};
|
|
216
263
|
}
|
|
217
264
|
function createObjSendProcessor(packet) {
|
|
218
265
|
const size = packet.type.length;
|
|
219
|
-
|
|
220
|
-
|
|
266
|
+
// TODO: Add compression and add rereferences[]
|
|
267
|
+
const processors = packet.type.map(t => createSendProcessor(t, false));
|
|
268
|
+
return async (ident, data) => {
|
|
221
269
|
let result = [];
|
|
222
270
|
for (let i = 0; i < size; i++) {
|
|
223
271
|
const sectorData = data[i];
|
|
224
|
-
const d = processors[i](Array.isArray(sectorData) ? sectorData : [sectorData]);
|
|
272
|
+
const d = await processors[i](ident, Array.isArray(sectorData) ? sectorData : [sectorData]);
|
|
225
273
|
if (d.length > CompressionUtil_1.MAX_UVARINT)
|
|
226
274
|
throw new Error(`Cannot send ${d.length}/${CompressionUtil_1.MAX_UVARINT} bytes of data!`);
|
|
227
275
|
result.push(...(0, CompressionUtil_1.convertVarInt)(d.length));
|
|
228
276
|
d.forEach(val => result.push(val));
|
|
229
277
|
}
|
|
230
|
-
return result;
|
|
278
|
+
return new Uint8Array(result);
|
|
231
279
|
};
|
|
232
280
|
}
|
|
233
281
|
function createObjReceiveProcessor(packet) {
|
|
@@ -247,22 +295,22 @@ function createObjReceiveProcessor(packet) {
|
|
|
247
295
|
};
|
|
248
296
|
}
|
|
249
297
|
function createObjValidator(packet) {
|
|
250
|
-
const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet));
|
|
251
|
-
return (data) => {
|
|
298
|
+
const validators = packet.type.map((t, i) => createValidator(t, packet.dataMax[i], packet.dataMin[i], packet, false));
|
|
299
|
+
return async (data) => {
|
|
252
300
|
let index = 0, enums = 0, computedData = [];
|
|
253
301
|
while (index < data.length) {
|
|
254
302
|
if (computedData.length > packet.type.length)
|
|
255
|
-
return false; // only types amount of values
|
|
303
|
+
return [data, false]; // only types amount of values
|
|
256
304
|
const [off, sectorLength] = (0, CompressionUtil_1.readVarInt)(data, index);
|
|
257
305
|
index = off;
|
|
258
306
|
if (sectorLength + index > data.length)
|
|
259
|
-
return false;
|
|
307
|
+
return [data, false];
|
|
260
308
|
const sector = data.subarray(index, index += sectorLength);
|
|
261
|
-
const result = validators[computedData.length](sector, packet.type[computedData.length] == PacketType_1.PacketType.ENUMS ? enums++ : 0);
|
|
309
|
+
const [, result] = await validators[computedData.length](sector, packet.type[computedData.length] == PacketType_1.PacketType.ENUMS ? enums++ : 0);
|
|
262
310
|
if (result === false)
|
|
263
|
-
return false; // chat i used === to fix a bug !!!!
|
|
311
|
+
return [data, false]; // chat i used === to fix a bug !!!!
|
|
264
312
|
computedData.push(result);
|
|
265
313
|
}
|
|
266
|
-
return computedData;
|
|
314
|
+
return [data, computedData];
|
|
267
315
|
};
|
|
268
316
|
}
|
|
@@ -31,5 +31,11 @@ export declare enum PacketType {
|
|
|
31
31
|
/** One or more double precision floating point numbers. */
|
|
32
32
|
DOUBLES = 13,
|
|
33
33
|
/** One or more true/false */
|
|
34
|
-
BOOLEANS = 14
|
|
34
|
+
BOOLEANS = 14,
|
|
35
|
+
/** Consumes multiple keys to describe the value. E.g. if you want to send a boolean, this could take up 2 keys instead of sending 2 bytes. Currently W.I.P. */
|
|
36
|
+
KEY_EFFECTIVE = 15,
|
|
37
|
+
/** A more optimized version of JSON for when it's a necessity. However, please try to avoid this; the other types are usually better. */
|
|
38
|
+
JSON = 16,
|
|
39
|
+
/** Hex bytes, e.g. 0xFFFFFF - the result will always be returned in lowercase. This can only hold 1 hex string, since it's the same as UBYTES but auto-parses. */
|
|
40
|
+
HEX = 17
|
|
35
41
|
}
|
|
@@ -52,4 +52,10 @@ var PacketType;
|
|
|
52
52
|
PacketType[PacketType["DOUBLES"] = 13] = "DOUBLES";
|
|
53
53
|
/** One or more true/false */
|
|
54
54
|
PacketType[PacketType["BOOLEANS"] = 14] = "BOOLEANS";
|
|
55
|
+
/** Consumes multiple keys to describe the value. E.g. if you want to send a boolean, this could take up 2 keys instead of sending 2 bytes. Currently W.I.P. */
|
|
56
|
+
PacketType[PacketType["KEY_EFFECTIVE"] = 15] = "KEY_EFFECTIVE";
|
|
57
|
+
/** A more optimized version of JSON for when it's a necessity. However, please try to avoid this; the other types are usually better. */
|
|
58
|
+
PacketType[PacketType["JSON"] = 16] = "JSON";
|
|
59
|
+
/** Hex bytes, e.g. 0xFFFFFF - the result will always be returned in lowercase. This can only hold 1 hex string, since it's the same as UBYTES but auto-parses. */
|
|
60
|
+
PacketType[PacketType["HEX"] = 17] = "HEX";
|
|
55
61
|
})(PacketType || (exports.PacketType = PacketType = {}));
|