Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

socket.js 8.1KB

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