arnaucube
arnaucube/comunicationLeapPublic Self-hosted repository
comunicationLeap/node_modules/socket.io-parser/index.js
node_modules/socket.io-parser/index.jsRaw
  1
  2/**
  3 * Module dependencies.
  4 */
  5
  6var debug = require('debug')('socket.io-parser');
  7var json = require('json3');
  8var isArray = require('isarray');
  9var Emitter = require('component-emitter');
 10var binary = require('./binary');
 11var isBuf = require('./is-buffer');
 12
 13/**
 14 * Protocol version.
 15 *
 16 * @api public
 17 */
 18
 19exports.protocol = 4;
 20
 21/**
 22 * Packet types.
 23 *
 24 * @api public
 25 */
 26
 27exports.types = [
 28  'CONNECT',
 29  'DISCONNECT',
 30  'EVENT',
 31  'BINARY_EVENT',
 32  'ACK',
 33  'BINARY_ACK',
 34  'ERROR'
 35];
 36
 37/**
 38 * Packet type `connect`.
 39 *
 40 * @api public
 41 */
 42
 43exports.CONNECT = 0;
 44
 45/**
 46 * Packet type `disconnect`.
 47 *
 48 * @api public
 49 */
 50
 51exports.DISCONNECT = 1;
 52
 53/**
 54 * Packet type `event`.
 55 *
 56 * @api public
 57 */
 58
 59exports.EVENT = 2;
 60
 61/**
 62 * Packet type `ack`.
 63 *
 64 * @api public
 65 */
 66
 67exports.ACK = 3;
 68
 69/**
 70 * Packet type `error`.
 71 *
 72 * @api public
 73 */
 74
 75exports.ERROR = 4;
 76
 77/**
 78 * Packet type 'binary event'
 79 *
 80 * @api public
 81 */
 82
 83exports.BINARY_EVENT = 5;
 84
 85/**
 86 * Packet type `binary ack`. For acks with binary arguments.
 87 *
 88 * @api public
 89 */
 90
 91exports.BINARY_ACK = 6;
 92
 93/**
 94 * Encoder constructor.
 95 *
 96 * @api public
 97 */
 98
 99exports.Encoder = Encoder;
