@baltica/raknet 0.0.1
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/dist/client/client.d.ts +20 -0
- package/dist/client/client.js +122 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +18 -0
- package/dist/client/types/client-events.d.ts +6 -0
- package/dist/client/types/client-events.js +2 -0
- package/dist/client/types/client-options.d.ts +12 -0
- package/dist/client/types/client-options.js +11 -0
- package/dist/client/types/index.d.ts +2 -0
- package/dist/client/types/index.js +18 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/server/connection.d.ts +16 -0
- package/dist/server/connection.js +30 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +19 -0
- package/dist/server/server.d.ts +19 -0
- package/dist/server/server.js +119 -0
- package/dist/server/types/index.d.ts +2 -0
- package/dist/server/types/index.js +18 -0
- package/dist/server/types/server-events.d.ts +6 -0
- package/dist/server/types/server-events.js +2 -0
- package/dist/server/types/server-options.d.ts +10 -0
- package/dist/server/types/server-options.js +11 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +19 -0
- package/dist/shared/network-session.d.ts +63 -0
- package/dist/shared/network-session.js +480 -0
- package/dist/shared/proto/enums/index.d.ts +4 -0
- package/dist/shared/proto/enums/index.js +20 -0
- package/dist/shared/proto/enums/packet.d.ts +21 -0
- package/dist/shared/proto/enums/packet.js +25 -0
- package/dist/shared/proto/enums/priority.d.ts +6 -0
- package/dist/shared/proto/enums/priority.js +8 -0
- package/dist/shared/proto/enums/reliability.d.ts +10 -0
- package/dist/shared/proto/enums/reliability.js +14 -0
- package/dist/shared/proto/enums/status.d.ts +6 -0
- package/dist/shared/proto/enums/status.js +10 -0
- package/dist/shared/proto/index.d.ts +3 -0
- package/dist/shared/proto/index.js +19 -0
- package/dist/shared/proto/packets/data-packet.d.ts +7 -0
- package/dist/shared/proto/packets/data-packet.js +14 -0
- package/dist/shared/proto/packets/index.d.ts +3 -0
- package/dist/shared/proto/packets/index.js +19 -0
- package/dist/shared/proto/packets/offline/index.d.ts +6 -0
- package/dist/shared/proto/packets/offline/index.js +22 -0
- package/dist/shared/proto/packets/offline/open-connection-reply-one.d.ts +13 -0
- package/dist/shared/proto/packets/offline/open-connection-reply-one.js +46 -0
- package/dist/shared/proto/packets/offline/open-connection-reply-two.d.ts +12 -0
- package/dist/shared/proto/packets/offline/open-connection-reply-two.js +32 -0
- package/dist/shared/proto/packets/offline/open-connection-request-one.d.ts +9 -0
- package/dist/shared/proto/packets/offline/open-connection-request-one.js +26 -0
- package/dist/shared/proto/packets/offline/open-connection-request-two.d.ts +13 -0
- package/dist/shared/proto/packets/offline/open-connection-request-two.js +43 -0
- package/dist/shared/proto/packets/offline/unconnected-ping.d.ts +9 -0
- package/dist/shared/proto/packets/offline/unconnected-ping.js +25 -0
- package/dist/shared/proto/packets/offline/unconnected-pong.d.ts +10 -0
- package/dist/shared/proto/packets/offline/unconnected-pong.js +28 -0
- package/dist/shared/proto/packets/online/ack.d.ts +5 -0
- package/dist/shared/proto/packets/online/ack.js +9 -0
- package/dist/shared/proto/packets/online/acknowledgement.d.ts +6 -0
- package/dist/shared/proto/packets/online/acknowledgement.js +72 -0
- package/dist/shared/proto/packets/online/connected-ping.d.ts +8 -0
- package/dist/shared/proto/packets/online/connected-ping.js +19 -0
- package/dist/shared/proto/packets/online/connected-pong.d.ts +9 -0
- package/dist/shared/proto/packets/online/connected-pong.js +22 -0
- package/dist/shared/proto/packets/online/connection-request-accepted.d.ts +13 -0
- package/dist/shared/proto/packets/online/connection-request-accepted.js +41 -0
- package/dist/shared/proto/packets/online/connection-request.d.ts +10 -0
- package/dist/shared/proto/packets/online/connection-request.js +25 -0
- package/dist/shared/proto/packets/online/disconnect.d.ts +7 -0
- package/dist/shared/proto/packets/online/disconnect.js +16 -0
- package/dist/shared/proto/packets/online/frame-set.d.ts +10 -0
- package/dist/shared/proto/packets/online/frame-set.js +24 -0
- package/dist/shared/proto/packets/online/index.d.ts +10 -0
- package/dist/shared/proto/packets/online/index.js +26 -0
- package/dist/shared/proto/packets/online/nack.d.ts +5 -0
- package/dist/shared/proto/packets/online/nack.js +9 -0
- package/dist/shared/proto/packets/online/new-incoming-connection.d.ts +12 -0
- package/dist/shared/proto/packets/online/new-incoming-connection.js +33 -0
- package/dist/shared/proto/types/address.d.ts +11 -0
- package/dist/shared/proto/types/address.js +61 -0
- package/dist/shared/proto/types/data-type.d.ts +5 -0
- package/dist/shared/proto/types/data-type.js +9 -0
- package/dist/shared/proto/types/frame.d.ts +22 -0
- package/dist/shared/proto/types/frame.js +113 -0
- package/dist/shared/proto/types/index.d.ts +5 -0
- package/dist/shared/proto/types/index.js +21 -0
- package/dist/shared/proto/types/magic.d.ts +7 -0
- package/dist/shared/proto/types/magic.js +17 -0
- package/dist/shared/proto/types/mtu.d.ts +5 -0
- package/dist/shared/proto/types/mtu.js +12 -0
- package/dist/shared/socks5.d.ts +16 -0
- package/dist/shared/socks5.js +166 -0
- package/package.json +26 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NetworkSession = void 0;
|
|
4
|
+
const binarystream_1 = require("@serenityjs/binarystream");
|
|
5
|
+
const proto_1 = require("./proto");
|
|
6
|
+
const utils_1 = require("@baltica/utils");
|
|
7
|
+
const MTU_HEADER_SIZE = 36;
|
|
8
|
+
const RECEIVE_WINDOW = 2048;
|
|
9
|
+
const RELIABLE_WINDOW = 4096;
|
|
10
|
+
const FRAGMENT_TIMEOUT = 30_000;
|
|
11
|
+
const ORDER_QUEUE_MAX = 1024;
|
|
12
|
+
const ORDER_SKIP_THRESHOLD = 512;
|
|
13
|
+
const RAKNET_PROTOCOL = 11;
|
|
14
|
+
const GAME_PACKET_ID = 0xfe;
|
|
15
|
+
class NetworkSession extends utils_1.Emitter {
|
|
16
|
+
mtu;
|
|
17
|
+
client;
|
|
18
|
+
guid;
|
|
19
|
+
remoteGuid;
|
|
20
|
+
status = proto_1.Status.Disconnected;
|
|
21
|
+
address;
|
|
22
|
+
send;
|
|
23
|
+
serverMessage;
|
|
24
|
+
maxRetransmit = 3;
|
|
25
|
+
retransmitInterval = 1000;
|
|
26
|
+
outputReliableIndex = 0;
|
|
27
|
+
outputSplitIndex = 0;
|
|
28
|
+
outputSequence = 0;
|
|
29
|
+
outputSequenceIndex = new Array(32).fill(0);
|
|
30
|
+
outputOrderIndex = new Array(32).fill(0);
|
|
31
|
+
outputFrames = new Set();
|
|
32
|
+
outputBackup = new Map();
|
|
33
|
+
receivedFrameSequences = new Set();
|
|
34
|
+
lostFrameSequences = new Set();
|
|
35
|
+
pendingAcks = new Set();
|
|
36
|
+
lastInputSequence = -1;
|
|
37
|
+
fragmentsQueue = new Map();
|
|
38
|
+
inputHighestSequenceIndex = new Array(32).fill(0);
|
|
39
|
+
inputOrderIndex = new Array(32).fill(0);
|
|
40
|
+
inputOrderingQueue = new Map();
|
|
41
|
+
receivedReliableFrameIndices = new Set();
|
|
42
|
+
highestReliableIndex = -1;
|
|
43
|
+
offlineRetry = null;
|
|
44
|
+
outputBackupTimestamps = new Map();
|
|
45
|
+
constructor(mtu, client) {
|
|
46
|
+
super();
|
|
47
|
+
this.mtu = mtu;
|
|
48
|
+
this.client = client;
|
|
49
|
+
for (let i = 0; i < 32; i++)
|
|
50
|
+
this.inputOrderingQueue.set(i, new Map());
|
|
51
|
+
}
|
|
52
|
+
sendOfflineWithRetry(data) {
|
|
53
|
+
this.offlineRetry = { data, attempts: 1, maxAttempts: this.maxRetransmit, lastSent: Date.now(), interval: this.retransmitInterval };
|
|
54
|
+
this.send(data);
|
|
55
|
+
}
|
|
56
|
+
clearOfflineRetry() {
|
|
57
|
+
this.offlineRetry = null;
|
|
58
|
+
}
|
|
59
|
+
receive(buffer) {
|
|
60
|
+
const id = buffer[0];
|
|
61
|
+
const payload = buffer.subarray(1);
|
|
62
|
+
if (id === proto_1.Packet.Ack)
|
|
63
|
+
return this.onAck(new proto_1.Ack(payload).deserialize());
|
|
64
|
+
if (id === proto_1.Packet.Nack)
|
|
65
|
+
return this.onNack(new proto_1.Nack(payload).deserialize());
|
|
66
|
+
if (id >= proto_1.Packet.FrameSetMin && id <= proto_1.Packet.FrameSetMax)
|
|
67
|
+
return this.onFrameSet(new proto_1.FrameSet(payload).deserialize());
|
|
68
|
+
if (this.client)
|
|
69
|
+
this.handleClientOffline(id, buffer);
|
|
70
|
+
else
|
|
71
|
+
this.handleServerOffline(id, buffer);
|
|
72
|
+
}
|
|
73
|
+
handleClientOffline(id, buffer) {
|
|
74
|
+
const payload = buffer.subarray(1);
|
|
75
|
+
switch (id) {
|
|
76
|
+
case proto_1.Packet.UnconnectedPong: {
|
|
77
|
+
this.clearOfflineRetry();
|
|
78
|
+
const pong = new proto_1.UnconnectedPong(payload).deserialize();
|
|
79
|
+
this.serverMessage = pong.message;
|
|
80
|
+
this.remoteGuid = pong.guid;
|
|
81
|
+
this.emit("pong", pong.message);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case proto_1.Packet.OpenConnectionReply1: {
|
|
85
|
+
this.clearOfflineRetry();
|
|
86
|
+
const reply = new proto_1.OpenConnectionReplyOne(payload).deserialize();
|
|
87
|
+
this.remoteGuid = reply.guid;
|
|
88
|
+
this.mtu = Math.min(this.mtu, reply.mtu);
|
|
89
|
+
const req = new proto_1.OpenConnectionRequestTwo();
|
|
90
|
+
req.address = this.address;
|
|
91
|
+
req.mtu = this.mtu;
|
|
92
|
+
req.guid = this.guid;
|
|
93
|
+
req.cookie = reply.cookie;
|
|
94
|
+
req.clientSupportsecurity = false;
|
|
95
|
+
this.sendOfflineWithRetry(req.serialize());
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case proto_1.Packet.OpenConnectionReply2: {
|
|
99
|
+
this.clearOfflineRetry();
|
|
100
|
+
const reply = new proto_1.OpenConnectionReplyTwo(payload).deserialize();
|
|
101
|
+
this.mtu = Math.min(this.mtu, reply.mtu);
|
|
102
|
+
this.status = proto_1.Status.Connecting;
|
|
103
|
+
const req = new proto_1.ConnectionRequest();
|
|
104
|
+
req.guid = this.guid;
|
|
105
|
+
req.timestamp = BigInt(Date.now());
|
|
106
|
+
req.useSecurity = false;
|
|
107
|
+
this.frameAndSend(req.serialize(), proto_1.Priority.High);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case proto_1.Packet.AlreadyConnected: {
|
|
111
|
+
this.clearOfflineRetry();
|
|
112
|
+
this.status = proto_1.Status.Disconnected;
|
|
113
|
+
this.emit("disconnect");
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case proto_1.Packet.IncompatibleProtocolVersion: {
|
|
117
|
+
this.clearOfflineRetry();
|
|
118
|
+
this.status = proto_1.Status.Disconnected;
|
|
119
|
+
this.emit("error", new Error("Incompatible protocol version"));
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
handleServerOffline(id, buffer) {
|
|
125
|
+
const payload = buffer.subarray(1);
|
|
126
|
+
switch (id) {
|
|
127
|
+
case proto_1.Packet.UnconnectedPing:
|
|
128
|
+
case proto_1.Packet.UnconnectedPingOpenConnections: {
|
|
129
|
+
const ping = new proto_1.UnconnectedPing(payload).deserialize();
|
|
130
|
+
const pong = new proto_1.UnconnectedPong();
|
|
131
|
+
pong.timestamp = ping.timestamp;
|
|
132
|
+
pong.guid = this.guid;
|
|
133
|
+
pong.message = this.serverMessage ?? "";
|
|
134
|
+
this.send(pong.serialize());
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case proto_1.Packet.OpenConnectionRequest1: {
|
|
138
|
+
const req = new proto_1.OpenConnectionRequestOne(payload).deserialize();
|
|
139
|
+
const reply = new proto_1.OpenConnectionReplyOne();
|
|
140
|
+
reply.guid = this.guid;
|
|
141
|
+
reply.security = false;
|
|
142
|
+
reply.cookie = null;
|
|
143
|
+
reply.hasCookie = false;
|
|
144
|
+
reply.serverPublicKey = null;
|
|
145
|
+
reply.mtu = Math.min(this.mtu, req.mtu);
|
|
146
|
+
this.send(reply.serialize());
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case proto_1.Packet.OpenConnectionRequest2: {
|
|
150
|
+
const req = new proto_1.OpenConnectionRequestTwo(payload).deserialize();
|
|
151
|
+
this.mtu = Math.min(this.mtu, req.mtu);
|
|
152
|
+
this.remoteGuid = req.guid;
|
|
153
|
+
this.address = req.address;
|
|
154
|
+
const reply = new proto_1.OpenConnectionReplyTwo();
|
|
155
|
+
reply.guid = this.guid;
|
|
156
|
+
reply.address = req.address;
|
|
157
|
+
reply.mtu = this.mtu;
|
|
158
|
+
reply.encryptionEnabled = false;
|
|
159
|
+
this.send(reply.serialize());
|
|
160
|
+
this.status = proto_1.Status.Connecting;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
handleOnlinePacket(payload) {
|
|
166
|
+
const id = payload[0];
|
|
167
|
+
const data = payload.subarray(1);
|
|
168
|
+
switch (id) {
|
|
169
|
+
case proto_1.Packet.ConnectionRequestAccepted: {
|
|
170
|
+
if (!this.client)
|
|
171
|
+
break;
|
|
172
|
+
const accepted = new proto_1.ConnectionRequestAccepted(data).deserialize();
|
|
173
|
+
const nic = new proto_1.NewIncomingConnection();
|
|
174
|
+
nic.address = this.address;
|
|
175
|
+
nic.internalAddress = new proto_1.Address("0.0.0.0", 0, 4);
|
|
176
|
+
nic.incomingTimestamp = accepted.requestTimestamp;
|
|
177
|
+
nic.serverTimestamp = BigInt(Date.now());
|
|
178
|
+
this.frameAndSend(nic.serialize(), proto_1.Priority.High);
|
|
179
|
+
this.status = proto_1.Status.Connected;
|
|
180
|
+
this.emit("connect");
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case proto_1.Packet.ConnectionRequest: {
|
|
184
|
+
if (this.client)
|
|
185
|
+
break;
|
|
186
|
+
const req = new proto_1.ConnectionRequest(data).deserialize();
|
|
187
|
+
const accepted = new proto_1.ConnectionRequestAccepted();
|
|
188
|
+
accepted.address = this.address;
|
|
189
|
+
accepted.systemIndex = 0;
|
|
190
|
+
accepted.addresses = Array.from({ length: 20 }, () => new proto_1.Address("0.0.0.0", 0, 4));
|
|
191
|
+
accepted.requestTimestamp = req.timestamp;
|
|
192
|
+
accepted.timestamp = BigInt(Date.now());
|
|
193
|
+
this.frameAndSend(accepted.serialize(), proto_1.Priority.High);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case proto_1.Packet.NewIncomingConnection: {
|
|
197
|
+
if (this.client)
|
|
198
|
+
break;
|
|
199
|
+
this.status = proto_1.Status.Connected;
|
|
200
|
+
this.emit("connect");
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
case proto_1.Packet.ConnectedPing: {
|
|
204
|
+
const ping = new proto_1.ConnectedPing(data).deserialize();
|
|
205
|
+
const pong = new proto_1.ConnectedPong();
|
|
206
|
+
pong.pingTimestamp = ping.timestamp;
|
|
207
|
+
pong.pongTimestamp = BigInt(Date.now());
|
|
208
|
+
this.frameAndSend(pong.serialize(), proto_1.Priority.High);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case proto_1.Packet.ConnectedPong:
|
|
212
|
+
break;
|
|
213
|
+
case proto_1.Packet.DisconnectionNotification:
|
|
214
|
+
this.status = proto_1.Status.Disconnected;
|
|
215
|
+
this.emit("disconnect");
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
if (id === GAME_PACKET_ID)
|
|
219
|
+
this.emit("encapsulated", payload);
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
tick() {
|
|
224
|
+
const now = Date.now();
|
|
225
|
+
if (this.offlineRetry) {
|
|
226
|
+
const r = this.offlineRetry;
|
|
227
|
+
if (now - r.lastSent >= r.interval) {
|
|
228
|
+
if (r.attempts >= r.maxAttempts) {
|
|
229
|
+
this.offlineRetry = null;
|
|
230
|
+
this.status = proto_1.Status.Disconnected;
|
|
231
|
+
this.emit("error", new Error("Connection timed out after " + r.maxAttempts + " attempts"));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
r.attempts++;
|
|
235
|
+
r.lastSent = now;
|
|
236
|
+
this.send(r.data);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const windowStart = this.lastInputSequence - RECEIVE_WINDOW;
|
|
241
|
+
if (windowStart > 0) {
|
|
242
|
+
for (const s of this.receivedFrameSequences)
|
|
243
|
+
if (s < windowStart)
|
|
244
|
+
this.receivedFrameSequences.delete(s);
|
|
245
|
+
for (const s of this.lostFrameSequences)
|
|
246
|
+
if (s < windowStart)
|
|
247
|
+
this.lostFrameSequences.delete(s);
|
|
248
|
+
}
|
|
249
|
+
const relStart = this.highestReliableIndex - RELIABLE_WINDOW;
|
|
250
|
+
if (relStart > 0) {
|
|
251
|
+
for (const i of this.receivedReliableFrameIndices)
|
|
252
|
+
if (i < relStart)
|
|
253
|
+
this.receivedReliableFrameIndices.delete(i);
|
|
254
|
+
}
|
|
255
|
+
for (const [id, entry] of this.fragmentsQueue) {
|
|
256
|
+
if (now - entry.timestamp > FRAGMENT_TIMEOUT)
|
|
257
|
+
this.fragmentsQueue.delete(id);
|
|
258
|
+
}
|
|
259
|
+
if (this.pendingAcks.size > 0) {
|
|
260
|
+
const ack = new proto_1.Ack();
|
|
261
|
+
ack.sequences = [...this.pendingAcks];
|
|
262
|
+
this.pendingAcks.clear();
|
|
263
|
+
this.send(ack.serialize());
|
|
264
|
+
}
|
|
265
|
+
if (this.lostFrameSequences.size > 0) {
|
|
266
|
+
const nack = new proto_1.Nack();
|
|
267
|
+
nack.sequences = [...this.lostFrameSequences];
|
|
268
|
+
this.lostFrameSequences.clear();
|
|
269
|
+
this.send(nack.serialize());
|
|
270
|
+
}
|
|
271
|
+
// Retransmit unacked frame sets that are older than the retry interval
|
|
272
|
+
for (const [seq, sentAt] of this.outputBackupTimestamps) {
|
|
273
|
+
if (now - sentAt >= this.retransmitInterval) {
|
|
274
|
+
const frames = this.outputBackup.get(seq);
|
|
275
|
+
if (frames) {
|
|
276
|
+
const fs = new proto_1.FrameSet();
|
|
277
|
+
fs.sequence = seq;
|
|
278
|
+
fs.frames = frames;
|
|
279
|
+
this.send(fs.serialize());
|
|
280
|
+
this.outputBackupTimestamps.set(seq, now);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
this.outputBackupTimestamps.delete(seq);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (this.outputFrames.size > 0)
|
|
288
|
+
this.flush();
|
|
289
|
+
}
|
|
290
|
+
onAck(ack) {
|
|
291
|
+
for (const seq of ack.sequences) {
|
|
292
|
+
this.outputBackup.delete(seq);
|
|
293
|
+
this.outputBackupTimestamps.delete(seq);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
onNack(nack) {
|
|
297
|
+
for (const seq of nack.sequences) {
|
|
298
|
+
const frames = this.outputBackup.get(seq);
|
|
299
|
+
if (!frames)
|
|
300
|
+
continue;
|
|
301
|
+
const fs = new proto_1.FrameSet();
|
|
302
|
+
fs.sequence = seq;
|
|
303
|
+
fs.frames = frames;
|
|
304
|
+
this.send(fs.serialize());
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
frameAndSend(data, priority = proto_1.Priority.Medium) {
|
|
308
|
+
const frame = new proto_1.Frame();
|
|
309
|
+
frame.reliability = proto_1.Reliability.ReliableOrdered;
|
|
310
|
+
frame.orderChannel = 0;
|
|
311
|
+
frame.payload = data;
|
|
312
|
+
this.sendFrame(frame, priority);
|
|
313
|
+
}
|
|
314
|
+
sendFrame(frame, priority = proto_1.Priority.Medium) {
|
|
315
|
+
const channel = frame.orderChannel;
|
|
316
|
+
if (frame.isSequenced()) {
|
|
317
|
+
frame.orderedFrameIndex = this.outputOrderIndex[channel];
|
|
318
|
+
frame.sequenceFrameIndex = this.outputSequenceIndex[channel]++;
|
|
319
|
+
}
|
|
320
|
+
else if (frame.isOrdered()) {
|
|
321
|
+
frame.orderedFrameIndex = this.outputOrderIndex[channel]++;
|
|
322
|
+
this.outputSequenceIndex[channel] = 0;
|
|
323
|
+
}
|
|
324
|
+
const maxSize = this.mtu - MTU_HEADER_SIZE;
|
|
325
|
+
if (frame.payload.byteLength > maxSize) {
|
|
326
|
+
this.sendSplit(frame, maxSize, priority);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
if (frame.isReliable())
|
|
330
|
+
frame.reliableFrameIndex = this.outputReliableIndex++;
|
|
331
|
+
this.queueFrame(frame, priority);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
sendSplit(frame, maxSize, priority) {
|
|
335
|
+
const payload = frame.payload;
|
|
336
|
+
const splitSize = Math.ceil(payload.byteLength / maxSize);
|
|
337
|
+
const splitId = this.outputSplitIndex++ & 0xffff;
|
|
338
|
+
for (let i = 0; i < splitSize; i++) {
|
|
339
|
+
const nf = new proto_1.Frame();
|
|
340
|
+
nf.reliability = frame.reliability;
|
|
341
|
+
nf.sequenceFrameIndex = frame.sequenceFrameIndex;
|
|
342
|
+
nf.orderedFrameIndex = frame.orderedFrameIndex;
|
|
343
|
+
nf.orderChannel = frame.orderChannel;
|
|
344
|
+
if (nf.isReliable())
|
|
345
|
+
nf.reliableFrameIndex = this.outputReliableIndex++;
|
|
346
|
+
nf.payload = payload.subarray(i * maxSize, Math.min((i + 1) * maxSize, payload.byteLength));
|
|
347
|
+
nf.splitFrameIndex = i;
|
|
348
|
+
nf.splitId = splitId;
|
|
349
|
+
nf.splitSize = splitSize;
|
|
350
|
+
this.queueFrame(nf, priority);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
queueFrame(frame, priority) {
|
|
354
|
+
let length = 4;
|
|
355
|
+
for (const f of this.outputFrames)
|
|
356
|
+
length += f.getByteLength();
|
|
357
|
+
if (length + frame.getByteLength() > this.mtu - MTU_HEADER_SIZE)
|
|
358
|
+
this.flush();
|
|
359
|
+
this.outputFrames.add(frame);
|
|
360
|
+
if (priority === proto_1.Priority.High)
|
|
361
|
+
this.flush();
|
|
362
|
+
}
|
|
363
|
+
flush() {
|
|
364
|
+
if (this.outputFrames.size === 0)
|
|
365
|
+
return;
|
|
366
|
+
const fs = new proto_1.FrameSet();
|
|
367
|
+
fs.sequence = this.outputSequence++;
|
|
368
|
+
fs.frames = [...this.outputFrames];
|
|
369
|
+
this.outputBackup.set(fs.sequence, fs.frames);
|
|
370
|
+
this.outputBackupTimestamps.set(fs.sequence, Date.now());
|
|
371
|
+
this.outputFrames.clear();
|
|
372
|
+
const serialized = fs.serialize();
|
|
373
|
+
this.send(serialized);
|
|
374
|
+
}
|
|
375
|
+
onFrameSet(fs) {
|
|
376
|
+
if (this.receivedFrameSequences.has(fs.sequence))
|
|
377
|
+
return;
|
|
378
|
+
this.lostFrameSequences.delete(fs.sequence);
|
|
379
|
+
this.receivedFrameSequences.add(fs.sequence);
|
|
380
|
+
this.pendingAcks.add(fs.sequence);
|
|
381
|
+
if (fs.sequence > this.lastInputSequence) {
|
|
382
|
+
for (let i = this.lastInputSequence + 1; i < fs.sequence; i++) {
|
|
383
|
+
if (!this.receivedFrameSequences.has(i))
|
|
384
|
+
this.lostFrameSequences.add(i);
|
|
385
|
+
}
|
|
386
|
+
this.lastInputSequence = fs.sequence;
|
|
387
|
+
}
|
|
388
|
+
for (const frame of fs.frames)
|
|
389
|
+
this.handleFrame(frame);
|
|
390
|
+
}
|
|
391
|
+
handleFrame(frame) {
|
|
392
|
+
if (frame.isReliable()) {
|
|
393
|
+
if (this.receivedReliableFrameIndices.has(frame.reliableFrameIndex))
|
|
394
|
+
return;
|
|
395
|
+
this.receivedReliableFrameIndices.add(frame.reliableFrameIndex);
|
|
396
|
+
if (frame.reliableFrameIndex > this.highestReliableIndex)
|
|
397
|
+
this.highestReliableIndex = frame.reliableFrameIndex;
|
|
398
|
+
}
|
|
399
|
+
if (frame.isSplit())
|
|
400
|
+
this.handleSplit(frame);
|
|
401
|
+
else if (frame.isSequenced())
|
|
402
|
+
this.handleSequenced(frame);
|
|
403
|
+
else if (frame.isOrdered())
|
|
404
|
+
this.handleOrdered(frame);
|
|
405
|
+
else
|
|
406
|
+
this.handleOnlinePacket(frame.payload);
|
|
407
|
+
}
|
|
408
|
+
handleSplit(frame) {
|
|
409
|
+
let entry = this.fragmentsQueue.get(frame.splitId);
|
|
410
|
+
if (!entry) {
|
|
411
|
+
entry = { frames: new Map(), timestamp: Date.now() };
|
|
412
|
+
this.fragmentsQueue.set(frame.splitId, entry);
|
|
413
|
+
}
|
|
414
|
+
entry.frames.set(frame.splitFrameIndex, frame);
|
|
415
|
+
if (entry.frames.size !== frame.splitSize)
|
|
416
|
+
return;
|
|
417
|
+
const stream = new binarystream_1.BinaryStream();
|
|
418
|
+
for (let i = 0; i < frame.splitSize; i++) {
|
|
419
|
+
const f = entry.frames.get(i);
|
|
420
|
+
if (!f) {
|
|
421
|
+
this.fragmentsQueue.delete(frame.splitId);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
stream.write(f.payload);
|
|
425
|
+
}
|
|
426
|
+
this.fragmentsQueue.delete(frame.splitId);
|
|
427
|
+
const reassembled = new proto_1.Frame();
|
|
428
|
+
reassembled.reliability = frame.reliability;
|
|
429
|
+
reassembled.reliableFrameIndex = frame.reliableFrameIndex;
|
|
430
|
+
reassembled.sequenceFrameIndex = frame.sequenceFrameIndex;
|
|
431
|
+
reassembled.orderedFrameIndex = frame.orderedFrameIndex;
|
|
432
|
+
reassembled.orderChannel = frame.orderChannel;
|
|
433
|
+
reassembled.splitSize = 0;
|
|
434
|
+
reassembled.payload = stream.getBuffer();
|
|
435
|
+
if (reassembled.isSequenced())
|
|
436
|
+
this.handleSequenced(reassembled);
|
|
437
|
+
else if (reassembled.isOrdered())
|
|
438
|
+
this.handleOrdered(reassembled);
|
|
439
|
+
else
|
|
440
|
+
this.handleOnlinePacket(reassembled.payload);
|
|
441
|
+
}
|
|
442
|
+
handleSequenced(frame) {
|
|
443
|
+
const ch = frame.orderChannel;
|
|
444
|
+
if (frame.sequenceFrameIndex < this.inputHighestSequenceIndex[ch])
|
|
445
|
+
return;
|
|
446
|
+
this.inputHighestSequenceIndex[ch] = frame.sequenceFrameIndex + 1;
|
|
447
|
+
this.handleOnlinePacket(frame.payload);
|
|
448
|
+
}
|
|
449
|
+
handleOrdered(frame) {
|
|
450
|
+
const ch = frame.orderChannel;
|
|
451
|
+
const expected = this.inputOrderIndex[ch];
|
|
452
|
+
if (frame.orderedFrameIndex === expected) {
|
|
453
|
+
this.inputHighestSequenceIndex[ch] = 0;
|
|
454
|
+
this.inputOrderIndex[ch] = expected + 1;
|
|
455
|
+
this.handleOnlinePacket(frame.payload);
|
|
456
|
+
const queue = this.inputOrderingQueue.get(ch);
|
|
457
|
+
let next = expected + 1;
|
|
458
|
+
while (queue.has(next)) {
|
|
459
|
+
this.handleOnlinePacket(queue.get(next).payload);
|
|
460
|
+
queue.delete(next);
|
|
461
|
+
next++;
|
|
462
|
+
}
|
|
463
|
+
this.inputOrderIndex[ch] = next;
|
|
464
|
+
}
|
|
465
|
+
else if (frame.orderedFrameIndex > expected) {
|
|
466
|
+
if (frame.orderedFrameIndex - expected > ORDER_SKIP_THRESHOLD) {
|
|
467
|
+
const queue = this.inputOrderingQueue.get(ch);
|
|
468
|
+
if (queue)
|
|
469
|
+
queue.clear();
|
|
470
|
+
this.inputOrderIndex[ch] = frame.orderedFrameIndex + 1;
|
|
471
|
+
this.handleOnlinePacket(frame.payload);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const queue = this.inputOrderingQueue.get(ch);
|
|
475
|
+
if (queue.size < ORDER_QUEUE_MAX)
|
|
476
|
+
queue.set(frame.orderedFrameIndex, frame);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
exports.NetworkSession = NetworkSession;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./packet"), exports);
|
|
18
|
+
__exportStar(require("./reliability"), exports);
|
|
19
|
+
__exportStar(require("./priority"), exports);
|
|
20
|
+
__exportStar(require("./status"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare enum Packet {
|
|
2
|
+
UnconnectedPing = 1,
|
|
3
|
+
UnconnectedPingOpenConnections = 2,
|
|
4
|
+
UnconnectedPong = 28,
|
|
5
|
+
ConnectedPing = 0,
|
|
6
|
+
ConnectedPong = 3,
|
|
7
|
+
OpenConnectionRequest1 = 5,
|
|
8
|
+
OpenConnectionReply1 = 6,
|
|
9
|
+
OpenConnectionRequest2 = 7,
|
|
10
|
+
OpenConnectionReply2 = 8,
|
|
11
|
+
ConnectionRequest = 9,
|
|
12
|
+
ConnectionRequestAccepted = 16,
|
|
13
|
+
NewIncomingConnection = 19,
|
|
14
|
+
DisconnectionNotification = 21,
|
|
15
|
+
IncompatibleProtocolVersion = 25,
|
|
16
|
+
AlreadyConnected = 18,
|
|
17
|
+
Ack = 192,
|
|
18
|
+
Nack = 160,
|
|
19
|
+
FrameSetMin = 128,
|
|
20
|
+
FrameSetMax = 141
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Packet = void 0;
|
|
4
|
+
var Packet;
|
|
5
|
+
(function (Packet) {
|
|
6
|
+
Packet[Packet["UnconnectedPing"] = 1] = "UnconnectedPing";
|
|
7
|
+
Packet[Packet["UnconnectedPingOpenConnections"] = 2] = "UnconnectedPingOpenConnections";
|
|
8
|
+
Packet[Packet["UnconnectedPong"] = 28] = "UnconnectedPong";
|
|
9
|
+
Packet[Packet["ConnectedPing"] = 0] = "ConnectedPing";
|
|
10
|
+
Packet[Packet["ConnectedPong"] = 3] = "ConnectedPong";
|
|
11
|
+
Packet[Packet["OpenConnectionRequest1"] = 5] = "OpenConnectionRequest1";
|
|
12
|
+
Packet[Packet["OpenConnectionReply1"] = 6] = "OpenConnectionReply1";
|
|
13
|
+
Packet[Packet["OpenConnectionRequest2"] = 7] = "OpenConnectionRequest2";
|
|
14
|
+
Packet[Packet["OpenConnectionReply2"] = 8] = "OpenConnectionReply2";
|
|
15
|
+
Packet[Packet["ConnectionRequest"] = 9] = "ConnectionRequest";
|
|
16
|
+
Packet[Packet["ConnectionRequestAccepted"] = 16] = "ConnectionRequestAccepted";
|
|
17
|
+
Packet[Packet["NewIncomingConnection"] = 19] = "NewIncomingConnection";
|
|
18
|
+
Packet[Packet["DisconnectionNotification"] = 21] = "DisconnectionNotification";
|
|
19
|
+
Packet[Packet["IncompatibleProtocolVersion"] = 25] = "IncompatibleProtocolVersion";
|
|
20
|
+
Packet[Packet["AlreadyConnected"] = 18] = "AlreadyConnected";
|
|
21
|
+
Packet[Packet["Ack"] = 192] = "Ack";
|
|
22
|
+
Packet[Packet["Nack"] = 160] = "Nack";
|
|
23
|
+
Packet[Packet["FrameSetMin"] = 128] = "FrameSetMin";
|
|
24
|
+
Packet[Packet["FrameSetMax"] = 141] = "FrameSetMax";
|
|
25
|
+
})(Packet || (exports.Packet = Packet = {}));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Reliability = void 0;
|
|
4
|
+
var Reliability;
|
|
5
|
+
(function (Reliability) {
|
|
6
|
+
Reliability[Reliability["Unreliable"] = 0] = "Unreliable";
|
|
7
|
+
Reliability[Reliability["UnreliableSequenced"] = 1] = "UnreliableSequenced";
|
|
8
|
+
Reliability[Reliability["Reliable"] = 2] = "Reliable";
|
|
9
|
+
Reliability[Reliability["ReliableOrdered"] = 3] = "ReliableOrdered";
|
|
10
|
+
Reliability[Reliability["ReliableSequenced"] = 4] = "ReliableSequenced";
|
|
11
|
+
Reliability[Reliability["UnreliableWithAckReceipt"] = 5] = "UnreliableWithAckReceipt";
|
|
12
|
+
Reliability[Reliability["ReliableWithAckReceipt"] = 6] = "ReliableWithAckReceipt";
|
|
13
|
+
Reliability[Reliability["ReliableOrderedWithAckReceipt"] = 7] = "ReliableOrderedWithAckReceipt";
|
|
14
|
+
})(Reliability || (exports.Reliability = Reliability = {}));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Status = void 0;
|
|
4
|
+
var Status;
|
|
5
|
+
(function (Status) {
|
|
6
|
+
Status[Status["Connecting"] = 0] = "Connecting";
|
|
7
|
+
Status[Status["Connected"] = 1] = "Connected";
|
|
8
|
+
Status[Status["Disconnecting"] = 2] = "Disconnecting";
|
|
9
|
+
Status[Status["Disconnected"] = 3] = "Disconnected";
|
|
10
|
+
})(Status || (exports.Status = Status = {}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./packets"), exports);
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
19
|
+
__exportStar(require("./enums"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataPacket = void 0;
|
|
4
|
+
const binarystream_1 = require("@serenityjs/binarystream");
|
|
5
|
+
class DataPacket extends binarystream_1.BinaryStream {
|
|
6
|
+
static ID;
|
|
7
|
+
serialize() {
|
|
8
|
+
throw new Error(`${this.constructor.name}.serialize is not implemented!`);
|
|
9
|
+
}
|
|
10
|
+
deserialize() {
|
|
11
|
+
throw new Error(`${this.constructor.name}.deserialize is not implemented!`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.DataPacket = DataPacket;
|