2019-04-11 15:26:13 -05:00
|
|
|
import schemapack from 'schemapack';
|
|
|
|
|
|
|
|
import {compose} from '@avocado/core';
|
|
|
|
import {EventEmitter} from '@avocado/mixins';
|
|
|
|
|
|
|
|
import {allPackets, idFromPacket, packetFromId} from './registry';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Packet types (see https://github.com/socketio/socket.io-protocol)
|
|
|
|
*/
|
|
|
|
const TYPES = {
|
|
|
|
EVENT: 2,
|
|
|
|
ERROR: 4,
|
|
|
|
BINARY_EVENT: 5,
|
|
|
|
};
|
|
|
|
|
|
|
|
const errorPacket = {
|
|
|
|
type: TYPES.ERROR,
|
|
|
|
data: 'parser error',
|
|
|
|
};
|
|
|
|
|
|
|
|
let schemas = undefined;
|
|
|
|
function schemaFromId(id) {
|
|
|
|
if (!schemas) {
|
|
|
|
schemas = {};
|
|
|
|
for (const Packet of allPackets()) {
|
|
|
|
const id_ = idFromPacket(Packet);
|
|
|
|
schemas[id_] = schemapack.build(Packet.schema);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return schemas[id];
|
|
|
|
}
|
|
|
|
|
|
|
|
class Encoder {
|
|
|
|
|
|
|
|
encode(packet, callback) {
|
|
|
|
switch (packet.type) {
|
|
|
|
case TYPES.EVENT:
|
|
|
|
case TYPES.BINARY_EVENT:
|
|
|
|
return callback([this.pack(packet)]);
|
|
|
|
default:
|
|
|
|
return callback([JSON.stringify(packet)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pack(packet) {
|
|
|
|
const eventId = packet.data[0];
|
|
|
|
const schema = schemaFromId(eventId);
|
|
|
|
if (!schema) {
|
|
|
|
throw new Error('unknown schema with id: ' + eventId);
|
|
|
|
}
|
|
|
|
return schema.encode({
|
|
|
|
_id: eventId,
|
|
|
|
data: packet.data[1],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const decorateDecoder = compose(
|
|
|
|
EventEmitter,
|
|
|
|
);
|
|
|
|
|
|
|
|
class Decoder extends decorateDecoder(class {}) {
|
|
|
|
|
|
|
|
add(obj) {
|
|
|
|
if (typeof obj === 'string') {
|
|
|
|
this.parseJSON(obj);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.parseBinary(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {}
|
|
|
|
|
|
|
|
parseBinary(obj) {
|
|
|
|
const view = new Uint8Array(obj);
|
|
|
|
const packetId = view[0];
|
2019-04-14 15:32:17 -05:00
|
|
|
let packet;
|
2019-04-11 15:26:13 -05:00
|
|
|
try {
|
|
|
|
const schema = schemaFromId(packetId);
|
|
|
|
if (!schema) {
|
|
|
|
throw new Error(`unknown schema with id: ${packetId}`);
|
|
|
|
}
|
2019-04-20 01:47:46 -05:00
|
|
|
const {data} = schema.decode(obj);
|
2019-04-11 15:26:13 -05:00
|
|
|
const Packet = packetFromId(packetId);
|
2019-04-14 15:32:17 -05:00
|
|
|
packet = {
|
2019-04-11 15:26:13 -05:00
|
|
|
type: TYPES.EVENT,
|
|
|
|
data: [packetId, new Packet(data)],
|
2019-04-20 01:47:46 -05:00
|
|
|
nsp: '/',
|
2019-04-14 15:32:17 -05:00
|
|
|
};
|
2019-04-11 15:26:13 -05:00
|
|
|
}
|
2019-04-14 15:32:17 -05:00
|
|
|
catch (e) {
|
|
|
|
packet = errorPacket;
|
|
|
|
}
|
|
|
|
this.emit('decoded', packet);
|
2019-04-11 15:26:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
parseJSON(obj) {
|
2019-04-14 15:32:17 -05:00
|
|
|
let decoded;
|
2019-04-11 15:26:13 -05:00
|
|
|
try {
|
2019-04-14 15:32:17 -05:00
|
|
|
decoded = JSON.parse(obj);
|
2019-04-11 15:26:13 -05:00
|
|
|
}
|
|
|
|
catch (e) {
|
2019-04-14 15:32:17 -05:00
|
|
|
decoded = errorPacket;
|
2019-04-11 15:26:13 -05:00
|
|
|
}
|
2019-04-14 15:32:17 -05:00
|
|
|
this.emit('decoded', decoded);
|
2019-04-11 15:26:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
export {Decoder, Encoder};
|