-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConnection.js
More file actions
129 lines (113 loc) · 4.35 KB
/
Connection.js
File metadata and controls
129 lines (113 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
class Connection extends PacketRegistry {
constructor(packetListeners) {
super();
this.packetListeners = packetListeners;
this.timeout = 5000;
this.responseListeners = {};
this.lastPacketId = -1;
this.responseIds = new WeakMap();
}
start(socket) {
this.socket = socket;
socket.binaryType = "arraybuffer";
socket.addEventListener("error", event => {
console.error("WebSocket error: " + JSON.stringify(event, ["message", "arguments", "type", "name"]));
});
socket.addEventListener("message", event => {
var buf = new DataInputStream(Array.from(new Uint8Array(event.data)));
// Read metadata
var id = buf.readInt();
var responseId = buf.readInt();
var PacketType = this.getPacketType(buf.readInt());
if (buf.readInt() != buf.remaining())
throw new Error("Incoming packet is corrupted!");
if (PacketType === null)
throw new Error("Unregistered packet type received!");
// Read and handle packet
var packet = new PacketType(buf);
this.responseIds.set(packet, id);
if (responseId != -1) {
var listener = this.responseListeners[responseId];
if (listener !== undefined && listener.key != -1 && listener.key < Date.now())
delete this.responseListeners[responseId];
else if (listener !== undefined)
this.invokePacketListeners([listener.value], packet);
} else
this.invokePacketListeners(this.packetListeners, packet);
});
}
invokePacketListeners(listeners, packet) {
// Normally multithreaded
// Thus, WaitState isn't nessesary
for (var listener of listeners)
listener(packet, this);
}
sendPacket_internal(packet, responseId, response) {
if (this.socket === null || this.socket.readyState != 1)
throw new Error("The connection isn't alive!");
this.cleanResponseListeners();
var id = ++this.lastPacketId;
if (response !== null) {
var packetTimeout = this.timeout == -1 ? -1 : Date.now() + this.timeout;
this.responseListeners[id] = {key: packetTimeout, value: response};
}
var out = new DataOutputStream();
out.writeInt(id);
out.writeInt(responseId);
out.writeInt(this.getPacketId(packet));
var data = new DataOutputStream();
packet.write(data);
out.writeInt(data.length());
for (var b of data.bytes)
out.write(b);
this.socket.send(new Uint8Array(out.bytes));
return id;
}
sendPacket(packet, response) {
return this.sendPacket_internal(packet, -1, response ?? null);
}
reply(toReply, packet, response) {
return this.sendPacket_internal(packet, this.responseIds.get(toReply), response ?? null);
}
// sendPacketWithResponse not supported due to single threading
// Use a callback instead
setTimeout(timeout) {
this.timeout = timeout;
}
getTimeout() {
return this.timeout;
}
removeResponseListener(query) {
if (query instanceof PacketListener) {
var toRemove = [];
for (var id in this.responseListeners) {
if (this.responseListeners[id].value == query)
toRemove.push(id);
}
if (toRemove.length == 0)
return false;
for (var id of toRemove)
delete this.responseListeners[id];
return true;
}
}
cleanResponseListeners() {
var time = Date.now();
var toRemove = [];
for (var id in this.responseListeners) {
if (this.responseListeners[id].key != -1 && this.responseListeners[id].key < time)
toRemove.push(id);
}
for (var id of toRemove)
delete this.responseListeners[id];
}
isAlive() {
return this.socket != null && this.socket.readyState < 2;
}
close() {
this.socket.close();
this.responseListeners = {};
this.responseIds = new WeakMap();
}
onClose() {}
}