123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- 'use strict';
-
- const assert = require('bsert');
-
- const types = {
- CONNECT: 0,
- DISCONNECT: 1,
- EVENT: 2,
- ACK: 3,
- ERROR: 4,
- BINARY_EVENT: 5,
- BINARY_ACK: 6
- };
-
- class Packet {
- constructor(type) {
- this.type = type || 0;
- this.attachments = 0;
- this.nsp = '/';
- this.id = -1;
- this.data = '';
- this.buffers = [];
- }
-
- setData(data) {
- assert(data !== undefined);
- assert(typeof data !== 'number');
- assert(typeof data !== 'function');
-
- const [str, buffers] = deconstruct(data);
-
- this.data = str;
- this.buffers = buffers;
- this.attachments = buffers.length;
-
- if (this.attachments > 0) {
- switch (this.type) {
- case types.EVENT:
- this.type = types.BINARY_EVENT;
- break;
- case types.ACK:
- this.type = types.BINARY_ACK;
- break;
- }
- }
-
- return this;
- }
-
- getData() {
- if (this.data.length === 0)
- return null;
- return reconstruct(this.data, this.buffers);
- }
-
- toString() {
- let str = this.type.toString(10);
-
- switch (this.type) {
- case types.BINARY_EVENT:
- case types.BINARY_ACK:
- str += this.attachments.toString(10) + '-';
- break;
- }
-
- if (this.nsp !== '/')
- str += this.nsp + ',';
-
- if (this.id !== -1)
- str += this.id.toString(10);
-
- str += this.data;
-
- return str;
- }
-
- static fromString(str) {
- assert(typeof str === 'string');
- assert(str.length > 0);
-
- let i = 0;
- let type = 0;
- let attachments = 0;
- let nsp = '/';
- let id = -1;
- let data = '';
-
- [i, type] = readChar(str, i);
-
- assert(type !== -1);
- assert(type <= types.BINARY_ACK);
-
- switch (type) {
- case types.BINARY_EVENT:
- case types.BINARY_ACK: {
- [i, attachments] = readInt(str, i);
- assert(attachments !== -1);
- assert(i < str.length);
- assert(str[i] === '-');
- i += 1;
- break;
- }
- }
-
- if (i < str.length && str[i] === '/')
- [i, nsp] = readTo(str, i, ',');
-
- [i, id] = readInt(str, i);
-
- if (i < str.length)
- data = str.substring(i);
-
- const packet = new this();
-
- packet.type = type;
- packet.attachments = attachments;
- packet.nsp = nsp;
- packet.id = id;
- packet.data = data;
-
- return packet;
- }
- }
-
- Packet.types = types;
-
- function isPlaceholder(obj) {
- return obj !== null
- && typeof obj === 'object'
- && obj._placeholder === true
- && (obj.num >>> 0) === obj.num;
- }
-
- function deconstruct(obj) {
- const buffers = [];
- const out = replace('', obj, buffers, new Map());
- const str = JSON.stringify(out);
- return [str, buffers];
- }
-
- function replace(key, value, buffers, seen) {
- if (value === null || typeof value !== 'object')
- return value;
-
- if (Buffer.isBuffer(value)) {
- const placeholder = seen.get(value);
-
- // De-duplicate.
- if (placeholder != null)
- return placeholder;
-
- const out = { _placeholder: true, num: buffers.length };
-
- seen.set(value, out);
- buffers.push(value);
-
- return out;
- }
-
- if (seen.has(value))
- throw new TypeError('Converting circular structure to JSON.');
-
- if (Array.isArray(value)) {
- const out = [];
-
- seen.set(value, null);
-
- for (let i = 0; i < value.length; i++)
- out.push(replace(i, value[i], buffers, seen));
-
- seen.delete(value);
-
- return out;
- }
-
- const out = Object.create(null);
-
- const json = typeof value.toJSON === 'function'
- ? value.toJSON(key)
- : value;
-
- seen.set(value, null);
-
- for (const key of Object.keys(json))
- out[key] = replace(key, json[key], buffers, seen);
-
- seen.delete(value);
-
- return out;
- }
-
- function reconstruct(str, buffers) {
- return JSON.parse(str, (key, value) => {
- if (isPlaceholder(value)) {
- if (value.num < buffers.length)
- return buffers[value.num];
- }
- return value;
- });
- }
-
- function readChar(str, i) {
- const ch = str.charCodeAt(i) - 0x30;
-
- if (ch < 0 || ch > 9)
- return -1;
-
- return [i + 1, ch];
- }
-
- function readInt(str, i) {
- let len = 0;
- let num = 0;
-
- for (; i < str.length; i++) {
- const ch = str.charCodeAt(i) - 0x30;
-
- if (ch < 0 || ch > 9)
- break;
-
- num *= 10;
- num += ch;
- len += 1;
-
- assert(len <= 10);
- }
-
- assert(num <= 0xffffffff);
-
- if (len === 0)
- num = -1;
-
- return [i, num];
- }
-
- function readTo(str, i, ch) {
- let j = i;
-
- for (; j < str.length; j++) {
- if (str[j] === ch)
- break;
- }
-
- assert(j < str.length);
-
- return [j + 1, str.substring(i, j)];
- }
-
- /*
- * Expose
- */
-
- module.exports = Packet;
|