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}