150 lines
5.7 KiB
JavaScript
150 lines
5.7 KiB
JavaScript
import { BinaryInfo } from './BinaryInfo.js';
|
|
import { FLAG_BYTE, FLAG_EVENT, FLAG_EXTENDED, FLAG_FIELD, FLAG_GLOBAL, WEB_EVENTS, WEB_GLOBALS } from './constants.js';
|
|
const getHeaderBitLength = (key) => (key < 256 ? 2 : 3);
|
|
export const encodeWAM = (binaryInfo) => {
|
|
binaryInfo.buffer = [];
|
|
encodeWAMHeader(binaryInfo);
|
|
encodeEvents(binaryInfo);
|
|
const totalSize = binaryInfo.buffer.map(a => a.length).reduce((a, b) => a + b);
|
|
const buffer = Buffer.alloc(totalSize);
|
|
let offset = 0;
|
|
for (const buffer_ of binaryInfo.buffer) {
|
|
buffer_.copy(buffer, offset);
|
|
offset += buffer_.length;
|
|
}
|
|
return buffer;
|
|
};
|
|
function encodeWAMHeader(binaryInfo) {
|
|
const headerBuffer = Buffer.alloc(8); // starting buffer
|
|
headerBuffer.write('WAM', 0, 'utf8');
|
|
headerBuffer.writeUInt8(binaryInfo.protocolVersion, 3);
|
|
headerBuffer.writeUInt8(1, 4); //random flag
|
|
headerBuffer.writeUInt16BE(binaryInfo.sequence, 5);
|
|
headerBuffer.writeUInt8(0, 7); // regular channel
|
|
binaryInfo.buffer.push(headerBuffer);
|
|
}
|
|
function encodeGlobalAttributes(binaryInfo, globals) {
|
|
for (const [key, _value] of Object.entries(globals)) {
|
|
const id = WEB_GLOBALS.find(a => a?.name === key).id;
|
|
let value = _value;
|
|
if (typeof value === 'boolean') {
|
|
value = value ? 1 : 0;
|
|
}
|
|
binaryInfo.buffer.push(serializeData(id, value, FLAG_GLOBAL));
|
|
}
|
|
}
|
|
function encodeEvents(binaryInfo) {
|
|
for (const [name, { props, globals }] of binaryInfo.events.map(a => Object.entries(a)[0])) {
|
|
encodeGlobalAttributes(binaryInfo, globals);
|
|
const event = WEB_EVENTS.find(a => a.name === name);
|
|
const props_ = Object.entries(props);
|
|
let extended = false;
|
|
for (const [, value] of props_) {
|
|
extended || (extended = value !== null);
|
|
}
|
|
const eventFlag = extended ? FLAG_EVENT : FLAG_EVENT | FLAG_EXTENDED;
|
|
binaryInfo.buffer.push(serializeData(event.id, -event.weight, eventFlag));
|
|
for (let i = 0; i < props_.length; i++) {
|
|
const [key, _value] = props_[i];
|
|
const id = event.props[key]?.[0];
|
|
extended = i < props_.length - 1;
|
|
let value = _value;
|
|
if (typeof value === 'boolean') {
|
|
value = value ? 1 : 0;
|
|
}
|
|
const fieldFlag = extended ? FLAG_EVENT : FLAG_FIELD | FLAG_EXTENDED;
|
|
binaryInfo.buffer.push(serializeData(id, value, fieldFlag));
|
|
}
|
|
}
|
|
}
|
|
function serializeData(key, value, flag) {
|
|
const bufferLength = getHeaderBitLength(key);
|
|
let buffer;
|
|
let offset = 0;
|
|
if (value === null) {
|
|
if (flag === FLAG_GLOBAL) {
|
|
buffer = Buffer.alloc(bufferLength);
|
|
offset = serializeHeader(buffer, offset, key, flag);
|
|
return buffer;
|
|
}
|
|
}
|
|
else if (typeof value === 'number' && Number.isInteger(value)) {
|
|
// is number
|
|
if (value === 0 || value === 1) {
|
|
buffer = Buffer.alloc(bufferLength);
|
|
offset = serializeHeader(buffer, offset, key, flag | ((value + 1) << 4));
|
|
return buffer;
|
|
}
|
|
else if (-128 <= value && value < 128) {
|
|
buffer = Buffer.alloc(bufferLength + 1);
|
|
offset = serializeHeader(buffer, offset, key, flag | (3 << 4));
|
|
buffer.writeInt8(value, offset);
|
|
return buffer;
|
|
}
|
|
else if (-32768 <= value && value < 32768) {
|
|
buffer = Buffer.alloc(bufferLength + 2);
|
|
offset = serializeHeader(buffer, offset, key, flag | (4 << 4));
|
|
buffer.writeInt16LE(value, offset);
|
|
return buffer;
|
|
}
|
|
else if (-2147483648 <= value && value < 2147483648) {
|
|
buffer = Buffer.alloc(bufferLength + 4);
|
|
offset = serializeHeader(buffer, offset, key, flag | (5 << 4));
|
|
buffer.writeInt32LE(value, offset);
|
|
return buffer;
|
|
}
|
|
else {
|
|
buffer = Buffer.alloc(bufferLength + 8);
|
|
offset = serializeHeader(buffer, offset, key, flag | (7 << 4));
|
|
buffer.writeDoubleLE(value, offset);
|
|
return buffer;
|
|
}
|
|
}
|
|
else if (typeof value === 'number') {
|
|
// is float
|
|
buffer = Buffer.alloc(bufferLength + 8);
|
|
offset = serializeHeader(buffer, offset, key, flag | (7 << 4));
|
|
buffer.writeDoubleLE(value, offset);
|
|
return buffer;
|
|
}
|
|
else if (typeof value === 'string') {
|
|
// is string
|
|
const utf8Bytes = Buffer.byteLength(value, 'utf8');
|
|
if (utf8Bytes < 256) {
|
|
buffer = Buffer.alloc(bufferLength + 1 + utf8Bytes);
|
|
offset = serializeHeader(buffer, offset, key, flag | (8 << 4));
|
|
buffer.writeUint8(utf8Bytes, offset++);
|
|
}
|
|
else if (utf8Bytes < 65536) {
|
|
buffer = Buffer.alloc(bufferLength + 2 + utf8Bytes);
|
|
offset = serializeHeader(buffer, offset, key, flag | (9 << 4));
|
|
buffer.writeUInt16LE(utf8Bytes, offset);
|
|
offset += 2;
|
|
}
|
|
else {
|
|
buffer = Buffer.alloc(bufferLength + 4 + utf8Bytes);
|
|
offset = serializeHeader(buffer, offset, key, flag | (10 << 4));
|
|
buffer.writeUInt32LE(utf8Bytes, offset);
|
|
offset += 4;
|
|
}
|
|
buffer.write(value, offset, 'utf8');
|
|
return buffer;
|
|
}
|
|
throw 'missing';
|
|
}
|
|
function serializeHeader(buffer, offset, key, flag) {
|
|
if (key < 256) {
|
|
buffer.writeUInt8(flag, offset);
|
|
offset += 1;
|
|
buffer.writeUInt8(key, offset);
|
|
offset += 1;
|
|
}
|
|
else {
|
|
buffer.writeUInt8(flag | FLAG_BYTE, offset);
|
|
offset += 1;
|
|
buffer.writeUInt16LE(key, offset);
|
|
offset += 2;
|
|
}
|
|
return offset;
|
|
}
|
|
//# sourceMappingURL=encode.js.map
|