프로젝트

일반

사용자정보

통계
| 개정판:

root / HServer / 00.Server / 00.Program / node_modules / socket.io-parser / index.js

이력 | 보기 | 이력해설 | 다운로드 (7.81 KB)

1

    
2
/**
3
 * Module dependencies.
4
 */
5

    
6
var debug = require('debug')('socket.io-parser');
7
var Emitter = require('component-emitter');
8
var hasBin = require('has-binary2');
9
var binary = require('./binary');
10
var isArray = require('isarray');
11
var isBuf = require('./is-buffer');
12

    
13
/**
14
 * Protocol version.
15
 *
16
 * @api public
17
 */
18

    
19
exports.protocol = 4;
20

    
21
/**
22
 * Packet types.
23
 *
24
 * @api public
25
 */
26

    
27
exports.types = [
28
  'CONNECT',
29
  'DISCONNECT',
30
  'EVENT',
31
  'ACK',
32
  'ERROR',
33
  'BINARY_EVENT',
34
  'BINARY_ACK'
35
];
36

    
37
/**
38
 * Packet type `connect`.
39
 *
40
 * @api public
41
 */
42

    
43
exports.CONNECT = 0;
44

    
45
/**
46
 * Packet type `disconnect`.
47
 *
48
 * @api public
49
 */
50

    
51
exports.DISCONNECT = 1;
52

    
53
/**
54
 * Packet type `event`.
55
 *
56
 * @api public
57
 */
58

    
59
exports.EVENT = 2;
60

    
61
/**
62
 * Packet type `ack`.
63
 *
64
 * @api public
65
 */
66

    
67
exports.ACK = 3;
68

    
69
/**
70
 * Packet type `error`.
71
 *
72
 * @api public
73
 */
74

    
75
exports.ERROR = 4;
76

    
77
/**
78
 * Packet type 'binary event'
79
 *
80
 * @api public
81
 */
82

    
83
exports.BINARY_EVENT = 5;
84

    
85
/**
86
 * Packet type `binary ack`. For acks with binary arguments.
87
 *
88
 * @api public
89
 */
90

    
91
exports.BINARY_ACK = 6;
92

    
93
/**
94
 * Encoder constructor.
95
 *
96
 * @api public
97
 */
98

    
99
exports.Encoder = Encoder;
100

    
101
/**
102
 * Decoder constructor.
103
 *
104
 * @api public
105
 */
106

    
107
exports.Decoder = Decoder;
108

    
109
/**
110
 * A socket.io Encoder instance
111
 *
112
 * @api public
113
 */
114

    
115
function 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

    
127
Encoder.prototype.encode = function(obj, callback){
128
  if ((obj.type === exports.EVENT || obj.type === exports.ACK) && hasBin(obj.data)) {
129
    obj.type = obj.type === exports.EVENT ? exports.BINARY_EVENT : exports.BINARY_ACK;
130
  }
131

    
132
  debug('encoding packet %j', obj);
133

    
134
  if (exports.BINARY_EVENT === obj.type || exports.BINARY_ACK === obj.type) {
135
    encodeAsBinary(obj, callback);
136
  }
137
  else {
138
    var encoding = encodeAsString(obj);
139
    callback([encoding]);
140
  }
141
};
142

    
143
/**
144
 * Encode packet as string.
145
 *
146
 * @param {Object} packet
147
 * @return {String} encoded
148
 * @api private
149
 */
150

    
151
function encodeAsString(obj) {
152

    
153
  // first is type
154
  var str = '' + obj.type;
155

    
156
  // attachments if we have them
157
  if (exports.BINARY_EVENT === obj.type || exports.BINARY_ACK === obj.type) {
158
    str += obj.attachments + '-';
159
  }
160

    
161
  // if we have a namespace other than `/`
162
  // we append it followed by a comma `,`
163
  if (obj.nsp && '/' !== obj.nsp) {
164
    str += obj.nsp + ',';
165
  }
166

    
167
  // immediately followed by the id
168
  if (null != obj.id) {
169
    str += obj.id;
170
  }
171

    
172
  // json data
173
  if (null != obj.data) {
174
    str += JSON.stringify(obj.data);
175
  }
176

    
177
  debug('encoded %j as %s', obj, str);
178
  return str;
179
}
180

    
181
/**
182
 * Encode packet as 'buffer sequence' by removing blobs, and
183
 * deconstructing packet into object with placeholders and
184
 * a list of buffers.
185
 *
186
 * @param {Object} packet
187
 * @return {Buffer} encoded
188
 * @api private
189
 */
190

    
191
function encodeAsBinary(obj, callback) {
192

    
193
  function writeEncoding(bloblessData) {
194
    var deconstruction = binary.deconstructPacket(bloblessData);
195
    var pack = encodeAsString(deconstruction.packet);
196
    var buffers = deconstruction.buffers;
197

    
198
    buffers.unshift(pack); // add packet info to beginning of data list
199
    callback(buffers); // write all the buffers
200
  }
201

    
202
  binary.removeBlobs(obj, writeEncoding);
203
}
204

    
205
/**
206
 * A socket.io Decoder instance
207
 *
208
 * @return {Object} decoder
209
 * @api public
210
 */
211

    
212
function Decoder() {
213
  this.reconstructor = null;
214
}
215

    
216
/**
217
 * Mix in `Emitter` with Decoder.
218
 */
219

    
220
Emitter(Decoder.prototype);
221

    
222
/**
223
 * Decodes an ecoded packet string into packet JSON.
224
 *
225
 * @param {String} obj - encoded packet
226
 * @return {Object} packet
227
 * @api public
228
 */