100
101/**
102 * Decoder constructor.
103 *
104 * @api public
105 */
106
107exports.Decoder = Decoder;
108
109/**
110 * A socket.io Encoder instance
111 *
112 * @api public
113 */
114
115function Encoder() {}
116
117/**
118 * Encode a packet as a single string if non-binary, or as a
119 * buffer sequence, depending on packet type.
120 *
121 * @param {Object} obj - packet object
122 * @param {Function} callback - function to handle encodings (likely engine.write)
123 * @return Calls callback with Array of encodings
124 * @api public
125 */
126
127Encoder.prototype.encode = function(obj, callback){
128  debug('encoding packet %j', obj);
129
130  if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
131    encodeAsBinary(obj, callback);
132  }
133  else {
134    var encoding = encodeAsString(obj);
135    callback([encoding]);
136  }
137};
138
139/**
140 * Encode packet as string.
141 *
142 * @param {Object} packet
143 * @return {String} encoded
144 * @api private
145 */
146
147function encodeAsString(obj) {
148  var str = '';
149  var nsp = false;
150
151  // first is type
152  str += obj.type;
153
154  // attachments if we have them
155  if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
156    str += obj.attachments;
157    str += '-';
158  }
159
160  // if we have a namespace other than `/`
161  // we append it followed by a comma `,`
162  if (obj.nsp && '/' != obj.nsp) {
163    nsp = true;
164    str += obj.nsp;
165  }
166
167  // immediately followed by the id
168  if (null != obj.id) {
169    if (nsp) {
170      str += ',';
171      nsp = false;
172    }
173    str += obj.id;
174  }
175
176  // json data
177  if (null != obj.data) {
178    if (nsp) str += ',';
179    str += json.stringify(obj.data);
180  }
181
182  debug('encoded %j as %s', obj, str);
183  return str;
184}
185
186/**
187 * Encode packet as 'buffer sequence' by removing blobs, and
188 * deconstructing packet into object with placeholders and
189 * a list of buffers.
190 *
191 * @param {Object} packet
192 * @return {Buffer} encoded
193 * @api private
194 */
195
196function encodeAsBinary(obj, callback) {
197
198  function writeEncoding(bloblessData) {
199    var deconstruction = binary.deconstructPacket(bloblessData);
200    var pack = encodeAsString(deconstruction.packet);
201    var buffers = deconstruction.buffers;
202
203    buffers.unshift(pack); // add packet info to beginning of data list
204    callback(buffers); // write all the buffers
205  }
206
207  binary.removeBlobs(obj, writeEncoding);
208}
209
210/**
211 * A socket.io Decoder instance
212 *
213 * @return {Object} decoder
214 * @api public
215 */
216
217function Decoder() {
218  this.reconstructor = null;
219}
220
221/**
222 * Mix in `Emitter` with Decoder.
223 */
224
225Emitter(Decoder.prototype);
226
227/**
228 * Decodes an ecoded packet string into packet JSON.
229 *
230 * @param {String} obj - encoded packet
231 * @return {Object} packet
232 * @api public
233 */
234
235Decoder.prototype.add = function(obj) {
236  var packet;
237  if ('string' == typeof obj) {
238    packet = decodeString(obj);
239    if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json
240      this.reconstructor = new BinaryReconstructor(packet);
241
242      // no attachments, labeled binary but no binary data to follow
243      if (this.reconstructor.reconPack.attachments == 0) {
244        this.emit('decoded', packet);
245      }
246    } else { // non-binary full packet
247      this.emit('decoded', packet);
248    }
249  }
250  else if (isBuf(obj) || obj.base64) { // raw binary data
251    if (!this.reconstructor) {
252      throw new Error('got binary data when not reconstructing a packet');
253    } else {
254      packet = this.reconstructor.takeBinaryData(obj);
255      if (packet) { // received final buffer
256        this.reconstructor = null;
257        this.emit('decoded', packet);
258      }
259    }
260  }
261  else {
262    throw new Error('Unknown type: ' + obj);
263  }
264};
265
266/**
267 * Decode a packet String (JSON data)
268 *
269 * @param {String} str
270 * @return {Object} packet
271 * @api private
272 */
273
274function decodeString(str) {
275  var p = {};
276  var i = 0;
277
278  // look up type
279  p.type = Number(str.charAt(0));
280  if (null == exports.types[p.type]) return error();
281
282  // look up attachments if type binary
283  if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) {
284    p.attachments = '';
285    while (str.charAt(++i) != '-') {
286      p.attachments += str.charAt(i);
287    }
288    p.attachments = Number(p.attachments);
289  }
290
291  // look up namespace (if any)
292  if ('/' == str.charAt(i + 1)) {
293    p.nsp = '';
294    while (++i) {
295      var c = str.charAt(i);
296      if (',' == c) break;
297      p.nsp += c;
298      if (i + 1 == str.length) break;
299    }
300  } else {
301    p.nsp = '/';
302  }
303
304  // look up id
305  var next = str.charAt(i + 1);
306  if ('' != next && Number(next) == next) {
307    p.id = '';
308    while (++i) {
309      var c = str.charAt(i);
310      if (null == c || Number(c) != c) {
311        --i;
312        break;
313      }
314      p.id += str.charAt(i);
315      if (i + 1 == str.length) break;
316    }
317    p.id = Number(p.id);
318  }
319
320  // look up json data
321  if (str.charAt(++i)) {
322    try {
323      p.data = json.parse(str.substr(i));
324    } catch(e){
325      return error();
326    }
327  }
328
329  debug('decoded %s as %j', str, p);
330  return p;
331}
332
333/**
334 * Deallocates a parser's resources
335 *
336 * @api public
337 */
338
339Decoder.prototype.destroy = function() {
340  if (this.reconstructor) {
341    this.reconstructor.finishedReconstruction();
342  }
343};
344
345/**
346 * A manager of a binary event's 'buffer sequence'. Should
347 * be constructed whenever a packet of type BINARY_EVENT is
348 * decoded.
349 *
350 * @param {Object} packet
351 * @return {BinaryReconstructor} initialized reconstructor
352 * @api private
353 */
354
355function BinaryReconstructor(packet) {
356  this.reconPack = packet;
357  this.buffers = [];
358}
359
360/**
361 * Method to be called when binary data received from connection
362 * after a BINARY_EVENT packet.
363 *
364 * @param {Buffer | ArrayBuffer} binData - the raw binary data received
365 * @return {null | Object} returns null if more binary data is expected or
366 *   a reconstructed packet object if all buffers have been received.
367 * @api private
368 */
369
370BinaryReconstructor.prototype.takeBinaryData = function(binData) {
371  this.buffers.push(binData);
372  if (this.buffers.length == this.reconPack.attachments) { // done with buffer list
373    var packet = binary.reconstructPacket(this.reconPack, this.buffers);
374    this.finishedReconstruction();
375    return packet;
376  }
377  return null;
378};
379
380/**
381 * Cleans up binary packet reconstruction variables.
382 *
383 * @api private
384 */
385
386BinaryReconstructor.prototype.finishedReconstruction = function() {
387  this.reconPack = null;
388  this.buffers = [];
389};
390
391function error(data){
392  return {
393    type: exports.ERROR,
394    data: 'parser error'
395  };
396}