avocado-old/packages/packet/socket.io-parser.js
2019-04-20 01:54:31 -05:00

114 lines
2.1 KiB
JavaScript

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];
let packet;
try {
const schema = schemaFromId(packetId);
if (!schema) {
throw new Error(`unknown schema with id: ${packetId}`);
}
const {data} = schema.decode(obj);
const Packet = packetFromId(packetId);
packet = {
type: TYPES.EVENT,
data: [packetId, new Packet(data)],
nsp: '/',
};
}
catch (e) {
packet = errorPacket;
}
this.emit('decoded', packet);
}
parseJSON(obj) {
let decoded;
try {
decoded = JSON.parse(obj);
}
catch (e) {
decoded = errorPacket;
}
this.emit('decoded', decoded);
}
}
export {Decoder, Encoder};