sonic-ws 1.3.3 → 2.0.0-fix
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/LICENSE +56 -196
- package/README.md +88 -17
- package/bundled/bundle.js +6 -0
- package/bundled/bundle.wasm +0 -0
- package/dist/{index.d.ts → ts/index.d.ts} +11 -0
- package/dist/{index.js → ts/index.js} +10 -11
- package/dist/ts/native/wrapper.d.ts +64 -0
- package/dist/ts/native/wrapper.js +7 -0
- package/dist/ts/version.d.ts +16 -0
- package/dist/ts/version.js +7 -0
- package/dist/{ws → ts/ws}/Connection.d.ts +10 -0
- package/dist/ts/ws/Connection.js +7 -0
- package/dist/{ws → ts/ws}/PacketProcessor.d.ts +10 -0
- package/dist/ts/ws/PacketProcessor.js +7 -0
- package/dist/{ws → ts/ws}/client/core/ClientCore.d.ts +10 -0
- package/dist/ts/ws/client/core/ClientCore.js +7 -0
- package/dist/{ws → ts/ws}/client/node/ClientNode.d.ts +10 -0
- package/dist/ts/ws/client/node/ClientNode.js +7 -0
- package/dist/ts/ws/debug/DebugServer.d.ts +17 -0
- package/dist/ts/ws/debug/DebugServer.js +7 -0
- package/dist/{ws → ts/ws}/packets/PacketType.d.ts +11 -1
- package/dist/ts/ws/packets/PacketType.js +7 -0
- package/dist/{ws → ts/ws}/packets/Packets.d.ts +10 -3
- package/dist/ts/ws/packets/Packets.js +7 -0
- package/dist/{ws → ts/ws}/server/SonicWSConnection.d.ts +10 -0
- package/dist/ts/ws/server/SonicWSConnection.js +7 -0
- package/dist/{ws → ts/ws}/server/SonicWSServer.d.ts +13 -0
- package/dist/ts/ws/server/SonicWSServer.js +7 -0
- package/dist/{ws → ts/ws}/util/BufferUtil.d.ts +10 -0
- package/dist/ts/ws/util/BufferUtil.js +7 -0
- package/dist/ts/ws/util/StringUtil.d.ts +13 -0
- package/dist/ts/ws/util/StringUtil.js +7 -0
- package/dist/{ws → ts/ws}/util/enums/EnumHandler.d.ts +10 -0
- package/dist/ts/ws/util/enums/EnumHandler.js +7 -0
- package/dist/ts/ws/util/enums/EnumType.d.ts +12 -0
- package/dist/ts/ws/util/enums/EnumType.js +7 -0
- package/dist/ts/ws/util/packets/BatchHelper.d.ts +11 -0
- package/dist/ts/ws/util/packets/BatchHelper.js +7 -0
- package/dist/ts/ws/util/packets/CompressionUtil.d.ts +18 -0
- package/dist/ts/ws/util/packets/CompressionUtil.js +7 -0
- package/dist/ts/ws/util/packets/HashUtil.d.ts +12 -0
- package/dist/ts/ws/util/packets/HashUtil.js +7 -0
- package/dist/ts/ws/util/packets/JSONUtil.d.ts +12 -0
- package/dist/ts/ws/util/packets/JSONUtil.js +7 -0
- package/dist/ts/ws/util/packets/PacketHolder.d.ts +11 -0
- package/dist/ts/ws/util/packets/PacketHolder.js +7 -0
- package/dist/{ws → ts/ws}/util/packets/PacketUtils.d.ts +10 -0
- package/dist/ts/ws/util/packets/PacketUtils.js +7 -0
- package/dist/ts/ws/util/packets/RateHandler.d.ts +11 -0
- package/dist/ts/ws/util/packets/RateHandler.js +7 -0
- package/package.json +14 -10
- package/dist/version.d.ts +0 -6
- package/dist/version.js +0 -25
- package/dist/ws/Connection.js +0 -126
- package/dist/ws/PacketProcessor.js +0 -52
- package/dist/ws/client/core/ClientCore.js +0 -251
- package/dist/ws/client/node/ClientNode.js +0 -36
- package/dist/ws/debug/DebugServer.d.ts +0 -7
- package/dist/ws/debug/DebugServer.js +0 -607
- package/dist/ws/packets/PacketProcessors.d.ts +0 -13
- package/dist/ws/packets/PacketProcessors.js +0 -317
- package/dist/ws/packets/PacketType.js +0 -61
- package/dist/ws/packets/Packets.js +0 -277
- package/dist/ws/server/SonicWSConnection.js +0 -298
- package/dist/ws/server/SonicWSServer.js +0 -307
- package/dist/ws/util/BufferUtil.js +0 -42
- package/dist/ws/util/StringUtil.d.ts +0 -5
- package/dist/ws/util/StringUtil.js +0 -51
- package/dist/ws/util/enums/EnumHandler.js +0 -60
- package/dist/ws/util/enums/EnumType.d.ts +0 -2
- package/dist/ws/util/enums/EnumType.js +0 -72
- package/dist/ws/util/packets/BatchHelper.d.ts +0 -1
- package/dist/ws/util/packets/BatchHelper.js +0 -85
- package/dist/ws/util/packets/CompressionUtil.d.ts +0 -35
- package/dist/ws/util/packets/CompressionUtil.js +0 -277
- package/dist/ws/util/packets/HashUtil.d.ts +0 -2
- package/dist/ws/util/packets/HashUtil.js +0 -122
- package/dist/ws/util/packets/JSONUtil.d.ts +0 -2
- package/dist/ws/util/packets/JSONUtil.js +0 -179
- package/dist/ws/util/packets/PacketHolder.d.ts +0 -1
- package/dist/ws/util/packets/PacketHolder.js +0 -126
- package/dist/ws/util/packets/PacketUtils.js +0 -283
- package/dist/ws/util/packets/RateHandler.d.ts +0 -1
- package/dist/ws/util/packets/RateHandler.js +0 -66
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright 2026 Lily (liwybloc)
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.SonicWSConnection = void 0;
|
|
19
|
-
const PacketUtils_1 = require("../util/packets/PacketUtils");
|
|
20
|
-
const BatchHelper_1 = require("../util/packets/BatchHelper");
|
|
21
|
-
const RateHandler_1 = require("../util/packets/RateHandler");
|
|
22
|
-
const BufferUtil_1 = require("../util/BufferUtil");
|
|
23
|
-
const Connection_1 = require("../Connection");
|
|
24
|
-
const CLIENT_RATELIMIT_TAG = "C", SERVER_RATELIMIT_TAG = "S";
|
|
25
|
-
class SonicWSConnection extends Connection_1.Connection {
|
|
26
|
-
host;
|
|
27
|
-
print = false;
|
|
28
|
-
handshakePacket;
|
|
29
|
-
handshakeLambda;
|
|
30
|
-
messageLambda = (data) => this.messageHandler(this.parseData(data));
|
|
31
|
-
handshakedMessageLambda = (data) => {
|
|
32
|
-
const parsed = this.parseData(data);
|
|
33
|
-
if (parsed == null)
|
|
34
|
-
return this.socket.close(Connection_1.CloseCodes.INVALID_DATA);
|
|
35
|
-
if (parsed[0] == this.handshakePacket)
|
|
36
|
-
return this.socket.close(Connection_1.CloseCodes.REPEATED_HANDSHAKE);
|
|
37
|
-
this.messageHandler(parsed);
|
|
38
|
-
};
|
|
39
|
-
rater;
|
|
40
|
-
enabledPackets = {};
|
|
41
|
-
/** If the packet handshake has been completed; `wss.requireHandshake(packet)` */
|
|
42
|
-
handshakeComplete = false;
|
|
43
|
-
asyncMap = {};
|
|
44
|
-
asyncData = {};
|
|
45
|
-
constructor(socket, host, id, handshakePacket, clientRateLimit, serverRateLimit) {
|
|
46
|
-
super(socket, id, "Socket " + id, socket.addEventListener.bind(socket), socket.removeEventListener.bind(socket));
|
|
47
|
-
this.host = host;
|
|
48
|
-
this.handshakePacket = handshakePacket;
|
|
49
|
-
for (const pack of host.clientPackets.getPackets()) {
|
|
50
|
-
const tag = pack.tag;
|
|
51
|
-
this.listeners[tag] = [];
|
|
52
|
-
pack.lastReceived[this.id] = undefined;
|
|
53
|
-
this.enabledPackets[tag] = pack.defaultEnabled;
|
|
54
|
-
this.asyncMap[tag] = pack.async;
|
|
55
|
-
if (pack.async)
|
|
56
|
-
this.asyncData[tag] = [false, []];
|
|
57
|
-
}
|
|
58
|
-
this.setInterval = this.setInterval.bind(this);
|
|
59
|
-
this.batcher.registerSendPackets(this.host.serverPackets, this);
|
|
60
|
-
this.invalidPacket = this.invalidPacket.bind(this);
|
|
61
|
-
this.rater = new RateHandler_1.RateHandler(this);
|
|
62
|
-
this.rater.registerRate(CLIENT_RATELIMIT_TAG, clientRateLimit);
|
|
63
|
-
this.rater.registerRate(SERVER_RATELIMIT_TAG, serverRateLimit);
|
|
64
|
-
this.rater.registerAll(host.clientPackets, "client");
|
|
65
|
-
this.rater.registerAll(host.serverPackets, "server");
|
|
66
|
-
this.rater.start();
|
|
67
|
-
if (this.handshakePacket == null) {
|
|
68
|
-
this.socket.addEventListener('message', this.messageLambda);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
this.handshakeLambda = (data) => this.handshakeHandler(data);
|
|
72
|
-
this.socket.addEventListener('message', this.handshakeLambda);
|
|
73
|
-
}
|
|
74
|
-
this.socket.on('close', () => {
|
|
75
|
-
for (const packet of host.clientPackets.getPackets()) {
|
|
76
|
-
delete packet.lastReceived[this.id];
|
|
77
|
-
}
|
|
78
|
-
for (const packet of host.serverPackets.getPackets()) {
|
|
79
|
-
delete packet.lastSent[this.id];
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
parseData(event) {
|
|
84
|
-
if (this.rater.trigger(CLIENT_RATELIMIT_TAG))
|
|
85
|
-
return null;
|
|
86
|
-
if (!(event.data instanceof Buffer))
|
|
87
|
-
return null;
|
|
88
|
-
const message = new Uint8Array(event.data);
|
|
89
|
-
if (this.print)
|
|
90
|
-
console.log(`\x1b[31m⬇ \x1b[38;5;245m(${this.id},${message.byteLength})\x1b[0m`, (message.length > 0 && this.host.clientPackets.getTag(message[0])) || "<INVALID>", (0, BufferUtil_1.stringifyBuffer)(message));
|
|
91
|
-
if (message.byteLength < 1) {
|
|
92
|
-
this.socket.close(Connection_1.CloseCodes.SMALL);
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
const key = message[0];
|
|
96
|
-
const value = message.slice(1);
|
|
97
|
-
// not a key, bye bye
|
|
98
|
-
if (!this.host.clientPackets.hasKey(key)) {
|
|
99
|
-
this.socket.close(Connection_1.CloseCodes.INVALID_KEY);
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
const tag = this.host.clientPackets.getTag(key);
|
|
103
|
-
// disabled, bye bye
|
|
104
|
-
if (!this.enabledPackets[tag]) {
|
|
105
|
-
this.socket.close(Connection_1.CloseCodes.DISABLED_PACKET);
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
if (this.rater.trigger("client" + key))
|
|
109
|
-
return null;
|
|
110
|
-
return [tag, value];
|
|
111
|
-
}
|
|
112
|
-
handshakeHandler(data) {
|
|
113
|
-
const parsed = this.parseData(data);
|
|
114
|
-
if (parsed == null)
|
|
115
|
-
return this.socket.close(Connection_1.CloseCodes.INVALID_DATA);
|
|
116
|
-
if (parsed[0] != this.handshakePacket) {
|
|
117
|
-
this.socket.close(Connection_1.CloseCodes.INVALID_DATA);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
this.messageHandler(parsed);
|
|
121
|
-
this.socket.removeEventListener('message', this.handshakeLambda);
|
|
122
|
-
this.socket.addEventListener('message', this.handshakedMessageLambda);
|
|
123
|
-
this.handshakeComplete = true;
|
|
124
|
-
}
|
|
125
|
-
invalidPacket(listened) {
|
|
126
|
-
console.log("Closure cause", listened);
|
|
127
|
-
this.socket.close(Connection_1.CloseCodes.INVALID_PACKET, listened);
|
|
128
|
-
}
|
|
129
|
-
isAsync(tag) {
|
|
130
|
-
return this.asyncMap[tag];
|
|
131
|
-
}
|
|
132
|
-
listenLock = false;
|
|
133
|
-
packetQueue = [];
|
|
134
|
-
async listenPacket(data, tag, packetQueue, isAsync, asyncData) {
|
|
135
|
-
if (this.closed)
|
|
136
|
-
return;
|
|
137
|
-
await (0, PacketUtils_1.listenPacket)(data, this.listeners[tag], this.invalidPacket);
|
|
138
|
-
await this.callMiddleware('onReceive_post', tag, typeof data == 'string' ? [data] : data[0]);
|
|
139
|
-
if (isAsync)
|
|
140
|
-
asyncData[0] = false;
|
|
141
|
-
else
|
|
142
|
-
this.listenLock = false;
|
|
143
|
-
if (packetQueue.length != 0) {
|
|
144
|
-
this.messageHandler(packetQueue.shift());
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
async messageHandler(data, recall = false) {
|
|
149
|
-
if (data == null)
|
|
150
|
-
return;
|
|
151
|
-
const [tag, value] = data;
|
|
152
|
-
const isAsync = this.isAsync(tag);
|
|
153
|
-
let locked, packetQueue, asyncData;
|
|
154
|
-
if (isAsync) {
|
|
155
|
-
asyncData = this.asyncData[tag];
|
|
156
|
-
locked = asyncData[0];
|
|
157
|
-
packetQueue = asyncData[1];
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
locked = this.listenLock;
|
|
161
|
-
packetQueue = this.packetQueue;
|
|
162
|
-
}
|
|
163
|
-
if (locked) {
|
|
164
|
-
packetQueue.push(data);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
if (isAsync)
|
|
168
|
-
asyncData[0] = true;
|
|
169
|
-
else
|
|
170
|
-
this.listenLock = true;
|
|
171
|
-
const packet = this.host.clientPackets.getPacket(tag);
|
|
172
|
-
if (!recall && await this.callMiddleware('onReceive_pre', packet.tag, value, value.length))
|
|
173
|
-
return;
|
|
174
|
-
if (packet.rereference && value.length == 0) {
|
|
175
|
-
const lastRecv = packet.lastReceived[this.id];
|
|
176
|
-
if (lastRecv === undefined)
|
|
177
|
-
return this.invalidPacket("No previous value to rereference");
|
|
178
|
-
await this.listenPacket(lastRecv, tag, packetQueue, isAsync, asyncData);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (packet.dataBatching == 0) {
|
|
182
|
-
const res = await packet.listen(value, this);
|
|
183
|
-
packet.lastReceived[this.id] = res;
|
|
184
|
-
await this.listenPacket(res, tag, packetQueue, isAsync, asyncData);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const batchData = await BatchHelper_1.BatchHelper.unravelBatch(packet, value, this);
|
|
188
|
-
if (typeof batchData == 'string')
|
|
189
|
-
return this.invalidPacket(batchData);
|
|
190
|
-
for (const data of batchData) {
|
|
191
|
-
if (isAsync)
|
|
192
|
-
asyncData[0] = true;
|
|
193
|
-
else
|
|
194
|
-
this.listenLock = true;
|
|
195
|
-
await this.listenPacket(data, tag, packetQueue, isAsync, asyncData);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Enables a packet for the client.
|
|
200
|
-
* @param tag The tag of the packet
|
|
201
|
-
*/
|
|
202
|
-
enablePacket(tag) {
|
|
203
|
-
this.enabledPackets[tag] = true;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Disables a packet for the client.
|
|
207
|
-
* @param tag The tag of the packet
|
|
208
|
-
*/
|
|
209
|
-
disablePacket(tag) {
|
|
210
|
-
this.enabledPackets[tag] = false;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Listens for when the connection closes
|
|
214
|
-
* @param listener Called when it closes
|
|
215
|
-
*/
|
|
216
|
-
on_close(listener) {
|
|
217
|
-
this.socket.on('close', (code, reason) => listener(code, String(reason)));
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Listens for a packet
|
|
221
|
-
* @param tag The tag of the key to listen for
|
|
222
|
-
* @param listener A function to listen for it
|
|
223
|
-
*/
|
|
224
|
-
on(tag, listener) {
|
|
225
|
-
if (!this.host.clientPackets.hasTag(tag))
|
|
226
|
-
throw new Error(`Tag "${String(tag)}" has not been created!`);
|
|
227
|
-
this.listeners[tag] ??= [];
|
|
228
|
-
this.listeners[tag].push(listener);
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* For internal use.
|
|
232
|
-
*/
|
|
233
|
-
send_processed(code, data, packet) {
|
|
234
|
-
if (this.rater.trigger("server" + code))
|
|
235
|
-
return;
|
|
236
|
-
if (packet.dataBatching == 0)
|
|
237
|
-
this.raw_send((0, BufferUtil_1.toPacketBuffer)(code, data));
|
|
238
|
-
else
|
|
239
|
-
this.batcher.batchPacket(code, data);
|
|
240
|
-
}
|
|
241
|
-
sendQueue = [false, [], undefined];
|
|
242
|
-
/**
|
|
243
|
-
* Sends a packet with the tag and values
|
|
244
|
-
* @param tag The tag to send
|
|
245
|
-
* @param values The values to send
|
|
246
|
-
*/
|
|
247
|
-
async send(tag, ...values) {
|
|
248
|
-
if (await this.callMiddleware('onSend_pre', tag, values, Date.now(), performance.now()))
|
|
249
|
-
return;
|
|
250
|
-
const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.host.serverPackets, tag, values, this.sendQueue, this.id);
|
|
251
|
-
if (await this.callMiddleware('onSend_post', tag, data, data.length))
|
|
252
|
-
return;
|
|
253
|
-
this.send_processed(code, data, packet);
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Broadcasts a packet to all other users connected
|
|
257
|
-
* @param tag The tag to send
|
|
258
|
-
* @param values The values to send
|
|
259
|
-
*/
|
|
260
|
-
broadcastFiltered(tag, filter, ...values) {
|
|
261
|
-
this.host.broadcastFiltered(tag, (socket) => socket != this && filter(socket), ...values);
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Broadcasts a packet to all other users connected
|
|
265
|
-
* @param tag The tag to send
|
|
266
|
-
* @param values The values to send
|
|
267
|
-
*/
|
|
268
|
-
broadcast(tag, ...values) {
|
|
269
|
-
this.broadcastFiltered(tag, () => true, ...values);
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Toggles printing all sent and received messages
|
|
273
|
-
*/
|
|
274
|
-
togglePrint() {
|
|
275
|
-
this.print = !this.print;
|
|
276
|
-
}
|
|
277
|
-
/* JSDocs in Connection.ts class */
|
|
278
|
-
raw_send(data) {
|
|
279
|
-
if (this.isClosed()) {
|
|
280
|
-
console.warn("WARN! Connection already closed when trying to send message!", this.id, (0, BufferUtil_1.stringifyBuffer)(data));
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
if (this.rater.trigger(SERVER_RATELIMIT_TAG))
|
|
284
|
-
return;
|
|
285
|
-
if (this.print)
|
|
286
|
-
console.log(`\x1b[32m⬆ \x1b[38;5;245m(${this.id},${data.byteLength})\x1b[0m`, (data.length > 0 && this.host.serverPackets.getTag(data[0])) || "<INVALID>", (0, BufferUtil_1.stringifyBuffer)(data));
|
|
287
|
-
super.raw_send(data);
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Tags the socket with a key
|
|
291
|
-
* @param tag The tag to add
|
|
292
|
-
* @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
|
|
293
|
-
*/
|
|
294
|
-
tag(tag, replace = true) {
|
|
295
|
-
this.host.tag(this, tag, replace);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
exports.SonicWSConnection = SonicWSConnection;
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright 2026 Lily (liwybloc)
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
-
if (k2 === undefined) k2 = k;
|
|
19
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
-
}
|
|
23
|
-
Object.defineProperty(o, k2, desc);
|
|
24
|
-
}) : (function(o, m, k, k2) {
|
|
25
|
-
if (k2 === undefined) k2 = k;
|
|
26
|
-
o[k2] = m[k];
|
|
27
|
-
}));
|
|
28
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
-
}) : function(o, v) {
|
|
31
|
-
o["default"] = v;
|
|
32
|
-
});
|
|
33
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
-
var ownKeys = function(o) {
|
|
35
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
-
var ar = [];
|
|
37
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
-
return ar;
|
|
39
|
-
};
|
|
40
|
-
return ownKeys(o);
|
|
41
|
-
};
|
|
42
|
-
return function (mod) {
|
|
43
|
-
if (mod && mod.__esModule) return mod;
|
|
44
|
-
var result = {};
|
|
45
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
-
__setModuleDefault(result, mod);
|
|
47
|
-
return result;
|
|
48
|
-
};
|
|
49
|
-
})();
|
|
50
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.SonicWSServer = void 0;
|
|
52
|
-
const WS = __importStar(require("ws"));
|
|
53
|
-
const SonicWSConnection_1 = require("./SonicWSConnection");
|
|
54
|
-
const PacketHolder_1 = require("../util/packets/PacketHolder");
|
|
55
|
-
const CompressionUtil_1 = require("../util/packets/CompressionUtil");
|
|
56
|
-
const version_1 = require("../../version");
|
|
57
|
-
const PacketUtils_1 = require("../util/packets/PacketUtils");
|
|
58
|
-
const PacketProcessor_1 = require("../PacketProcessor");
|
|
59
|
-
const HashUtil_1 = require("../util/packets/HashUtil");
|
|
60
|
-
const Connection_1 = require("../Connection");
|
|
61
|
-
const DebugServer_1 = require("../debug/DebugServer");
|
|
62
|
-
class SonicWSServer extends PacketProcessor_1.MiddlewareHolder {
|
|
63
|
-
wss;
|
|
64
|
-
availableIds = [];
|
|
65
|
-
lastId = 0;
|
|
66
|
-
connectListeners = [];
|
|
67
|
-
clientPackets;
|
|
68
|
-
serverPackets;
|
|
69
|
-
connections = [];
|
|
70
|
-
connectionMap = {};
|
|
71
|
-
clientRateLimit = 500;
|
|
72
|
-
serverRateLimit = 500;
|
|
73
|
-
handshakePacket = null;
|
|
74
|
-
tags = new Map();
|
|
75
|
-
tagsInv = new Map();
|
|
76
|
-
serverwideSendQueue = [false, [], undefined];
|
|
77
|
-
/**
|
|
78
|
-
* Initializes and hosts a websocket with sonic protocol
|
|
79
|
-
* Rate limits can be set with wss.setClientRateLimit(x) and wss.setServerRateLimit(x); it is defaulted at 500/second per both
|
|
80
|
-
* @param settings Sonic Server Options such as schema data for client and server packets, alongside websocket options
|
|
81
|
-
*/
|
|
82
|
-
constructor(settings) {
|
|
83
|
-
super();
|
|
84
|
-
const { clientPackets = [], serverPackets = [], websocketOptions = {} } = settings;
|
|
85
|
-
this.wss = new WS.WebSocketServer(websocketOptions);
|
|
86
|
-
this.clientPackets = new PacketHolder_1.PacketHolder(clientPackets);
|
|
87
|
-
this.serverPackets = new PacketHolder_1.PacketHolder(serverPackets);
|
|
88
|
-
const s_clientPackets = this.clientPackets.serialize();
|
|
89
|
-
const s_serverPackets = this.serverPackets.serialize();
|
|
90
|
-
const serverData = [...version_1.SERVER_SUFFIX_NUMS, version_1.VERSION];
|
|
91
|
-
const keyData = [...(0, CompressionUtil_1.convertVarInt)(s_clientPackets.length), ...s_clientPackets, ...s_serverPackets];
|
|
92
|
-
(0, HashUtil_1.setHashFunc)(settings.sonicServerSettings?.bit64Hash ?? true);
|
|
93
|
-
this.wss.on('connection', async (socket) => {
|
|
94
|
-
const sonicConnection = new SonicWSConnection_1.SonicWSConnection(socket, this, this.generateSocketID(), this.handshakePacket, this.clientRateLimit, this.serverRateLimit);
|
|
95
|
-
if (await this.callMiddleware("onClientConnect", sonicConnection)) {
|
|
96
|
-
sonicConnection.close(Connection_1.CloseCodes.MIDDLEWARE, "Connection blocked by middleware.");
|
|
97
|
-
this.callMiddleware("onClientDisconnect", sonicConnection, Connection_1.CloseCodes.MIDDLEWARE, Buffer.from("Connection blocked by middleware."));
|
|
98
|
-
this.availableIds.push(sonicConnection.id);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
// send tags to the client so it doesn't have to hard code them in
|
|
102
|
-
const data = new Uint8Array([...(0, CompressionUtil_1.convertVarInt)(sonicConnection.id), ...keyData]);
|
|
103
|
-
socket.send([...serverData, ...await (0, CompressionUtil_1.compressGzip)(data)]);
|
|
104
|
-
this.connections.push(sonicConnection);
|
|
105
|
-
this.connectionMap[sonicConnection.id] = sonicConnection;
|
|
106
|
-
this.connectListeners.forEach(l => l(sonicConnection));
|
|
107
|
-
socket.on('close', (code, reason) => {
|
|
108
|
-
this.connections.splice(this.connections.indexOf(sonicConnection), 1);
|
|
109
|
-
delete this.connectionMap[sonicConnection.id];
|
|
110
|
-
this.availableIds.push(sonicConnection.id);
|
|
111
|
-
if (this.tags.has(sonicConnection)) {
|
|
112
|
-
for (const tag of this.tags.get(sonicConnection))
|
|
113
|
-
this.tagsInv.get(tag)?.delete(sonicConnection);
|
|
114
|
-
this.tags.delete(sonicConnection);
|
|
115
|
-
}
|
|
116
|
-
this.callMiddleware("onClientDisconnect", sonicConnection, code, reason);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
if (settings.sonicServerSettings?.checkForUpdates ?? true) {
|
|
120
|
-
fetch('https://raw.githubusercontent.com/liwybloc/sonic-ws/refs/heads/main/release/version')
|
|
121
|
-
.then((res) => res.text())
|
|
122
|
-
.then((ver) => {
|
|
123
|
-
if (parseInt(ver) > version_1.VERSION) {
|
|
124
|
-
console.warn(`SonicWS is currently running outdated! (current: ${version_1.VERSION}, latest: ${ver}) Update with "npm update sonic-ws"`);
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
.catch((err) => {
|
|
128
|
-
console.error(err);
|
|
129
|
-
console.warn(`Could not check SonicWS version.`);
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
generateSocketID() {
|
|
134
|
-
if (this.availableIds.length == 0)
|
|
135
|
-
this.availableIds.push(this.lastId + 1);
|
|
136
|
-
this.lastId = this.availableIds.shift();
|
|
137
|
-
return this.lastId;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Requires each client to send this packet upon initialization
|
|
141
|
-
*
|
|
142
|
-
* Recreates this:
|
|
143
|
-
* ```js
|
|
144
|
-
* let initiated = false;
|
|
145
|
-
* socket.on('init', () => {
|
|
146
|
-
* if(initiated) return socket.close();
|
|
147
|
-
* initiated = true;
|
|
148
|
-
* // process
|
|
149
|
-
* });
|
|
150
|
-
*
|
|
151
|
-
* socket.on('otherPacket', () => {
|
|
152
|
-
* if(!initiated) return socket.close();
|
|
153
|
-
* // process
|
|
154
|
-
* })
|
|
155
|
-
* ```
|
|
156
|
-
*
|
|
157
|
-
* @param packet The tag of the packet to require as a handshake
|
|
158
|
-
*/
|
|
159
|
-
requireHandshake(packet) {
|
|
160
|
-
if (!this.clientPackets.hasTag(packet))
|
|
161
|
-
throw new Error(`The client does not send "${packet}" and so it cannot use it as a handshake!`);
|
|
162
|
-
if (this.clientPackets.getPacket(packet).dataBatching != 0)
|
|
163
|
-
throw new Error(`The packet "${packet}" is a batched packet, and cannot be used as a handshake!`);
|
|
164
|
-
this.handshakePacket = packet;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Sets the rate limit for all client-side packets
|
|
168
|
-
* @param limit Amount of packets the sockets can send every second, or 0 for infinite
|
|
169
|
-
*/
|
|
170
|
-
setClientRateLimit(limit) {
|
|
171
|
-
// so that i can store limits in 1 packet
|
|
172
|
-
if (limit > CompressionUtil_1.MAX_BYTE) {
|
|
173
|
-
limit = 0;
|
|
174
|
-
console.warn(`A rate limit above ${CompressionUtil_1.MAX_BYTE} is considered infinite.`);
|
|
175
|
-
}
|
|
176
|
-
this.clientRateLimit = limit;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Sets the rate limit for server-side packets per-socket
|
|
180
|
-
* @param limit Amount of packets the server can send every second, or 0 for infinite
|
|
181
|
-
*/
|
|
182
|
-
setServerRateLimit(limit) {
|
|
183
|
-
// so that i can store limits in 1 packet
|
|
184
|
-
if (limit > CompressionUtil_1.MAX_BYTE) {
|
|
185
|
-
limit = 0;
|
|
186
|
-
console.warn(`A rate limit above ${CompressionUtil_1.MAX_BYTE} is considered infinite.`);
|
|
187
|
-
}
|
|
188
|
-
this.serverRateLimit = limit;
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Enables a packet for all current & new clients.
|
|
192
|
-
* @param tag The tag of the packet
|
|
193
|
-
*/
|
|
194
|
-
enablePacket(tag) {
|
|
195
|
-
this.clientPackets.getPacket(tag).defaultEnabled = true;
|
|
196
|
-
this.connections.forEach(socket => socket.enablePacket(tag));
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Disables a packet for all current & new clients.
|
|
200
|
-
* @param tag The tag of the packet
|
|
201
|
-
*/
|
|
202
|
-
disablePacket(tag) {
|
|
203
|
-
this.clientPackets.getPacket(tag).defaultEnabled = false;
|
|
204
|
-
this.connections.forEach(socket => socket.disablePacket(tag));
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Listens for whenever a client connects
|
|
208
|
-
* @param runner Called when ready
|
|
209
|
-
*/
|
|
210
|
-
on_connect(runner) {
|
|
211
|
-
this.connectListeners.push(runner);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Listens for whenever the server is ready
|
|
215
|
-
* @param runner Called when ready
|
|
216
|
-
*/
|
|
217
|
-
on_ready(runner) {
|
|
218
|
-
this.wss.on('listening', runner);
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Closes the server
|
|
222
|
-
* @param callback Called when server closes
|
|
223
|
-
*/
|
|
224
|
-
shutdown(callback) {
|
|
225
|
-
this.wss.close(callback);
|
|
226
|
-
}
|
|
227
|
-
async broadcastInternal(packetTag, target, values) {
|
|
228
|
-
let recipients;
|
|
229
|
-
if (target.type === "all") {
|
|
230
|
-
recipients = this.connections;
|
|
231
|
-
}
|
|
232
|
-
else if (target.type === "tagged") {
|
|
233
|
-
if (!this.tagsInv.has(target.tag))
|
|
234
|
-
return;
|
|
235
|
-
recipients = Array.from(this.tagsInv.get(target.tag));
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
recipients = this.connections.filter(target.filter);
|
|
239
|
-
}
|
|
240
|
-
if (await this.callMiddleware("onPacketBroadcast_pre", packetTag, { recipients, ...target }, values))
|
|
241
|
-
return;
|
|
242
|
-
if (recipients.length === 0)
|
|
243
|
-
return;
|
|
244
|
-
const [code, data, packet] = await (0, PacketUtils_1.processPacket)(this.serverPackets, packetTag, values, this.serverwideSendQueue, -1);
|
|
245
|
-
if (await this.callMiddleware("onPacketBroadcast_post", packetTag, { recipients, ...target }, data, data.length))
|
|
246
|
-
return;
|
|
247
|
-
recipients.forEach(conn => conn.send_processed(code, data, packet));
|
|
248
|
-
}
|
|
249
|
-
async broadcastTagged(tag, packetTag, ...values) {
|
|
250
|
-
await this.broadcastInternal(packetTag, { type: "tagged", tag }, values);
|
|
251
|
-
}
|
|
252
|
-
async broadcastFiltered(tag, filter, ...values) {
|
|
253
|
-
await this.broadcastInternal(tag, { type: "filter", filter }, values);
|
|
254
|
-
}
|
|
255
|
-
async broadcast(tag, ...values) {
|
|
256
|
-
await this.broadcastInternal(tag, { type: "all" }, values);
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* @returns All users connected to the socket
|
|
260
|
-
*/
|
|
261
|
-
getConnected() {
|
|
262
|
-
return this.connections;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* @param id The socket id
|
|
266
|
-
* @returns The socket
|
|
267
|
-
*/
|
|
268
|
-
getSocket(id) {
|
|
269
|
-
return this.connectionMap[id];
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Closes a socket by id
|
|
273
|
-
* @param id The socket id
|
|
274
|
-
*/
|
|
275
|
-
closeSocket(id, code = 1000, reason) {
|
|
276
|
-
this.getSocket(id).close(code, reason);
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Tags the socket with a key
|
|
280
|
-
* @param socket The socket to tag
|
|
281
|
-
* @param tag The tag to add
|
|
282
|
-
* @param replace If it should replace a previous tag; defaults to true. If using false, you can add multiple tags.
|
|
283
|
-
*/
|
|
284
|
-
tag(socket, tag, replace = true) {
|
|
285
|
-
if (!this.tags.get(socket))
|
|
286
|
-
this.tags.set(socket, new Set());
|
|
287
|
-
if (!this.tagsInv.get(tag))
|
|
288
|
-
this.tagsInv.set(tag, new Set());
|
|
289
|
-
if (replace) {
|
|
290
|
-
this.tags.get(socket).forEach(v => this.tagsInv.get(v)?.delete(socket));
|
|
291
|
-
}
|
|
292
|
-
this.tags.get(socket).add(tag);
|
|
293
|
-
this.tagsInv.get(tag).add(socket);
|
|
294
|
-
}
|
|
295
|
-
debugServer = null;
|
|
296
|
-
/**
|
|
297
|
-
* Opens a debug menu; this launches the browser and starts a subserver
|
|
298
|
-
* @param port Port of the server/http, defaults to 0 which finds an open port
|
|
299
|
-
* @param password Toggles the requirement of a password to access the server. Defaults to empty, which doesn't ask for a password.
|
|
300
|
-
*/
|
|
301
|
-
OpenDebug(data = {}) {
|
|
302
|
-
if (this.debugServer != null)
|
|
303
|
-
throw new Error("Attempted to open a debug server when one has already been opened.");
|
|
304
|
-
this.debugServer = new DebugServer_1.DebugServer(this, data);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
exports.SonicWSServer = SonicWSServer;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright 2026 Lily (liwybloc)
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.splitArray = splitArray;
|
|
19
|
-
exports.toPacketBuffer = toPacketBuffer;
|
|
20
|
-
exports.splitBuffer = splitBuffer;
|
|
21
|
-
exports.stringifyBuffer = stringifyBuffer;
|
|
22
|
-
function splitArray(arr, size) {
|
|
23
|
-
const result = [];
|
|
24
|
-
for (let i = 0; i < arr.length; i += size) {
|
|
25
|
-
const chunk = arr.slice(i, i + size);
|
|
26
|
-
result.push(chunk);
|
|
27
|
-
}
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
30
|
-
function toPacketBuffer(code, data) {
|
|
31
|
-
const buffer = new Uint8Array(1 + data.length);
|
|
32
|
-
buffer[0] = code;
|
|
33
|
-
buffer.set(data, 1);
|
|
34
|
-
return buffer;
|
|
35
|
-
}
|
|
36
|
-
function splitBuffer(arr, x) {
|
|
37
|
-
return splitArray(Array.from(arr), x);
|
|
38
|
-
}
|
|
39
|
-
function stringifyBuffer(data) {
|
|
40
|
-
const contents = Array.from(data).map(n => n.toString(16).padStart(2, "0")).join(" ");
|
|
41
|
-
return `<Buffer ${contents}>`;
|
|
42
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare function processCharCodes(text: string): number[];
|
|
2
|
-
export declare function convertCharCodes(codes: number[]): string;
|
|
3
|
-
export declare function encodeHuffman(text: string): Uint8Array;
|
|
4
|
-
export declare function decodeHuffman(bits: string): string;
|
|
5
|
-
export declare function as8String(data: Uint8Array): string;
|