-
Notifications
You must be signed in to change notification settings - Fork 0
/
protocol.js
119 lines (119 loc) · 4.81 KB
/
protocol.js
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
const protocol = {
defaultConfig: {
types: {
"String": { // encode and decode work with regular JS arrays of bytes, then it's converted to Uint8Array.
// this is just an implementation of what we have over in the rust program
encode(string) { // THANKS, STACKOVERFLOW
var utf8 = unescape(encodeURIComponent(string));
var arr = [Math.floor(string.length / 256), string.length % 256]; // convert length to a big endian (network order) byte array
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i)); // push in the actual data
}
return arr;
},
decode(bytes) {
var length = bytes.shift() * 256 + bytes.shift(); // go from two big endian bytes (network order, duh) to js number length; probably LE. endianness is cursed.
// just use big endian for everything, dipshits
return new TextDecoder().decode(new Uint8Array(bytes.splice(0, length)));
}
},
"u8": {
encode(data) {
return [data];
},
decode(bytes) {
return bytes.shift();
}
},
"u16": {
encode(data) {
return [Math.floor(data / 256), data % 256];
},
decode(bytes) {
return bytes.shift() * 256 + bytes.shift();
}
},
"f32": {
decode(bytes) { // THANKS, STACKOVERFLOW
var buf = new ArrayBuffer(4);
var view = new DataView(buf);
for (var x = 0; x < 4; x++) {
view.setUint8(x, bytes.shift());
}
return view.getFloat32(0);
},
encode(data) {
var buf = new ArrayBuffer(4);
var view = new DataView(buf);
view.setFloat32(0, data);
var ret = [];
for (var x = 0; x < 4; x++) {
ret.push(view.getUint8(x));
}
return ret;
}
},
"bool": {
decode(bytes) {
return bytes.shift() != 0;
},
encode(data) {
return [data ? 1 : 0];
}
}
}
},
async connectV3(config, uri, secure = false) { // TODO: make this handle URIs better, right now it makes a lot of assumptions
let manifest = await (await fetch(secure ? "https" : "http" + "://" + uri + "/manifest")).json();
console.log(manifest);
var obj = {
appname: manifest.application_name,
toServer: manifest.incoming_protocol,
fromServer: manifest.outgoing_protocol,
socket: new WebSocket(secure ? "wss" : "ws" + "://" + uri),
sendHandle(name) {
var op = undefined;
var socket = this.socket;
this.toServer.operations.forEach(item => {
if (item.name == name) {
op = item;
}
});
return (...args) => {
var out = [op.opcode];
for (var i = 0; i < op.args.length; i++) {
out.push(...config.types[op.args[i]].encode(args[i]));
}
socket.send(new Uint8Array(out));
}
},
listen(listener) {
this.socket.addEventListener("message", (msgdata) => {
var bytearray = Array.from(new Uint8Array(msgdata.data));
var opcode = bytearray.shift();
var type = undefined;
this.fromServer.operations.forEach(op => {
if (op.opcode == opcode) {
type = op;
}
});
if (type) {
var retProps = [];
type.args.forEach(rtype => {
retProps.push(config.types[rtype].decode(bytearray));
});
listener(type.name, retProps);
}
else {
console.warn("Invalid operation code " + opcode);
}
});
},
onOpen(callback) {
this.socket.addEventListener("open", callback);
}
};
obj.socket.binaryType = "arraybuffer";
return obj;
}
}