root / HServer / 00.Server / 00.Program / node_modules / socket.io-parser / index.js
이력 | 보기 | 이력해설 | 다운로드 (7.81 KB)
1 | 39 | HKM | |
---|---|---|---|
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 | } |