229

    
230
Decoder.prototype.add = function(obj) {
231
  var packet;
232
  if (typeof obj === 'string') {
233
    packet = decodeString(obj);
234
    if (exports.BINARY_EVENT === packet.type || exports.BINARY_ACK === packet.type) { // binary packet's json
235
      this.reconstructor = new BinaryReconstructor(packet);
236

    
237
      // no attachments, labeled binary but no binary data to follow
238
      if (this.reconstructor.reconPack.attachments === 0) {
239
        this.emit('decoded', packet);
240
      }
241
    } else { // non-binary full packet
242
      this.emit('decoded', packet);
243
    }
244
  }
245
  else if (isBuf(obj) || obj.base64) { // raw binary data
246
    if (!this.reconstructor) {
247
      throw new Error('got binary data when not reconstructing a packet');
248
    } else {
249
      packet = this.reconstructor.takeBinaryData(obj);
250
      if (packet) { // received final buffer
251
        this.reconstructor = null;
252
        this.emit('decoded', packet);
253
      }
254
    }
255
  }
256
  else {
257
    throw new Error('Unknown type: ' + obj);
258
  }
259
};
260

    
261
/**
262
 * Decode a packet String (JSON data)
263
 *
264
 * @param {String} str
265
 * @return {Object} packet
266
 * @api private
267
 */
268

    
269
function decodeString(str) {
270
  var i = 0;
271
  // look up type
272
  var p = {
273
    type: Number(str.charAt(0))
274
  };
275

    
276
  if (null == exports.types[p.type]) {
277
    return error('unknown packet type ' + p.type);
278
  }
279

    
280
  // look up attachments if type binary
281
  if (exports.BINARY_EVENT === p.type || exports.BINARY_ACK === p.type) {
282
    var buf = '';
283
    while (str.charAt(++i) !== '-') {
284
      buf += str.charAt(i);
285
      if (i == str.length) break;
286
    }
287
    if (buf != Number(buf) || str.charAt(i) !== '-') {
288
      throw new Error('Illegal attachments');
289
    }
290
    p.attachments = Number(buf);
291
  }
292

    
293
  // look up namespace (if any)
294
  if ('/' === str.charAt(i + 1)) {
295
    p.nsp = '';
296
    while (++i) {
297
      var c = str.charAt(i);
298
      if (',' === c) break;
299
      p.nsp += c;
300
      if (i === str.length) break;
301
    }
302
  } else {
303
    p.nsp = '/';
304
  }
305

    
306
  // look up id
307
  var next = str.charAt(i + 1);
308
  if ('' !== next && Number(next) == next) {
309
    p.id = '';
310
    while (++i) {
311
      var c = str.charAt(i);
312
      if (null == c || Number(c) != c) {
313
        --i;
314
        break;
315
      }
316
      p.id += str.charAt(i);
317
      if (i === str.length) break;
318
    }
319
    p.id = Number(p.id);
320
  }
321

    
322
  // look up json data
323
  if (str.charAt(++i)) {
324
    var payload = tryParse(str.substr(i));
325
    var isPayloadValid = payload !== false && (p.type === exports.ERROR || isArray(payload));
326
    if (isPayloadValid) {
327
      p.data = payload;
328
    } else {
329
      return error('invalid payload');
330
    }
331
  }
332

    
333
  debug('decoded %s as %j', str, p);
334
  return p;
335
}
336

    
337
function tryParse(str) {
338
  try {
339
    return JSON.parse(str);
340
  } catch(e){
341
    return false;
342
  }
343
}
344

    
345
/**
346
 * Deallocates a parser's resources
347
 *
348
 * @api public
349
 */
350

    
351
Decoder.prototype.destroy = function() {
352
  if (this.reconstructor) {
353
    this.reconstructor.finishedReconstruction();
354
  }
355
};
356

    
357
/**
358
 * A manager of a binary event's 'buffer sequence'. Should
359
 * be constructed whenever a packet of type BINARY_EVENT is
360
 * decoded.
361
 *
362
 * @param {Object} packet
363
 * @return {BinaryReconstructor} initialized reconstructor
364
 * @api private
365
 */
366

    
367
function BinaryReconstructor(packet) {
368
  this.reconPack = packet;
369
  this.buffers = [];
370
}
371

    
372
/**
373
 * Method to be called when binary data received from connection
374
 * after a BINARY_EVENT packet.
375
 *
376
 * @param {Buffer | ArrayBuffer} binData - the raw binary data received
377
 * @return {null | Object} returns null if more binary data is expected or
378
 *   a reconstructed packet object if all buffers have been received.
379
 * @api private
380
 */
381

    
382
BinaryReconstructor.prototype.takeBinaryData = function(binData) {
383
  this.buffers.push(binData);
384
  if (this.buffers.length === this.reconPack.attachments) { // done with buffer list
385
    var packet = binary.reconstructPacket(this.reconPack, this.buffers);
386
    this.finishedReconstruction();
387
    return packet;
388
  }
389
  return null;
390
};
391

    
392
/**
393
 * Cleans up binary packet reconstruction variables.
394
 *
395
 * @api private
396
 */
397

    
398
BinaryReconstructor.prototype.finishedReconstruction = function() {
399
  this.reconPack = null;
400
  this.buffers = [];
401
};
402

    
403
function error(msg) {
404
  return {
405
    type: exports.ERROR,
406
    data: 'parser error: ' + msg
407
  };
408
}