[Service] Integrate DeviceHome and SignalingServer
[platform/framework/web/wrtjs.git] / device_home / node_modules / socket.io / node_modules / socket.io-client / lib / socket.js
1
2 /**
3  * Module dependencies.
4  */
5
6 var parser = require('socket.io-parser');
7 var Emitter = require('component-emitter');
8 var toArray = require('to-array');
9 var on = require('./on');
10 var bind = require('component-bind');
11 var debug = require('debug')('socket.io-client:socket');
12 var parseqs = require('parseqs');
13 var hasBin = require('has-binary2');
14
15 /**
16  * Module exports.
17  */
18
19 module.exports = exports = Socket;
20
21 /**
22  * Internal events (blacklisted).
23  * These events can't be emitted by the user.
24  *
25  * @api private
26  */
27
28 var events = {
29   connect: 1,
30   connect_error: 1,
31   connect_timeout: 1,
32   connecting: 1,
33   disconnect: 1,
34   error: 1,
35   reconnect: 1,
36   reconnect_attempt: 1,
37   reconnect_failed: 1,
38   reconnect_error: 1,
39   reconnecting: 1,
40   ping: 1,
41   pong: 1
42 };
43
44 /**
45  * Shortcut to `Emitter#emit`.
46  */
47
48 var emit = Emitter.prototype.emit;
49
50 /**
51  * `Socket` constructor.
52  *
53  * @api public
54  */
55
56 function Socket (io, nsp, opts) {
57   this.io = io;
58   this.nsp = nsp;
59   this.json = this; // compat
60   this.ids = 0;
61   this.acks = {};
62   this.receiveBuffer = [];
63   this.sendBuffer = [];
64   this.connected = false;
65   this.disconnected = true;
66   this.flags = {};
67   if (opts && opts.query) {
68     this.query = opts.query;
69   }
70   if (this.io.autoConnect) this.open();
71 }
72
73 /**
74  * Mix in `Emitter`.
75  */
76
77 Emitter(Socket.prototype);
78
79 /**
80  * Subscribe to open, close and packet events
81  *
82  * @api private
83  */
84
85 Socket.prototype.subEvents = function () {
86   if (this.subs) return;
87
88   var io = this.io;
89   this.subs = [
90     on(io, 'open', bind(this, 'onopen')),
91     on(io, 'packet', bind(this, 'onpacket')),
92     on(io, 'close', bind(this, 'onclose'))
93   ];
94 };
95
96 /**
97  * "Opens" the socket.
98  *
99  * @api public
100  */
101
102 Socket.prototype.open =
103 Socket.prototype.connect = function () {
104   if (this.connected) return this;
105
106   this.subEvents();
107   if (!this.io.reconnecting) this.io.open(); // ensure open
108   if ('open' === this.io.readyState) this.onopen();
109   this.emit('connecting');
110   return this;
111 };
112
113 /**
114  * Sends a `message` event.
115  *
116  * @return {Socket} self
117  * @api public
118  */
119
120 Socket.prototype.send = function () {
121   var args = toArray(arguments);
122   args.unshift('message');
123   this.emit.apply(this, args);
124   return this;
125 };
126
127 /**
128  * Override `emit`.
129  * If the event is in `events`, it's emitted normally.
130  *
131  * @param {String} event name
132  * @return {Socket} self
133  * @api public
134  */
135
136 Socket.prototype.emit = function (ev) {
137   if (events.hasOwnProperty(ev)) {
138     emit.apply(this, arguments);
139     return this;
140   }
141
142   var args = toArray(arguments);
143   var packet = {
144     type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT,
145     data: args
146   };
147
148   packet.options = {};
149   packet.options.compress = !this.flags || false !== this.flags.compress;
150
151   // event ack callback
152   if ('function' === typeof args[args.length - 1]) {
153     debug('emitting packet with ack id %d', this.ids);
154     this.acks[this.ids] = args.pop();
155     packet.id = this.ids++;
156   }
157
158   if (this.connected) {
159     this.packet(packet);
160   } else {
161     this.sendBuffer.push(packet);
162   }
163
164   this.flags = {};
165
166   return this;
167 };
168
169 /**
170  * Sends a packet.
171  *
172  * @param {Object} packet
173  * @api private
174  */
175
176 Socket.prototype.packet = function (packet) {
177   packet.nsp = this.nsp;
178   this.io.packet(packet);
179 };
180
181 /**
182  * Called upon engine `open`.
183  *
184  * @api private
185  */
186
187 Socket.prototype.onopen = function () {
188   debug('transport is open - connecting');
189
190   // write connect packet if necessary
191   if ('/' !== this.nsp) {
192     if (this.query) {
193       var query = typeof this.query === 'object' ? parseqs.encode(this.query) : this.query;
194       debug('sending connect packet with query %s', query);
195       this.packet({type: parser.CONNECT, query: query});
196     } else {
197       this.packet({type: parser.CONNECT});
198     }
199   }
200 };
201
202 /**
203  * Called upon engine `close`.
204  *
205  * @param {String} reason
206  * @api private
207  */
208
209 Socket.prototype.onclose = function (reason) {
210   debug('close (%s)', reason);
211   this.connected = false;
212   this.disconnected = true;
213   delete this.id;
214   this.emit('disconnect', reason);
215 };
216
217 /**
218  * Called with socket packet.
219  *
220  * @param {Object} packet
221  * @api private
222  */
223
224 Socket.prototype.onpacket = function (packet) {
225   var sameNamespace = packet.nsp === this.nsp;
226   var rootNamespaceError = packet.type === parser.ERROR && packet.nsp === '/';
227
228   if (!sameNamespace && !rootNamespaceError) return;
229
230   switch (packet.type) {
231     case parser.CONNECT:
232       this.onconnect();
233       break;
234
235     case parser.EVENT:
236       this.onevent(packet);
237       break;
238
239     case parser.BINARY_EVENT:
240       this.onevent(packet);
241       break;
242
243     case parser.ACK:
244       this.onack(packet);
245       break;
246
247     case parser.BINARY_ACK:
248       this.onack(packet);
249       break;
250
251     case parser.DISCONNECT:
252       this.ondisconnect();
253       break;
254
255     case parser.ERROR:
256       this.emit('error', packet.data);
257       break;
258   }
259 };
260
261 /**
262  * Called upon a server event.
263  *
264  * @param {Object} packet
265  * @api private
266  */
267
268 Socket.prototype.onevent = function (packet) {
269   var args = packet.data || [];
270   debug('emitting event %j', args);
271
272   if (null != packet.id) {
273     debug('attaching ack callback to event');
274     args.push(this.ack(packet.id));
275   }
276
277   if (this.connected) {
278     emit.apply(this, args);
279   } else {
280     this.receiveBuffer.push(args);
281   }
282 };
283
284 /**
285  * Produces an ack callback to emit with an event.
286  *
287  * @api private
288  */
289
290 Socket.prototype.ack = function (id) {
291   var self = this;
292   var sent = false;
293   return function () {
294     // prevent double callbacks
295     if (sent) return;
296     sent = true;
297     var args = toArray(arguments);
298     debug('sending ack %j', args);
299
300     self.packet({
301       type: hasBin(args) ? parser.BINARY_ACK : parser.ACK,
302       id: id,
303       data: args
304     });
305   };
306 };
307
308 /**
309  * Called upon a server acknowlegement.
310  *
311  * @param {Object} packet
312  * @api private
313  */
314
315 Socket.prototype.onack = function (packet) {
316   var ack = this.acks[packet.id];
317   if ('function' === typeof ack) {
318     debug('calling ack %s with %j', packet.id, packet.data);
319     ack.apply(this, packet.data);
320     delete this.acks[packet.id];
321   } else {
322     debug('bad ack %s', packet.id);
323   }
324 };
325
326 /**
327  * Called upon server connect.
328  *
329  * @api private
330  */
331
332 Socket.prototype.onconnect = function () {
333   this.connected = true;
334   this.disconnected = false;
335   this.emit('connect');
336   this.emitBuffered();
337 };
338
339 /**
340  * Emit buffered events (received and emitted).
341  *
342  * @api private
343  */
344
345 Socket.prototype.emitBuffered = function () {
346   var i;
347   for (i = 0; i < this.receiveBuffer.length; i++) {
348     emit.apply(this, this.receiveBuffer[i]);
349   }
350   this.receiveBuffer = [];
351
352   for (i = 0; i < this.sendBuffer.length; i++) {
353     this.packet(this.sendBuffer[i]);
354   }
355   this.sendBuffer = [];
356 };
357
358 /**
359  * Called upon server disconnect.
360  *
361  * @api private
362  */
363
364 Socket.prototype.ondisconnect = function () {
365   debug('server disconnect (%s)', this.nsp);
366   this.destroy();
367   this.onclose('io server disconnect');
368 };
369
370 /**
371  * Called upon forced client/server side disconnections,
372  * this method ensures the manager stops tracking us and
373  * that reconnections don't get triggered for this.
374  *
375  * @api private.
376  */
377
378 Socket.prototype.destroy = function () {
379   if (this.subs) {
380     // clean subscriptions to avoid reconnections
381     for (var i = 0; i < this.subs.length; i++) {
382       this.subs[i].destroy();
383     }
384     this.subs = null;
385   }
386
387   this.io.destroy(this);
388 };
389
390 /**
391  * Disconnects the socket manually.
392  *
393  * @return {Socket} self
394  * @api public
395  */
396
397 Socket.prototype.close =
398 Socket.prototype.disconnect = function () {
399   if (this.connected) {
400     debug('performing disconnect (%s)', this.nsp);
401     this.packet({ type: parser.DISCONNECT });
402   }
403
404   // remove socket from pool
405   this.destroy();
406
407   if (this.connected) {
408     // fire events
409     this.onclose('io client disconnect');
410   }
411   return this;
412 };
413
414 /**
415  * Sets the compress flag.
416  *
417  * @param {Boolean} if `true`, compresses the sending data
418  * @return {Socket} self
419  * @api public
420  */
421
422 Socket.prototype.compress = function (compress) {
423   this.flags.compress = compress;
424   return this;
425 };
426
427 /**
428  * Sets the binary flag
429  *
430  * @param {Boolean} whether the emitted data contains binary
431  * @return {Socket} self
432  * @api public
433  */
434
435 Socket.prototype.binary = function (binary) {
436   this.flags.binary = binary;
437   return this;
438 };